diff --git a/.github/workflows/triage-incoming.yml b/.github/workflows/triage-incoming.yml index 4dadc25ab4..56bad8a2d7 100644 --- a/.github/workflows/triage-incoming.yml +++ b/.github/workflows/triage-incoming.yml @@ -10,7 +10,7 @@ jobs: # Skip in forks if: github.repository == 'vector-im/element-android' steps: - - uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d + - uses: alex-page/github-project-automation-plus@7ffb872c64bd809d23563a130a0a97d01dfa8f43 with: project: Issue triage column: Incoming diff --git a/.github/workflows/triage-priority-bugs.yml b/.github/workflows/triage-priority-bugs.yml index 07e73fe805..c109b06b7e 100644 --- a/.github/workflows/triage-priority-bugs.yml +++ b/.github/workflows/triage-priority-bugs.yml @@ -24,7 +24,7 @@ jobs: contains(github.event.issue.labels.*.name, 'A11y') && contains(github.event.issue.labels.*.name, 'O-Frequent')) steps: - - uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d + - uses: alex-page/github-project-automation-plus@7ffb872c64bd809d23563a130a0a97d01dfa8f43 with: project: Android App Team column: Important Issues & Topics (P1) @@ -50,7 +50,7 @@ jobs: contains(github.event.issue.labels.*.name, 'A11y') && contains(github.event.issue.labels.*.name, 'O-Frequent'))) steps: - - uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d + - uses: alex-page/github-project-automation-plus@7ffb872c64bd809d23563a130a0a97d01dfa8f43 with: project: Crypto Team column: Ready diff --git a/.github/workflows/triage-unlabelled.yml b/.github/workflows/triage-unlabelled.yml index 98d6579958..e29a79e2e7 100644 --- a/.github/workflows/triage-unlabelled.yml +++ b/.github/workflows/triage-unlabelled.yml @@ -28,7 +28,7 @@ jobs: echo "ALREADY_IN_BOARD=false" >> $GITHUB_ENV fi - name: Move issue - uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d + uses: alex-page/github-project-automation-plus@7ffb872c64bd809d23563a130a0a97d01dfa8f43 if: ${{ env.ALREADY_IN_BOARD == 'true' }} with: project: Issue triage diff --git a/build.gradle b/build.gradle index 0796ddaf97..9ea996e70b 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ buildscript { plugins { // ktlint Plugin - id "org.jlleitschuh.gradle.ktlint" version "11.0.0" + id "org.jlleitschuh.gradle.ktlint" version "11.1.0" // Detekt id "io.gitlab.arturbosch.detekt" version "1.22.0" // Ksp diff --git a/changelog.d/7975.bugfix b/changelog.d/7975.bugfix new file mode 100644 index 0000000000..b34c784b27 --- /dev/null +++ b/changelog.d/7975.bugfix @@ -0,0 +1 @@ +Fix extra new lines added to inline code diff --git a/changelog.d/8011.feature b/changelog.d/8011.feature new file mode 100644 index 0000000000..700a528fc1 --- /dev/null +++ b/changelog.d/8011.feature @@ -0,0 +1 @@ +[Rich text editor] Add inline code to rich text editor \ No newline at end of file diff --git a/changelog.d/8012.bugfix b/changelog.d/8012.bugfix new file mode 100644 index 0000000000..bd2ee3dd08 --- /dev/null +++ b/changelog.d/8012.bugfix @@ -0,0 +1 @@ +[Voice Broadcast] Use internal playback timer to compute the current playback position diff --git a/changelog.d/8031.bugfix b/changelog.d/8031.bugfix new file mode 100644 index 0000000000..0e7ff28509 --- /dev/null +++ b/changelog.d/8031.bugfix @@ -0,0 +1 @@ +Do not send any request to Posthog if no consent is provided. diff --git a/changelog.d/8042.misc b/changelog.d/8042.misc new file mode 100644 index 0000000000..dbfe98140c --- /dev/null +++ b/changelog.d/8042.misc @@ -0,0 +1 @@ +[Voice Broadcast] Show Live broadcast in the room list only if the feature flag is enabled in the lab diff --git a/changelog.d/8062.bugfix b/changelog.d/8062.bugfix new file mode 100644 index 0000000000..af1a370350 --- /dev/null +++ b/changelog.d/8062.bugfix @@ -0,0 +1,2 @@ + [Voice Broadcast] We should not be able to start broadcasting if there is already a live broadcast in the Room + \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index bab9229b3b..413199363a 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -6,7 +6,7 @@ ext.versions = [ 'targetCompat' : JavaVersion.VERSION_11, ] -def gradle = "7.3.1" +def gradle = "7.4.1" // Ref: https://kotlinlang.org/releases.html def kotlin = "1.8.0" def kotlinCoroutines = "1.6.4" diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40105220.txt b/fastlane/metadata/android/cs-CZ/changelogs/40105220.txt new file mode 100644 index 0000000000..afbcb7ef34 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: Především vylepšení funkce hlasového vysílání. +Úplný seznam změn: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/de-DE/changelogs/40105220.txt b/fastlane/metadata/android/de-DE/changelogs/40105220.txt new file mode 100644 index 0000000000..0f8b294746 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Die wichtigsten Änderungen in dieser Version: Hauptsächlich Verbesserungen für Sprachübertragungen. +Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/et/changelogs/40105220.txt b/fastlane/metadata/android/et/changelogs/40105220.txt new file mode 100644 index 0000000000..c085958fd8 --- /dev/null +++ b/fastlane/metadata/android/et/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Põhilised muutused selles versioonis: täiendused ringhäälingukõnede lahendusele. +Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fa/changelogs/40105220.txt b/fastlane/metadata/android/fa/changelogs/40105220.txt new file mode 100644 index 0000000000..be91236ca0 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/40105220.txt @@ -0,0 +1,2 @@ +تغییرات عمده در این نگارش: بیش‌تر بهبود در ویژگی پخش صوتی. +گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fr-FR/changelogs/40105220.txt b/fastlane/metadata/android/fr-FR/changelogs/40105220.txt new file mode 100644 index 0000000000..2c871c4b17 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : Principalement des améliorations sur la fonction de diffusion audio. +Intégralité des changements : https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hu-HU/changelogs/40105220.txt b/fastlane/metadata/android/hu-HU/changelogs/40105220.txt new file mode 100644 index 0000000000..8d6ab49da1 --- /dev/null +++ b/fastlane/metadata/android/hu-HU/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Legnagyobb változtatás ebben a verzióban: Fejlesztések a hang közvetítésben. +Teljes változási napló: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/id/changelogs/40105220.txt b/fastlane/metadata/android/id/changelogs/40105220.txt new file mode 100644 index 0000000000..849ffbee9a --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Perubahan utama dalam versi ini: Banyak perbaikan terutama pada fitur siaran suara. +Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/it-IT/changelogs/40105220.txt b/fastlane/metadata/android/it-IT/changelogs/40105220.txt new file mode 100644 index 0000000000..f4343ee074 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Modifiche principali in questa versione: miglioramenti nella funzionalità di trasmissione vocale. +Cronologia completa: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40100100.txt b/fastlane/metadata/android/ja-JP/changelogs/40100100.txt index 0f9fc720a9..2034b963a9 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40100100.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40100100.txt @@ -1,2 +1,2 @@ -今回の新バージョンでは、主にバグの修正と改善が行われています。メッセージの送信がより速くなりました。 +今回の新バージョンでは、主に不具合の修正と改善が行われています。メッセージの送信がより速くなりました。 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.0.10 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40100140.txt b/fastlane/metadata/android/ja-JP/changelogs/40100140.txt index 8fa9848d0b..8c7bdcfd73 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40100140.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40100140.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:部屋の許可、自動のテーマ切替、そして多くのバグを修正しました。 +このバージョンの主な変更点:部屋の許可、自動のテーマ切替、そして多くの不具合を修正しました。 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.0.14 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40100160.txt b/fastlane/metadata/android/ja-JP/changelogs/40100160.txt index ae947f1781..1eb18685f8 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40100160.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40100160.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:パフォーマンスの向上と、バグを修正しました! +このバージョンの主な変更点:ソーシャルログインのサポート。 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40100170.txt b/fastlane/metadata/android/ja-JP/changelogs/40100170.txt index 01b742a9a2..6d19fcaa2d 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40100170.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40100170.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:バグを修正しました! +このバージョンの主な変更点:不具合を修正しました! 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.0.17 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101000.txt b/fastlane/metadata/android/ja-JP/changelogs/40101000.txt index 0c09cee3dd..a91371f9f7 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40101000.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40101000.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:パフォーマンスの向上と、バグを修正しました! +このバージョンの主な変更点:VoIP(ダイレクトメッセージでの音声・ビデオ通話)の改善と、不具合を修正しました! 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.0 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101010.txt b/fastlane/metadata/android/ja-JP/changelogs/40101010.txt index 25ac73b449..c5b26dd26f 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40101010.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40101010.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:パフォーマンスの向上と、バグを修正しました! +このバージョンの主な変更点:パフォーマンスの向上と、不具合を修正しました! 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.1 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101020.txt b/fastlane/metadata/android/ja-JP/changelogs/40101020.txt index 762879a281..763dcd18c8 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40101020.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40101020.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:パフォーマンスの向上と、バグを修正しました! +このバージョンの主な変更点:パフォーマンスの向上と、不具合を修正しました! 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.2 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101030.txt b/fastlane/metadata/android/ja-JP/changelogs/40101030.txt index 3c641c09ac..5b65e8247c 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40101030.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40101030.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:パフォーマンスの向上と、バグを修正しました! +このバージョンの主な変更点:パフォーマンスの向上と、不具合を修正しました! 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.3 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101050.txt b/fastlane/metadata/android/ja-JP/changelogs/40101050.txt new file mode 100644 index 0000000000..3b30ef25a1 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101050.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:1.1.4のホットフィックス +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.5 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101060.txt b/fastlane/metadata/android/ja-JP/changelogs/40101060.txt new file mode 100644 index 0000000000..0c3e5663c4 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101060.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:1.1.5のホットフィックス +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.6 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101070.txt b/fastlane/metadata/android/ja-JP/changelogs/40101070.txt new file mode 100644 index 0000000000..8551b3fb30 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101070.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スペースのベータ版。送信前に動画を圧縮。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.7 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101080.txt b/fastlane/metadata/android/ja-JP/changelogs/40101080.txt new file mode 100644 index 0000000000..9ef3a834e6 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101080.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スペースの改善。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.8 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101090.txt b/fastlane/metadata/android/ja-JP/changelogs/40101090.txt new file mode 100644 index 0000000000..615681a617 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101090.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:gitter.imに対応。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.9 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101110.txt b/fastlane/metadata/android/ja-JP/changelogs/40101110.txt new file mode 100644 index 0000000000..ee107872e2 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101110.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:テーマとスタイルの更新、スペースの新しい機能(1.1.10の不具合の修正) +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.11 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101120.txt b/fastlane/metadata/android/ja-JP/changelogs/40101120.txt new file mode 100644 index 0000000000..1b6c3cdeb2 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101120.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:テーマとスタイルの更新、ビデオ通話の後のクラッシュを修正 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.12 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101130.txt b/fastlane/metadata/android/ja-JP/changelogs/40101130.txt new file mode 100644 index 0000000000..3dce47fd25 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101130.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:安定性の改善と不具合の修正。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.13 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101140.txt b/fastlane/metadata/android/ja-JP/changelogs/40101140.txt new file mode 100644 index 0000000000..79d2a9aacb --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101140.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:暗号化したメッセージに関する不具合の修正。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.14 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40101150.txt b/fastlane/metadata/android/ja-JP/changelogs/40101150.txt new file mode 100644 index 0000000000..2509a1a714 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40101150.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:ラボの設定に音声メッセージの実装を追加。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.1.15 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40102000.txt b/fastlane/metadata/android/ja-JP/changelogs/40102000.txt new file mode 100644 index 0000000000..76ccb8d0b5 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40102000.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:音声メッセージを既定で有効化。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.2.0 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40102010.txt b/fastlane/metadata/android/ja-JP/changelogs/40102010.txt new file mode 100644 index 0000000000..204ffdc52d --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40102010.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:VoIPとスペース(ベータ版)に関する改善。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.2.1 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40103000.txt b/fastlane/metadata/android/ja-JP/changelogs/40103000.txt new file mode 100644 index 0000000000..7243945833 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40103000.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スペース機能の実装 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.3.0 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40103010.txt b/fastlane/metadata/android/ja-JP/changelogs/40103010.txt new file mode 100644 index 0000000000..76fd62ee41 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40103010.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スペース機能。1.3.0のクラッシュの修正。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.3.1 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40103020.txt b/fastlane/metadata/android/ja-JP/changelogs/40103020.txt new file mode 100644 index 0000000000..5c05c18486 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40103020.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:Android Autoのサポート。不具合の修正。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.3.2 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40103030.txt b/fastlane/metadata/android/ja-JP/changelogs/40103030.txt new file mode 100644 index 0000000000..091cdfbe5c --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40103030.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:IDサーバーの方針を設定画面に表示。Android Autoのサポートを一時的に削除。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.3.3 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40103040.txt b/fastlane/metadata/android/ja-JP/changelogs/40103040.txt new file mode 100644 index 0000000000..d640cdfe58 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40103040.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:ダイレクトメッセージのルームでプレゼンス(ステータス表示)のサポートを追加(注意:プレゼンスは matrix.org では無効です)。Android Autoのサポートを再追加。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.3.4 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40103050.txt b/fastlane/metadata/android/ja-JP/changelogs/40103050.txt new file mode 100644 index 0000000000..735e2ee200 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40103050.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:ダイレクトメッセージのルームでプレゼンス(ステータス表示)のサポートを追加(注意:プレゼンスは matrix.org では無効です)。Android Autoのサポートを再追加。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.3.5 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40103060.txt b/fastlane/metadata/android/ja-JP/changelogs/40103060.txt new file mode 100644 index 0000000000..4cf878d1f0 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40103060.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:ダイレクトメッセージのルームでプレゼンス(ステータス表示)のサポートを追加(注意:プレゼンスは matrix.org では無効です)。Android Autoのサポートを再追加。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.3.6 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104020.txt b/fastlane/metadata/android/ja-JP/changelogs/40104020.txt index e792008faf..49bc764ac9 100644 --- a/fastlane/metadata/android/ja-JP/changelogs/40104020.txt +++ b/fastlane/metadata/android/ja-JP/changelogs/40104020.txt @@ -1,2 +1,2 @@ -このバージョンの主な変更点:@roomの対応、非公開の投票など。 +このバージョンの主な変更点:@roomの対応、非公開のアンケートなど。 更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.4.2 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104040.txt b/fastlane/metadata/android/ja-JP/changelogs/40104040.txt new file mode 100644 index 0000000000..1c37d1c948 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104040.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:入力中のインジケーターのUIを更新。不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.4.4 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104060.txt b/fastlane/metadata/android/ja-JP/changelogs/40104060.txt new file mode 100644 index 0000000000..bb27f21a19 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104060.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スレッドのタイムラインの有効化と高速化。不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.4.6 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104070.txt b/fastlane/metadata/android/ja-JP/changelogs/40104070.txt new file mode 100644 index 0000000000..a2b55f615e --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104070.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases/tag/v1.4.7 diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104080.txt b/fastlane/metadata/android/ja-JP/changelogs/40104080.txt new file mode 100644 index 0000000000..f0377e0d91 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104080.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スレッドのタイムラインの有効化と高速化。不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104100.txt b/fastlane/metadata/android/ja-JP/changelogs/40104100.txt new file mode 100644 index 0000000000..6bd2ce71f9 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104100.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:音声メッセージでのスクロール。不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104110.txt b/fastlane/metadata/android/ja-JP/changelogs/40104110.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104110.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104120.txt b/fastlane/metadata/android/ja-JP/changelogs/40104120.txt new file mode 100644 index 0000000000..a830059d63 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104120.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:オンラインの状態を表示しない設定を追加。音声の添付ファイルのプレイヤーを追加 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104130.txt b/fastlane/metadata/android/ja-JP/changelogs/40104130.txt new file mode 100644 index 0000000000..a830059d63 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104130.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:オンラインの状態を表示しない設定を追加。音声の添付ファイルのプレイヤーを追加 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104140.txt b/fastlane/metadata/android/ja-JP/changelogs/40104140.txt new file mode 100644 index 0000000000..265c306a33 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104140.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:無視したユーザーの管理を改善。不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104160.txt b/fastlane/metadata/android/ja-JP/changelogs/40104160.txt new file mode 100644 index 0000000000..899acf0262 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104160.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:暗号化されたメッセージの管理を改善。不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104180.txt b/fastlane/metadata/android/ja-JP/changelogs/40104180.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104180.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104190.txt b/fastlane/metadata/android/ja-JP/changelogs/40104190.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104190.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104200.txt b/fastlane/metadata/android/ja-JP/changelogs/40104200.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104200.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104220.txt b/fastlane/metadata/android/ja-JP/changelogs/40104220.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104220.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104230.txt b/fastlane/metadata/android/ja-JP/changelogs/40104230.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104230.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104240.txt b/fastlane/metadata/android/ja-JP/changelogs/40104240.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104240.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104250.txt b/fastlane/metadata/android/ja-JP/changelogs/40104250.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104250.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104260.txt b/fastlane/metadata/android/ja-JP/changelogs/40104260.txt new file mode 100644 index 0000000000..2180774da8 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104260.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:UnifiedPushを採用し、FCMなしでプッシュ通知を送信する機能を追加。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104270.txt b/fastlane/metadata/android/ja-JP/changelogs/40104270.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104270.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104280.txt b/fastlane/metadata/android/ja-JP/changelogs/40104280.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104280.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104300.txt b/fastlane/metadata/android/ja-JP/changelogs/40104300.txt new file mode 100644 index 0000000000..82685764cc --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104300.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:サインインとサインアップのプロセスを改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104310.txt b/fastlane/metadata/android/ja-JP/changelogs/40104310.txt new file mode 100644 index 0000000000..82685764cc --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104310.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:サインインとサインアップのプロセスを改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104320.txt b/fastlane/metadata/android/ja-JP/changelogs/40104320.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104320.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104340.txt b/fastlane/metadata/android/ja-JP/changelogs/40104340.txt new file mode 100644 index 0000000000..6dfe0935ea --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104340.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と安定性の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40104360.txt b/fastlane/metadata/android/ja-JP/changelogs/40104360.txt new file mode 100644 index 0000000000..5a1d73c08a --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40104360.txt @@ -0,0 +1,3 @@ +新しいレイアウトをラボの設定で有効にできます。試してみてください! +通知に関する問題、同期に必要な時間に関する不具合を修正しました。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105000.txt b/fastlane/metadata/android/ja-JP/changelogs/40105000.txt new file mode 100644 index 0000000000..980ff9b873 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105000.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:遅延DMを既定で有効化。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105020.txt b/fastlane/metadata/android/ja-JP/changelogs/40105020.txt new file mode 100644 index 0000000000..47aba6a1d7 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105020.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:新しいレイアウトを既定で有効化! +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105040.txt b/fastlane/metadata/android/ja-JP/changelogs/40105040.txt new file mode 100644 index 0000000000..8269b4b35e --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105040.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:ラボの設定に新しい機能(リッチテキストエディター、端末の新しい管理画面、音声配信)を追加。開発中です! +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105060.txt b/fastlane/metadata/android/ja-JP/changelogs/40105060.txt new file mode 100644 index 0000000000..ddf18871f8 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105060.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:添付ファイルの選択画面の更新。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105070.txt b/fastlane/metadata/android/ja-JP/changelogs/40105070.txt new file mode 100644 index 0000000000..ddf18871f8 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105070.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:添付ファイルの選択画面の更新。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105080.txt b/fastlane/metadata/android/ja-JP/changelogs/40105080.txt new file mode 100644 index 0000000000..f1b740f1d7 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105080.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正と改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105100.txt b/fastlane/metadata/android/ja-JP/changelogs/40105100.txt new file mode 100644 index 0000000000..eb8c3f1077 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105100.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:リッチテキストエディターの全画面モードを新たに実装。不具合の修正。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105110.txt b/fastlane/metadata/android/ja-JP/changelogs/40105110.txt new file mode 100644 index 0000000000..eb8c3f1077 --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105110.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:リッチテキストエディターの全画面モードを新たに実装。不具合の修正。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105120.txt b/fastlane/metadata/android/ja-JP/changelogs/40105120.txt new file mode 100644 index 0000000000..a476e0961b --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105120.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スレッド機能を既定で有効化。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105130.txt b/fastlane/metadata/android/ja-JP/changelogs/40105130.txt new file mode 100644 index 0000000000..a476e0961b --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105130.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スレッド機能を既定で有効化。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105140.txt b/fastlane/metadata/android/ja-JP/changelogs/40105140.txt new file mode 100644 index 0000000000..a476e0961b --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105140.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スレッド機能を既定で有効化。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105160.txt b/fastlane/metadata/android/ja-JP/changelogs/40105160.txt new file mode 100644 index 0000000000..a476e0961b --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105160.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スレッド機能を既定で有効化。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105180.txt b/fastlane/metadata/android/ja-JP/changelogs/40105180.txt new file mode 100644 index 0000000000..a476e0961b --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105180.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:スレッド機能を既定で有効化。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105200.txt b/fastlane/metadata/android/ja-JP/changelogs/40105200.txt new file mode 100644 index 0000000000..9d001b89be --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105200.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:不具合の修正。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/changelogs/40105220.txt b/fastlane/metadata/android/ja-JP/changelogs/40105220.txt new file mode 100644 index 0000000000..da0627e6ac --- /dev/null +++ b/fastlane/metadata/android/ja-JP/changelogs/40105220.txt @@ -0,0 +1,2 @@ +このバージョンの主な変更点:音声配信機能の改善。 +更新履歴:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ja-JP/full_description.txt b/fastlane/metadata/android/ja-JP/full_description.txt index ce1550acb0..2d351ca47c 100644 --- a/fastlane/metadata/android/ja-JP/full_description.txt +++ b/fastlane/metadata/android/ja-JP/full_description.txt @@ -1,42 +1,42 @@ -Elementは、安全なメッセージングアプリ、リモートワーク中のグループチャットに適したチームコラボレーションアプリです。エンド・ツー・エンドの暗号化技術を使用して、強力なビデオ会議、ファイル共有、音声通話を提供します。 +Elementは、安全なメッセージングアプリ、リモートワーク中のグループチャットに適したチームコラボレーションアプリです。エンドツーエンドの暗号化を使用して、強力なビデオ会議、ファイル共有、音声通話を提供します。 Elementの特徴 - 高度なオンラインコミュニケーションツール - メッセージの完全な暗号化。リモートワーカーでも、より安全な企業コミュニケーションが可能 - Matrixオープンソースフレームワークに基づく、分散型のチャット -- プロジェクトの管理と並行して、データの暗号化によりファイルを安全に共有することが可能 +- プロジェクトを管理しながら、データの暗号化により安全にファイルを共有 - Voice over IPによるビデオチャットと画面共有 -- お気に入りのオンラインコラボレーションツールや、プロジェクト管理ツール、VoIPサービス、その他のチームメッセージングアプリと簡単に統合可能 +- お気に入りのオンラインコラボレーションツール、プロジェクト管理ツール、VoIPサービス、その他のチームメッセージングアプリと簡単に統合可能 -Elementは、他のメッセージングアプリやコラボレーションアプリとは全く異なります。安全なメッセージングと分散型(非中央集権型)コミュニケーションのためのオープンネットワークであるMatrixで動作します。自分のデータやメッセージを最大限にコントロールするために、あなた自身がサーバーを運営することもできます。 +Elementは、他のメッセージングアプリやコラボレーションアプリとは全く異なります。安全なメッセージングと分散型コミュニケーションのためのオープンネットワークであるMatrix上で動作します。また、ユーザーが自分のデータやメッセージを最大限にコントロールできるように、セルフホスティングに対応しています。 プライバシーと暗号化されたコミュニケーション -Elementは、望ましくない広告、データマイニング、囲い込みからユーザーを守ります。また、エンド・ツー・エンドの暗号化と、相互署名による端末の認証に基づき、全てのデータ、ビデオ会議、音声通信を保護します。 +Elementは、望ましくない広告、データマイニング、囲い込みからユーザーを保護します。また、エンドツーエンドの暗号化と相互署名による端末の認証により、全てのデータ、1対1のビデオおよび音声通信を保護します。 -Elementでは、Matrixネットワークにいる誰とでもコミュニケーションが行えるだけでなく、Slackなどのアプリと連携すれば、他のネットワークともコミュニケーションを行うとともに、プライバシーをコントロールすることができます。 +Elementでは、Matrixのネットワーク、またはSlackなどのアプリを統合して他のビジネスコラボレーションツールにいる誰とでもコミュニケーションを行いながら、プライバシーをコントロールすることができます。 -セルフホスティングが可能 -機密データや会話の管理を強化するために、Elementはセルフホスティングが可能です。または、オープンソースの分散型コミュニケーションの標準であるMatrixに基づくサーバーを選ぶこともできます。Elementは、プライバシー、セキュリティーコンプライアンス、および柔軟な機能統合を提供します。 +Elementはセルフホスティングが可能 +機密データや会話の管理を強化するために、Elementはセルフホスティングに対応しています。または、オープンソースの分散型コミュニケーションの標準であるMatrixに基づくサーバーを選択することもできます。Elementは、プライバシー、セキュリティーコンプライアンス、および機能統合の柔軟性を提供します。 自分のデータを所有する -データやメッセージを保管する場所を自分で決めることができます。データマイニングや第三者へのデータ流出のリスクはありません。 +データやメッセージを保管する場所をご自身で決めることができます。データマイニングや第三者へのデータ流出のリスクはありません。 Elementでは、どのサーバーを使うかをご自身で決めることができます。 -1. 開発者が運営する matrix.org の公開サーバーで無料アカウントを取得するか、ボランティアが管理している運営サーバーから選ぶ。 -2. あなた自身がサーバーを運営し、アカウントを管理する。 -3. Element Matrix Servicesの運営プラットフォームに加入し、カスタムサーバー上でアカウントを作る。 +1. 開発者が運営する matrix.org の公開サーバーで無料アカウントを取得するか、ボランティアが管理している運営サーバーから選択 +2. あなた自身でサーバーを運営し、アカウントを管理 +3. Element Matrix Servicesのホスティングプラットフォームに加入し、カスタムサーバー上でアカウントを作成 オープンなメッセージングとコラボレーション -相手がElement、他のMatrixアプリ、さらには他のメッセージングアプリを使っているかに関わらず、Matrixネットワーク上の誰とでもチャットをすることができます。 +相手がElement、他のMatrixアプリ、その他のメッセージングアプリを使っているかに関わらず、Matrixネットワーク上の誰とでもチャットをすることができます。 非常に安全 本物のエンド・ツー・エンドの暗号化(会話に参加している人だけがメッセージを復号化できます)と、クロス署名による端末の認証が可能です。 包括的なコミュニケーションと統合 -メッセージング、音声およびビデオ通話、ファイル共有、画面共有、その他多くの機能統合、ボット、ウィジェットを提供します。ルームやコミュニティーを立ち上げて連絡を取り合い、物事をスムーズに成し遂げましょう。 +メッセージング、音声およびビデオ通話、ファイル共有、画面共有、その他多くの機能統合、ボット、ウィジェットを提供します。ルームやコミュニティーを作って連絡を取り合い、物事をスムーズに成し遂げましょう。 いつでも、どこにいても -メッセージの履歴は、全ての端末とウェブ(https://app.element.io)で完全に同期されるので、どこからでも連絡を取り合うことができます。 +メッセージの履歴は、全ての端末とウェブ https://app.element.io で完全に同期されるので、どこからでも連絡を取り合うことができます。 オープンソース Element Androidは、GitHubで開発されているオープンソースのプロジェクトです。 不具合の報告や開発への貢献は https://github.com/vector-im/element-android にて受け付けています。 diff --git a/fastlane/metadata/android/sk/changelogs/40105220.txt b/fastlane/metadata/android/sk/changelogs/40105220.txt new file mode 100644 index 0000000000..95063822ef --- /dev/null +++ b/fastlane/metadata/android/sk/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Hlavné zmeny v tejto verzii: Vylepšenia funkcie hlasového vysielania. +Úplný zoznam zmien: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sq/changelogs/40105220.txt b/fastlane/metadata/android/sq/changelogs/40105220.txt new file mode 100644 index 0000000000..52f541dd4d --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Ndryshimet kryesore në këtë version: Kryesisht përmirësime për veçorinë e transmetimeve zanore. +Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sv-SE/changelogs/40105220.txt b/fastlane/metadata/android/sv-SE/changelogs/40105220.txt new file mode 100644 index 0000000000..c213f01a58 --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Huvudsakliga ändringar i den här versionen: Huvudsakligen förbättringar för röstsändningsfunktion. +Full ändringslogg: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/uk/changelogs/40105220.txt b/fastlane/metadata/android/uk/changelogs/40105220.txt new file mode 100644 index 0000000000..bd5669f116 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/40105220.txt @@ -0,0 +1,2 @@ +Основні зміни в цій версії: Головним чином поліпшено функцію голосової трансляції. +Журнал усіх змін: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/zh-TW/changelogs/40105220.txt b/fastlane/metadata/android/zh-TW/changelogs/40105220.txt new file mode 100644 index 0000000000..a47d30aeb3 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/40105220.txt @@ -0,0 +1,2 @@ +此版本中的主要變動:主要改善音訊廣播功能。 +完整的變更紀錄:https://github.com/vector-im/element-android/releases diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt index 07c7b4588f..30da59750e 100644 --- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt +++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt @@ -102,7 +102,7 @@ class VideoViewHolder constructor(itemView: View) : views.videoView.setOnPreparedListener { stopTimer() - countUpTimer = CountUpTimer(100).also { + countUpTimer = CountUpTimer(intervalInMs = 100).also { it.tickListener = CountUpTimer.TickListener { val duration = views.videoView.duration val progress = views.videoView.currentPosition diff --git a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/Clock.kt b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/Clock.kt new file mode 100644 index 0000000000..47e2c6532a --- /dev/null +++ b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/Clock.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.lib.core.utils.timer + +interface Clock { + fun epochMillis(): Long +} + +class DefaultClock : Clock { + + /** + * Provides a UTC epoch in milliseconds + * + * This value is not guaranteed to be correct with reality + * as a User can override the system time and date to any values. + */ + override fun epochMillis(): Long { + return System.currentTimeMillis() + } +} diff --git a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt index a4fd8bb4e1..c96b51a85d 100644 --- a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt +++ b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt @@ -28,41 +28,50 @@ import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicLong @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) -class CountUpTimer(private val intervalInMs: Long = 1_000) { +class CountUpTimer(initialTime: Long = 0L, private val intervalInMs: Long = 1_000) { private val coroutineScope = CoroutineScope(Dispatchers.Main) - private val elapsedTime: AtomicLong = AtomicLong() private val resumed: AtomicBoolean = AtomicBoolean(false) + private val clock: Clock = DefaultClock() + private val lastTime: AtomicLong = AtomicLong() + private val elapsedTime: AtomicLong = AtomicLong(initialTime) + init { startCounter() } private fun startCounter() { - tickerFlow(coroutineScope, intervalInMs / 10) + tickerFlow(coroutineScope, intervalInMs) .filter { resumed.get() } - .map { elapsedTime.addAndGet(intervalInMs / 10) } - .filter { it % intervalInMs == 0L } - .onEach { - tickListener?.onTick(it) - }.launchIn(coroutineScope) + .map { elapsedTime() } + .onEach { tickListener?.onTick(it) } + .launchIn(coroutineScope) } var tickListener: TickListener? = null fun elapsedTime(): Long { - return elapsedTime.get() + return if (resumed.get()) { + val now = clock.epochMillis() + elapsedTime.addAndGet(now - lastTime.getAndSet(now)) + } else { + elapsedTime.get() + } } fun pause() { + tickListener?.onTick(elapsedTime()) resumed.set(false) } fun resume() { + lastTime.set(clock.epochMillis()) resumed.set(true) } fun stop() { + tickListener?.onTick(elapsedTime()) coroutineScope.cancel() } diff --git a/library/ui-strings/src/main/res/values-cs/strings.xml b/library/ui-strings/src/main/res/values-cs/strings.xml index c122de7798..b1f7df9bb4 100644 --- a/library/ui-strings/src/main/res/values-cs/strings.xml +++ b/library/ui-strings/src/main/res/values-cs/strings.xml @@ -2979,4 +2979,5 @@ Hlasovou zprávu nelze spustit, protože právě nahráváte živé vysílání. Ukončete prosím živé vysílání, abyste mohli začít nahrávat hlasovou zprávu Nelze spustit hlasovou zprávu Chyba připojení - nahrávání pozastaveno + Použít formát inline kódu \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-de/strings.xml b/library/ui-strings/src/main/res/values-de/strings.xml index 17fa9b6e44..06c477b410 100644 --- a/library/ui-strings/src/main/res/values-de/strings.xml +++ b/library/ui-strings/src/main/res/values-de/strings.xml @@ -2918,4 +2918,5 @@ Du kannst keine Sprachnachricht beginnen, da du im Moment eine Echtzeitübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen Kann Sprachnachricht nicht beginnen Verbindungsfehler − Aufnahme pausiert + Als Inline-Code formatieren \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-et/strings.xml b/library/ui-strings/src/main/res/values-et/strings.xml index f33ade2a7e..0f005fe04e 100644 --- a/library/ui-strings/src/main/res/values-et/strings.xml +++ b/library/ui-strings/src/main/res/values-et/strings.xml @@ -2256,7 +2256,7 @@ Koosta valikud Küsimus või teema Küsitluse küsimus või teema - Koosta üks küsitlus + Loo selline küsitlus Küsitlus Saada e-posti aadressid ja telefoninumbrid %s serverisse Sinu kontaktid on vaid sinu teada. Kui tahad nende hulgast leida Matrix\'i kasutajaid, siis me vajame sinu luba nende andmete saatmiseks räsitud kujul isikutuvastusserverisse. @@ -2330,9 +2330,9 @@ Asukoht Jaga asukohta Tulemusi kuvame vaid siis, kui küsitlus on lõppenud - Küsitlus on lõppenud + Suletud valikutega küsitlus Osalejad näevad tulemusi peale oma valiku salvestamist - Ava küsitlus + Avatud valikutega küsitlus Küsitluse tüüp Muuda küsitlust Hääletanuid ei ole @@ -2910,4 +2910,5 @@ Häälsõnumi esitamine ei õnnestu Kuna sa hetkel salvestad ringhäälingukõnet, siis häälsõnumi salvestamine või esitamine ei õnnestu. Selleks palun lõpeta ringhäälingukõne Viga võrguühenduses - salvestamine on peatatud + Kasuta lõimitud koodi vormingut \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-fa/strings.xml b/library/ui-strings/src/main/res/values-fa/strings.xml index d498f4a51b..9b1d367dde 100644 --- a/library/ui-strings/src/main/res/values-fa/strings.xml +++ b/library/ui-strings/src/main/res/values-fa/strings.xml @@ -2919,4 +2919,5 @@ از آن‌جا که در حال ضبط پخشی زنده‌اید، نمی‌توانید پیامی صوتی را آغاز کنید. لطفاً برای آغاز ضبط یک پیام صوتی، پخش زنده‌تان را پایان دهید نمی‌توان پخش صوتی را آغاز کرد خطای اتّصال - ضبط مکث شد + اعمال قالب کد درون‌خط \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-fr/strings.xml b/library/ui-strings/src/main/res/values-fr/strings.xml index d62d208e43..491a2660c4 100644 --- a/library/ui-strings/src/main/res/values-fr/strings.xml +++ b/library/ui-strings/src/main/res/values-fr/strings.xml @@ -2919,4 +2919,5 @@ Vous ne pouvez pas commencer un message vocal car vous êtes en train d’enregistrer une diffusion en direct. Veuillez terminer cette diffusion pour commencer un message vocal Impossible de démarrer un message vocal Erreur de connexion – Enregistrement en pause + Appliquer le formatage de code en ligne \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-hu/strings.xml b/library/ui-strings/src/main/res/values-hu/strings.xml index c265b79969..a44bc9b78b 100644 --- a/library/ui-strings/src/main/res/values-hu/strings.xml +++ b/library/ui-strings/src/main/res/values-hu/strings.xml @@ -2919,4 +2919,5 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze Nem lehet hang üzenetet indítani élő közvetítés felvétele közben. Az élő közvetítés bejezése szükséges a hang üzenet indításához Hang üzenetet nem lehet elindítani Kapcsolódási hiba – Felvétel szüneteltetve + Beágyazott kód formátum alkalmazása \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-in/strings.xml b/library/ui-strings/src/main/res/values-in/strings.xml index 8a05481fd5..ca871db81b 100644 --- a/library/ui-strings/src/main/res/values-in/strings.xml +++ b/library/ui-strings/src/main/res/values-in/strings.xml @@ -2861,4 +2861,5 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Kesalahan koneksi - Perekaman dijeda Anda tidak dapat memulai sebuah pesan suara karena Anda saat ini merekam sebuah siaran langsung. Silakan mengakhiri siaran langsung Anda untuk memulai merekam sebuah pesan suara Tidak dapat memulai pesan suara + Terapkan format kode dalam baris \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-it/strings.xml b/library/ui-strings/src/main/res/values-it/strings.xml index d8c81974b2..80a0b7045f 100644 --- a/library/ui-strings/src/main/res/values-it/strings.xml +++ b/library/ui-strings/src/main/res/values-it/strings.xml @@ -2909,4 +2909,6 @@ Non puoi iniziare un messaggio vocale perché stai registrando una trasmissione in diretta. Termina la trasmissione per potere iniziare un messaggio vocale Impossibile iniziare il messaggio vocale - + Applica formato codice interlinea + Errore di connessione - Registrazione in pausa + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-ja/strings.xml b/library/ui-strings/src/main/res/values-ja/strings.xml index 0b987ce683..54a8c8ee0f 100644 --- a/library/ui-strings/src/main/res/values-ja/strings.xml +++ b/library/ui-strings/src/main/res/values-ja/strings.xml @@ -1,5 +1,5 @@ - + %sの招待 %1$sが%2$sを招待しました %1$sがあなたを招待しました @@ -23,7 +23,7 @@ ルームへの招待 %1$sと%2$s 空のルーム - %1$sが今後のルーム履歴を%2$sに見えるように設定しました。 + %1$sが今後のルーム履歴を「%2$s」閲覧可能に設定しました。 ルームのメンバー全員(招待された時点から) ルームのメンバー全員(参加した時点から) ルームのメンバー全員 @@ -76,7 +76,7 @@ すぐに返信 開く 閉じる - クリップボードへコピー + クリップボードにコピーしました 警告 お気に入り メンバー @@ -93,7 +93,7 @@ ログを送信 開発者が問題を診断するために、このクライアントのログがバグレポートと一緒に送信されます。バグレポートは、ログとスクリーンショットを含めて、公開されることはありません。上記の説明文だけを送信したい場合は、以下のチェックを解除してください。 あなたは不満で端末を振っているようです。バグレポートの画面を開きますか? - 前回、アプリケーションは正常に停止しませんでした。クラッシュ報告の画面を開きますか? + 前回アプリケーションは正常に停止しませんでした。クラッシュ報告の画面を開きますか? 不具合を報告しました 不具合の報告の送信に失敗しました (%s) ルームに参加 @@ -105,7 +105,7 @@ メールアドレスの形式が正しくありません このメールアドレスは既に登録されています。 パスワードを忘れましたか? - 正しいURLを入力して下さい + 正しいURLを入力してください 原寸 大き目 中程度 @@ -115,12 +115,12 @@ いいえ 続行する 最新の未読へ移動 - ルームを退出 - このルームを退出してよろしいですか? + ルームから退出 + このルームから退出してよろしいですか? 招待 - %sさんが文字を入力しています… - %1$sさんと%2$sさんが文字を入力しています… - %1$sさん、%2$sさん他が文字を入力しています… + %sさんが入力しています… + %1$sさんと%2$sさんが入力しています… + %1$s、%2$s他が入力しています… 明るいテーマ 暗いテーマ 黒いテーマ @@ -134,7 +134,7 @@ 削除 参加 このルームで発言する権限がありません。 - 自分のアイコン画像 + プロフィール画像 表示名 メールアドレスを追加 電話番号を追加 @@ -144,7 +144,7 @@ 1対1のチャットでのメッセージ グループチャットでのメッセージ ルームへ招待されたとき - 通話の呼び出しがあったとき + 通話への招待 自動発言プログラム(Bot)が発言した時 端末起動時に開始 アプリを閉じているときの動作 @@ -247,9 +247,7 @@ 現在のパスワード 新しいパスワード パスワードの更新に失敗しました - %sの全てのメッセージを表示しますか? -\n -\nこの操作はアプリを再起動するため、時間がかかる場合があります。 + %sの全てのメッセージを表示しますか? 外観 公開端末名 ルームのエンドツーエンド暗号鍵をエクスポート @@ -278,9 +276,9 @@ リクエストの送信に失敗しました。 ウィジェットを作成できません。 ウィジェットをこのルームから削除してもよろしいですか? - 一致していない場合は、コミュニケーションのセキュリティーが破られている可能性があります。 + 一致していない場合は、コミュニケーションのセキュリティーが損なわれている可能性があります。 このセッションでは、未認証のセッションに対して暗号化されたメッセージを送信しない。 - 認証済のセッションに対してのみ暗号化 + 認証済のセッションにのみ暗号化 インポート ローカルファイルから鍵をインポート ルームの暗号鍵をインポート @@ -294,7 +292,7 @@ 通知あり(音量大) 通知あり(サイレント) 不具合の報告 - このユーザーにあなたと同じ権限を与えます。この変更は取り消せません。 + このユーザーにあなたと同じ権限レベルを与えようとしています。この変更は取り消せません。 \nよろしいですか? 信用する 信用しない @@ -314,14 +312,14 @@ olmのバージョン サードパーティーの使用に関する掲示 ホーム画面 - 逃した通知があるルームを固定 - 未読のあるルームを固定 + 逃した通知があるルームをピン止め + 未読メッセージがあるルームをピン止め 分析 復号エラー セッションキー 未認証 - 認証する - 他のセッションのユーザー設定で、以下を比較して確認してください: + 認証 + 他のセッションのユーザー設定で、以下を比較して承認してください: ルームのディレクトリを選択 サーバー名 %sサーバー上の全てのルーム @@ -399,7 +397,7 @@ 指定したIDのユーザーの管理者権限を取り消す 指定したユーザーを現在のルームに招待 指定されたアドレスのルームに参加 - ルームを退室 + ルームから退出 ルームの説明を設定 指定したIDのユーザーをこのルームから追放 表示するニックネームを変更 @@ -409,7 +407,7 @@ エラー 今すぐ確認 アカウントを停止 - この操作により、あなたのアカウントは永久に使えなくなります。あなたはログインできなくなり、誰も同じユーザーIDを再登録できなくなります。アカウントが参加している全てのルームを退出し、IDサーバーからアカウントの詳細は削除されます。 この操作は取り消せません。 + この操作により、あなたのアカウントは永久に使えなくなります。あなたはログインできなくなり、誰も同じユーザーIDを再登録できなくなります。アカウントが参加している全てのルームから退出し、IDサーバーからアカウントの詳細は削除されます。 この操作は取り消せません。 \n \nアカウントを停止しても、 デフォルトではあなたが送信したメッセージの履歴は消去されません。メッセージの履歴の消去を望む場合は、以下のボックスにチェックを入れてください。 \n @@ -420,18 +418,18 @@ このルームは置き換えられており、アクティブではありません。 こちらから継続中の会話を確認 このルームは別の会話の続きです - 以前のメッセージを見るには、ここをクリックしてください + 以前のメッセージを表示するには、ここをクリックしてください サービス管理者に連絡してください このホームサーバーはリソース制限の1つを超過しているため、 ユーザーがログインできなくなることがあります - このホームサーバーはリソース制限の1つを超過しています。 + このホームサーバーはリソースの上限に達しました。 このホームサーバーは月間アクティブユーザーの上限に達しているため、 ユーザーがログインできなくなることがあります - このホームサーバーは月間アクティブユーザーの上限に達しています。 + このホームサーバーは月間アクティブユーザー数の上限に達しました 。 この制限を上げるには、%sしてください。 - このサービスを使い続けるには、%sしてください。 + このサービスの使用を継続するには、%sしてください。 申し訳ありません、エラーが発生しました エクスポートされた鍵を暗号化するパスフレーズを作成してください。 鍵をインポートするには、同一のパスフレーズを入力する必要があります。 パスフレーズの作成 - パスフレーズが一致していません + パスフレーズが一致しません %1$s:%2$s %d+ 展開 @@ -465,7 +463,7 @@ パスワード パスワード 今ここでサインアウトすると、あなたの暗号化されたメッセージは失われてしまいます - 鍵のバックアップは現在処理中です。処理中にサインアウトすると、暗号化されたメッセージにアクセスできなくなります。 + 鍵をバックアップしています。処理中にサインアウトすると、暗号化されたメッセージにアクセスできなくなります。 暗号化されたメッセージにアクセスできなくなることを防ぐため、鍵の安全なバックアップはあなたのセッション全てで有効化してください。 暗号化されたメッセージは不要です 鍵をバックアップしています… @@ -485,13 +483,13 @@ 署名 通知に関する問題の解決 システム設定。 - アカウント設定。 + アカウントの設定。 カスタム設定。 起動時に実行 バックグラウンド制限の確認 編集 返信 - メッセージが削除されました + メッセージを削除しました 削除済のメッセージを表示 削除されたメッセージに関する通知を表示 ユーザーによって削除されたイベント @@ -535,7 +533,7 @@ %1$d人の参加者 アップロード - ルームを退出 + ルームから退出 ルームから退室しています… 管理者 モデレーター @@ -560,8 +558,8 @@ クロス署名は無効です 有効なセッション 全てのセッションを表示 - セッションの管理 - このセッションからログアウト + セッションを管理 + このセッションからサインアウト %d件のアクティブなセッション @@ -585,7 +583,7 @@ コピー 成功 通知 - 破棄 + 取り消す 再生 閉じる スキップ @@ -616,7 +614,7 @@ マークダウン書式 メッセージ送信前にマークダウン書式を適用します。これにより、アスタリスクを使用して斜体のテキストを表示するなどの高度な書式設定が利用できます。 音声とビデオ - 国際電話番号形式で入力してください(電話番号の最初に「+」が付きます) + 国際電話番号形式で入力してください(電話番号の最初に「+」を付けてください) メールアドレス あなたのアカウントに追加されたメールアドレスはありません あなたのアカウントに追加された電話番号はありません @@ -678,7 +676,7 @@ サウンドデバイスを選択 リアルタイム接続を確立できませんでした。 \nホームサーバーの管理者に、通話が正常に動作するためにTURNを設定するようご連絡ください。 - 終了 + 電話を切る 拒否 承諾 ウィジェットを削除できませんでした @@ -691,8 +689,8 @@ なし トピック ルーム名 - このルーム内のメッセージはエンドツーエンド暗号化されていません。 - ここでのメッセージはエンドツーエンド暗号化されていません。 + このルーム内のメッセージはエンドツーエンドで暗号化されていません。 + ここでのメッセージはエンドツーエンドで暗号化されていません。 設定 あなたにはこのルームの暗号化を有効にする権限がありません。 未読メッセージ @@ -700,7 +698,7 @@ タイムラインで非表示のイベントを表示 QRコードをスキャン QRコード - QRコードによる追加 + QRコードで追加 コードを共有 ${app_name}で話しましょう:%s 友達を招待 @@ -775,8 +773,8 @@ このルームは公開されていません。 招待がなければ再び参加することはできません。 連絡先へのアクセスを許可します。 QRコードをスキャンするには、カメラへのアクセスを許可する必要があります。 - 通話をかけました - %sが通話をかけました + 通話を保留しました + %sが通話を保留しました 保留 通話をやり直す ビデオ通話が行われています… @@ -858,9 +856,9 @@ %sがこのルームのサーバーアクセス制御リストを設定しました。 %sがここをアップグレードしました。 %sがこのルームをアップグレードしました。 - 今後のメッセージを%1$sに見えるように設定しました。 - 今後のルーム履歴を%1$sに見えるように設定しました。 - %1$sが今後のメッセージを%2$sに見えるように設定しました。 + 今後のメッセージを「%1$s」閲覧可能に設定しました。 + 今後のルーム履歴を「%1$s」閲覧可能に設定しました。 + %1$sが今後のメッセージを「%2$s」閲覧可能に設定しました。 %sが通話を設定するためにデータを送信しました。 通話を開始しました。 ビデオ通話を開始しました。 @@ -874,7 +872,7 @@ %1$sが招待を拒否しました。理由:%2$s 退出しました。理由:%1$s %1$sが退出しました。理由:%2$s - このルームを退出しました。理由:%1$s + このルームから退出しました。理由:%1$s 初期同期: \n退出したルームをインポートしています 初期同期: @@ -882,7 +880,7 @@ 初期同期: \n会話を読み込んでいます \n多くのルームに参加している場合、読み込みに時間がかかるかもしれません - %1$sがこのルームを退出しました。理由:%2$s + %1$sがこのルームから退出しました。理由:%2$s このルームに参加しました。理由:%1$s %1$sがこのルームに参加しました。理由:%2$s このルームに参加しました。理由:%1$s @@ -1014,7 +1012,7 @@ ファイルとして保存 共有 完了 - 成功! + 成功しました! バックアップを作成しています パスフレーズを設定 手動で鍵をエクスポート @@ -1076,7 +1074,7 @@ バックアップには認証済のセッション %s による不正な署名があります バックアップには未認証のセッション %s による有効な署名があります バックアップには認証済のセッション %s による署名があります。 - バックアップはこのセッションによる有効な署名があります。 + バックアップにはこのセッションによる有効な署名があります。 バックアップには%sというIDの不明のセッションによる署名があります。 このセッションでは鍵がバックアップされていません。 このセッションでは鍵のバックアップが無効になっています。 @@ -1088,7 +1086,7 @@ %d個のキーが含まれたバックアップを復元しました。 - バックアップが復元されました %s! + バックアップを復元しました %s! このリカバリーキーではバックアップを復号化できませんでした。正しいリカバリーキーを入力したことを確認してください。 リカバリーキーを入力してください 履歴のロックを解除 @@ -1097,11 +1095,11 @@ リカバリーキーを計算しています… バックアップを復元しています: このパスフレーズではバックアップを復号化できませんでした。正しい復旧用のパスフレーズを入力したことを確認してください。 - リカバリーキーを喪失しましたか? 設定で新しいリカバリーキーを設定できます。 + リカバリーキーを無くしましたか? 設定で新しいリカバリーキーを設定できます。 バックアップのバージョンを取得しています… 暗号化されたメッセージ履歴のロックを解除するには、復旧用のパスフレーズを使用してください 復旧用のパスフレーズが分からなければ、%sできます。 - リカバリーキーを使用して、暗号化されたメッセージの履歴のロックを解除 + リカバリーキーを使うと、暗号化されたメッセージの履歴のロックを解除できます リカバリーキーを入力 リカバリーキーを使用 ログアウトしたりこの端末を失くしたりすると、メッセージにアクセスできなくなる可能性があります。 @@ -1161,7 +1159,7 @@ \n%s ウィジェットを再読み込み これを使用すると、クッキーが設定され、データが%sと共有される可能性があります: - ウィジェットの追加者: + ウィジェットを追加した人: **送信に失敗 - ルームを開いてください 新しい招待 %1$sと%2$s @@ -1221,7 +1219,7 @@ ホームサーバーAPIのURL アクセスを取り消す 表示 - このルーム内のメッセージはエンドツーエンド暗号化されています。 + このルームのメッセージはエンドツーエンドで暗号化されています。 ダイレクトメッセージ 新しいダイレクトメッセージを送信 メールアドレス(任意) @@ -1305,7 +1303,7 @@ 現在、このルームにはアクセスできません。 \n後でもう一度やり直すか、ルームの管理者にアクセス権があるかどうかを確認するよう依頼してください。 このルームはプレビューできません - お待ち下さい… + お待ちください… ネットワークがありません。インターネット接続を確認してください。 不正な形式のイベントです。表示できません ルームの管理者によってモデレートされたイベント @@ -1314,8 +1312,8 @@ リアクションを追加 同意 リアクション - ルームがここに表示されます。右下の[+]をタップして、既存のルームを検索するか、独自のルームを開始します。 - ダイレクトメッセージの会話がここに表示されます。右下の[+]をタップして開始します。 + ルームがここに表示されます。右下の+をタップすると、既存のルームを検索するか、自分のルームを開始できます。 + ダイレクトメッセージの会話がここに表示されます。右下の+をタップして開始します。 ルーム 会話 未読メッセージはありません @@ -1336,7 +1334,7 @@ %1$s:%2$s %3$s %1$s:%2$s あなたが知らないかもしれない他のスペースやルーム - 誰がこのルームを検索し、参加できるか決める。 + 誰がこのルームを検索・参加できるか選択してください。 タップしスペースを編集 スペースを選択 アクセス可能なスペース @@ -1363,16 +1361,16 @@ メンションとキーワード 通知のデフォルト - %d個の不在着信(ビデオ) + %d件の不在着信(ビデオ) - %d個の不在着信(音声) + %d件の不在着信(音声) デフォルトで使いもう尋ねない 鍵の共有リクエストの履歴を送信 結果がありません 自分に電話をかけることはできません。参加者が招待を受け入れるまでお待ちください - ミーティングはJitsiのセキュリティーとパーミッションポリシーを使用します。会議中は、現在ルームにいる全ての人に招待状が表示されます。 + ミーティングはJitsiのセキュリティーとパーミッションポリシーを使用します。会議中は、現在ルームにいる全ての人に招待が表示されます。 権限がありません 音声メッセージを送信するには、マイクの権限を許可してください。 この操作を実行するには、システム設定からカメラの権限を許可してください。 @@ -1386,11 +1384,11 @@ %sにメールを送りました。メールを確認してリンクをクリックしてください %sにメールを送りました。メールの確認リンクをクリックしてください 発見可能な電話番号 - IDサーバーとの接続を解除すると、他のユーザーによって発見されなくなり、また、メールアドレスや電話で他のユーザーを招待することができなくなります。 + IDサーバーとの接続を解除すると、他のユーザーによって見つけられなくなり、また、メールアドレスや電話で他のユーザーを招待することもできなくなります。 電話番号を追加すると、発見可能に設定する電話番号を選択できるようになります。 メールアドレスを追加すると、発見可能に設定するメールアドレスを選択できるようになります。 - 現在、IDサーバーを使用していません。あなたの知っている連絡先を発見したり、その連絡先から発見されるようにするには、以下でIDサーバーを設定してください。 - あなたは現在%1$sを使って連絡先を見つけたり、連絡先から見つけられるようにしています。 + 現在、IDサーバーを使用していません。自分の連絡先を見つけたり、連絡先から見つけてもらったりするには、以下でIDサーバーを設定してください。 + 現在%1$sを使って自分の連絡先を見つけたり、連絡先から見つけてもらったりできるようにしています。 IDサーバーを変更 IDサーバーの設定 IDサーバーの切断 @@ -1400,7 +1398,7 @@ 利用規約 編集履歴を表示 提案 - クリップボードにコピーされたリンク + リンクをクリップボードにコピーしました メイン画面に未読通知専用のタブを追加する。 ルーム名を検索 名前もしくはID (#例えば:matrix.org) @@ -1421,7 +1419,7 @@ \n- あなたの端末が使用しているインターネット接続 \n \n設定画面からパスワードとリカバリーキーを早急に変更することを推奨します。 - 電子メール + メールアドレス アドレス 続行する ファイル @@ -1472,10 +1470,10 @@ このルームにファイルはありません このルームにメディアはありません 公開ルームをアップグレード - 非公開スペース + 非公開のスペース 公開スペース - 送信済 - 送信中 + 送信しました + 送信しています 種類 確認済 選択済 @@ -1521,7 +1519,7 @@ 音声メッセージを録音できません ルームのアップグレードには権限が必要です アップグレード - アップグレードが必要です + アップグレードが必要 非公開のルームをアップグレード 音声メッセージを一時停止 このメールアドレスをアカウントにリンク @@ -1594,11 +1592,11 @@ キーワードに「%s」を含めることはできません %sへのメール通知を有効にする ヒント:メッセージを長押しして「%s」を選択。 - スレッドを用いると、会話のテーマを保ったり、会話を追跡したりするのが容易になります。 - あなたの非公開スペース + スレッド機能を使うと、会話のテーマを維持したり、会話を簡単に追跡したりすることができます。 + あなたの非公開のスペース あなたの公開スペース 自分のみ - スレッドで議論を整理して管理 + スレッド機能を使って、会話をまとめましょう %sを待機しています… この端末でスキャン 認証を送信済 @@ -1757,7 +1755,7 @@ あなたの連絡先は非公開です。端末の連絡先からユーザーを発見するためには、連絡先の情報をIDサーバーに送信する許可が必要です。 ディスカバリー設定を開く トピックを追加 - %sはルームを作成し設定しました。 + %sがルームを作成し設定しました。 参加しました。 %sが参加しました。 このルームで使用されている暗号化はサポートされていません @@ -1819,7 +1817,7 @@ 再送信 コードを入力 電話番号 - 退席中 + 離席中 オフライン オンライン 一般 @@ -1850,11 +1848,11 @@ 紙吹雪🎉を送る 降雪❄️を送る あなたのチームのメッセージングに。 - エンドツーエンドで暗号化され、電話番号不要。広告やデータマイニング無し。 + エンドツーエンドで暗号化されており、登録に電話番号は不要です。広告もデータ収集もありません。 会話の保存先を自分で決められ、自分で管理できる独立したコミュニケーション。Matrixをもとに。 - お宅での対面会話と同じぐらいのプライバシーを提供する、セキュアで独立したコミュニケーション。 - セキュアメッセージング - 管理権を握るのは、あなたです。 + オンライン上でも対面の会話と同じレベルでプライバシーを守る、安全で独立したコミュニケーション。 + 安全なメッセージ。 + 主導権を握るのは、あなたです。 ${app_name}の使用に関するヘルプ 詳細なログは、イライラシェイクでログを送信する際に、より多くのログを提供することで、開発者にとっての助けになります。有効にした場合でも、メッセージの内容やその他のプライベートな情報は記録されません。 ルームのアップグレードは高度な作業であり、不具合や欠けている機能、セキュリティー上の脆弱性がある場合に推奨されます。 @@ -1869,7 +1867,7 @@ %sに招待 ユーザー名かメールアドレスで招待 - %sを退出してよろしいですか? + %sから退出してよろしいですか? スペースは、ルームや連絡先をグループ化する新しい方法です。 招待されています 新しいスペースを、あなたが管理するスペースに追加。 @@ -1954,7 +1952,7 @@ 認証 メールアドレスが正しくないようです 国際電話番号の形式を使用してください。 - 国際電話番号は「+」から始まる必要があります + 国際電話番号は「+」から始めてください コードを%1$sに送信しました。以下に入力して認証してください。 このメールアドレスはどのアカウントにも登録されていません パスワードを変更すると、全てのセッションでのエンドツーエンド暗号鍵がリセットされ、暗号化されたメッセージ履歴が読めなくなります。パスワードを再設定する前に、鍵のバックアップを設定するか、他のセッションからルームの鍵をエクスポートしておいてください。 @@ -1970,7 +1968,7 @@ %1$sを読み込み中にエラーが発生しました(%2$d) 利用したいサーバーのアドレスを入力してください 利用したいModular Elementまたはサーバーのアドレスを入力してください - 迷っていますか?%sしてもいいです + 迷っていますか?%s みんなと繋がる手助けをいたします。 自分のコード @@ -1988,7 +1986,7 @@ 音を出さずに通知 音を出して通知 既定の信頼レベル - いくつかのメッセージは送信されませんでした + いくつかのメッセージが送信されませんでした 保存されていない変更があります。変更を破棄しますか? このルームはまだ作成されていません。キャンセルしますか? テキストメッセージで共有 @@ -2059,11 +2057,9 @@ ただいま%1$sにメールを送信しました。 \nアカウント登録を続行するにはメール内のリンクをクリックしてください。 CAPTCHA認証を行ってください - アカウントがまだ登録されていません。 -\n -\n登録を中止しますか? + アカウントがまだ作成されていません。登録を中止しますか? %1$sにアカウント登録 - あなたはすべてのセッションからログアウトしており、これ以上プッシュ通知を受け取れません。通知を再び有効にするには、各端末でサインインしてください。 + すべてのセッションからログアウトしているため、プッシュ通知を受け取れません。通知を再び有効にするには、各端末でサインインしてください。 セキュリティーフレーズを設定 セキュリティーフレーズを使用 セキュリティーキーは、パスワードマネージャーもしくは金庫のような安全な場所で保管してください。 @@ -2133,10 +2129,10 @@ 暗号化の設定が正しくありません。 暗号化を復元 暗号化を有効な状態に取り戻すために、管理者に連絡してください。 - このユーザーとのメッセージはエンドツーエンド暗号化されており、第三者には読めません。 + このユーザーとのメッセージはエンドツーエンドで暗号化されており、第三者が解読することはできません。 このコードを相手の画面に現れているコードと比較してください。 - 絵文字を比較して、同じ順番に現れているのを確認してください。 - セキュリティーを高めるために、対面で行うか、他の信頼できる通信手段を利用しましょう。 + 絵文字を比較して、同じ順番で現れているのを確認してください。 + セキュリティーを高めるために、対面で行うか、他の通信手段を利用しましょう。 選択されたエモートを虹色にして送信します 選択されたテキストを虹色にして送信します ${app_name}がID%1$sのイベントを処理中にエラーが発生しました @@ -2173,7 +2169,7 @@ %1$sが%2$sの権限レベルを変更しました。 %1$sの権限レベルを変更しました。 誰と使いますか? - どんなスペースを作りますか? + 作成するスペースの種類を選択してください 自分と仲間の非公開のスペース ルームを整理するためのプライベートスペース ここが会話のスタート地点です。 @@ -2188,7 +2184,7 @@ 私のスペース %1$s %2$s に参加してください スキップ ルームの通知 - 現在、IDサーバーを使用していません。あなたの知っているチームメイトを発見したり、そのチームメイトから発見されるようにするには、以下でIDサーバーを設定してください。 + 現在、IDサーバーを使用していません。あなたの知っているチームメイトを招待したり、チームメイトから見つけてもらったりするには、以下でIDサーバーを設定してください。 ディスカバリーの設定を終了します。 ここの参加者はあなただけです。退出すると、今後あなたを含めて誰も参加できなくなります。 再び招待されない限り、再参加することはできません。 @@ -2221,7 +2217,7 @@ このルームが発見できません。存在することを確認してください。 指紋や顔画像など、端末に固有の生体認証を有効にする。 絵文字で認証 - テキストで認証 + テキストを使って手動で認証 復旧用の手段を全て無くしてしまいましたか?全てリセットする クロス署名に対応した他のMatrixのクライアントでも使用できます。 どのような議論を%sで行いたいですか? @@ -2253,7 +2249,7 @@ 通話の転送中にエラーが発生しました 2分後にPINコードを要求 ルーム名やメッセージの内容などの詳細を表示。 - エラーが多すぎます。ログアウトしました + 多数のエラーが発生したため、ログアウトしました 警告!もう一度誤ったコードを入力すると、ログアウトします! コードが誤っています。残りの試行回数は%d回です @@ -2278,7 +2274,7 @@ エラーのためメッセージが送信されませんでした %sにいない人を探していますか? 直接${app_name}で招待を受け取るには、設定画面から%sしてください。 - PINコードでしか${app_name}のロックを解除することはできません。 + PINコードでしか${app_name}のロックを解除できません。 ${app_name}を開く際には、毎回PINコードの入力が必要です。 あなたがブロックされているルームを開くことはできません。 PINコードの認証に失敗しました。新しいコードを入力してください。 @@ -2291,7 +2287,7 @@ 確認のため、セキュリティーフレーズを再入力してください。 ホームサーバー(%1$s)は、IDサーバーに%2$sを設定するように提案しています IDサーバー %s から切断しますか? - ダイレクトメッセージを作成できませんでした。招待したユーザーを確認し、もう一度やり直してください。 + ダイレクトメッセージを作成できませんでした。招待したいユーザーを確認し、もう一度やり直してください。 セキュリティーフレーズ 自分と仲間 メッセージの種類がありません @@ -2310,7 +2306,7 @@ 操作を実行できません。ホームサーバーは最新のバージョンではありません。 ビデオ通話が拒否されました 音声通話が拒否されました - %1$sは通話を拒否しました + %1$sは着信を拒否しました このデバイスを認証可能な他の端末が全くない場合にのみ、続行してください。 このセッションを信頼済として認証すると、暗号化されたメッセージにアクセスすることができます。このアカウントにサインインしなかった場合は、あなたのアカウントのセキュリティーが破られている可能性があります: アカウントのセキュリティーが破られている可能性があります @@ -2331,7 +2327,7 @@ %d個のエントリー 保存して続行 - 設定を保存しました。 + 設定画面からいつでもプロフィールを更新できます これは後から変更できます。 プロフィール画像を追加 これは後から変更できます @@ -2342,7 +2338,7 @@ 位置情報(ライブ)を共有 中止 表示名を選択 - あなたのアカウント %s が作成されました。 + あなたのアカウント %s が作成されました おめでとうございます! 近日中にスレッドはベータ版となります。 \n @@ -2355,7 +2351,7 @@ フィードバックを送信 ベータ版 ベータ版 - 試す + 試してみる オフラインモード 新着はありません。 - ユーザーの無視が解除されました @@ -2378,7 +2374,7 @@ %1$sと他%2$d名 %1$sと%2$s - ホームサーバーがサポートしていないため、スレッド機能は不安定かもしれません。スレッドのメッセージは安定して表示されないおそれがあります。%sスレッド機能を有効にしてよろしいですか? + ホームサーバーがサポートしていないため、スレッド機能は不安定かもしれません。スレッドのメッセージが安定して表示されないおそれがあります。%sスレッド機能を有効にしてよろしいですか? スレッド(ベータ版) スレッドを用いると、会話のテーマを保ったり、会話を追跡したりするのが容易になります。%sスレッドを有効にするとアプリケーションが再起動します。再起動には時間がかかる可能性があります。 スレッド(ベータ版) @@ -2472,7 +2468,7 @@ QRコードが不正です。 スペースは、ルームと連絡先をまとめる新しい方法です。はじめに、スペースを作成しましょう。 最近の履歴を表示 - この暗号化されたメッセージの信頼性はこの端末では保証できません。 + この暗号化されたメッセージの真正性はこの端末では保証できません。 アカウントが安全かどうか確認してください 未認証のセッションがあります 連絡先 @@ -2500,4 +2496,268 @@ リッチテキストエディターを試してみる(プレーンテキストモードは近日公開) タブを使用してElementの表示をシンプルにする セッションの詳細 + + %1$d日以上使用されていません + + + %1$d日以上使用されていません(%2$s) + + 地図を読み込めません +\nこのホームサーバーは地図が読み込むよう設定されていないおそれがあります。 + スペースは、ルームや連絡先をグループ化する新しい方法です。右下のボタンを使うと、既存のルームを追加したり新たに作成したりできます。 + セキュリティーに関する勧告 + その他のセッション + セキュリティーを最大限に高めるには、不明なセッションや利用していないセッションからサインアウトしてください。 + 生体認証を有効にできませんでした。 + 関連付けに失敗しました。 + おかえりなさい! + または + %sに返信しています + アニメーション画像がタイムラインに表示されたらすぐに再生 + 斜字体にする + 非アクティブなセッションは、しばらく使用されていませんが、暗号鍵を受信しているセッションです。 +\n +\n使用していないセッションを削除すると、セキュリティーとパフォーマンスが改善されます。また、新しいセッションが疑わしい場合に、より容易に特定できるようになります。 + 非アクティブなセッション + 改善したセッションの管理画面を使用します。 + 未認証のセッション + ルームのタイムラインで音声配信を録音して送信することを可能にします。 + 音声配信を有効にする + 未読のメッセージがある場合は、ここに表示されます。 + 報告することはありません。 + クライアントの情報の保存を有効にする + セッション名は連絡先にも表示されます。 + セッション名を設定すると、端末をより簡単に認識できるようになります。 + このセッションでプッシュ通知を受信。 + 絞り込みを解除 + 絞り込み + アプリケーション、端末、アクティビティーに関する情報。 + 直近のアクティビティー + セッション名 + + %1$d件のセッションからサインアウト + + 使用していないセッションはありません。 + 未認証のセッションはありません。 + 認証済のセッションはありません。 + + 使用していない古いセッション(%1$d日以上使用されていません)からサインアウトすることを検討してください。 + + 非アクティブ + セッションを認証すると、より安全なメッセージのやりとりが可能になります。見覚えのない、または使用していないセッションがあれば、サインアウトしましょう。 + 未認証 + 認証済 + 太字にする + 端末に接続しています + ホームサーバーはQRコードによるサインインをサポートしていません。 + 安全な接続を確立しました + 確認 + リンクを設定 + 全画面モードを切り替える + テキスト + リンク + リンクを作成 + リンクを編集 + 返信先 + アンケート + アクセストークン + アクセストークンを用いると、あなたのアカウントの全ての情報にアクセスできます。外部に公開したり、誰かと共有したりしないでください。 + セッションを選択 + このセッションからサインアウト + IPアドレスを表示しない + IPアドレスを表示 + 他の全てのセッションからサインアウト + サインアウト + 非アクティブ + 安全なメッセージのやりとりの準備ができていません + 未認証 + 安全なメッセージのやりとりの準備ができました + 認証済 + 全てのセッション + 端末 + セッション + 現在のセッション + 非アクティブなセッション + 未認証のセッション + 以下の勧告に従い、アカウントのセキュリティーを改善しましょう。 + 全て表示(%1$d) + 詳細を表示 + セッションを認証 + このセッションは暗号化をサポートしていないため、認証できません。 + セキュリティーと安定性の観点から、このセッションを認証するかサインアウトしてください。 + より安全なメッセージのやりとりのために、現在のセッションを認証しましょう。 + このセッションは安全なメッセージのやりとりの準備ができています。 + 現在のセッションは安全なメッセージのやりとりに対応しています。 + 認証の状態が不明です + 未認証のセッション + 認証済のセッション + 端末の種類が不明です + デスクトップ + ウェブ + 携帯端末 + + %d件のメッセージを削除しました + + 位置情報の共有を有効にする + 注意:これは一時的な実装による試験機能です。位置情報の履歴を削除することはできません。高度なユーザーは、あなたがこのルームで位置情報(ライブ)の共有を停止した後でも、あなたの位置情報の履歴を閲覧することができます。 + 位置情報(ライブ)の共有 + エンドポイントが見つかりません。 + 現在のエンドポイント:%s + エンドポイント + 現在%sを使用しています。 + 方法 + バックグラウンド同期 + バックグラウンド同期以外の方法がありません。 + Google Playサービス以外の方法がありません。 + 利用可能な方法 + 通知方法 + Googleサービス + 通知の受信方法を選択してください + 画面を共有しています + ${app_name}画面共有 + テキストの装飾 + 連絡先 + カメラ + 位置情報 + アンケート + 音声配信 + 添付ファイル + ステッカー + 音声配信を開始 + 位置情報(ライブ) + 位置情報を共有 + このルームでの位置情報(ライブ)の共有には適切な権限が必要です。 + 位置情報(ライブ)の共有に必要な権限がありません + 一時的な実装。位置情報がルームの履歴に残ります + 位置情報(ライブ)の共有を有効にする + 位置情報を共有しています + ${app_name}位置情報(ライブ) + 残り%1$s + 位置情報(ライブ)を表示 + 位置情報(ライブ)が終了しました + 位置情報(ライブ)を読み込んでいます… + 8時間 + 1時間 + 15分 + 位置情報(ライブ)を共有する時間 + 現在の位置にズーム + 地図で選択した位置情報のピン + アンケートの取得中にエラーが発生しました。 + アンケートを表示しています + このルームに過去のアンケートはありません + 過去のアンケート + このルームに実施中のアンケートはありません + 実施中のアンケート + 復号エラーにより、いくつかの投票はカウントできません + アンケートを終了しました。 + アンケートが終了するまで結果は表示できません + 履歴を共有している暗号化されたルームに招待する際、暗号化された履歴が表示されるようになります。 + MSC3061:過去のメッセージ用にルームの鍵を共有 + ライブ配信を終了してよろしいですか?配信を終了し、録音をこのルームで利用できるよう設定します。 + ライブ配信を停止しますか? + 残り%1$s + 接続エラー - 録音を停止しました + この音声配信を再生できません。 + 既に音声配信を録音しています。新しく始めるには今の音声配信を終了してください。 + 他の人が既に音声配信を録音しています。新しく始めるには音声配信が終わるまで待機してください。 + このルームで音声配信を開始する権限がありません。ルームの管理者に連絡して権限の付与を依頼してください。 + 新しい音声配信を開始できません + 音声配信を一時停止 + 音声配信の録音を再開 + バッファリングしています… + ライブ配信 + ライブ + (%1$s) + %1$s(%2$s) + %1$sを再生できません + %1$sを一時停止 + %1$sを再生 + %1$d分%2$d秒 + ライブ配信を録音しているため、音声メッセージを開始できません。音声メッセージの録音を開始するには、ライブ配信を終了してください + 音声メッセージを開始できません + 全てのメッセージに最新のプロフィール情報(アバターと表示名)を表示。 + 最新のユーザー情報を表示 + 検索結果がありません + 退出しない + 全て退出 + 現在、このエイリアスにはアクセスできません。 +\n後でもう一度やり直すか、ルームの管理者にアクセス権があるかどうかを確認するよう依頼してください。 + %sのメンバーにはなりません + 設定を開く + ビデオ通話の着信中 + 音声通話の着信中 + 暗号化されたルーム内の現在のアウトバウンドグループセッションを強制的に破棄 + 会話で入力したデータに基づいて入力履歴や辞書などに関する個人用データを変更しないようキーボードに指示します。いくつかのキーボードでは、この設定が無視されることがあります。 + プライベートキーボード + このチャットのメッセージはエンドツーエンドで暗号化されます。 + このQRコードは不正な形式です。他の方法で認証を試してください。 + 最新版を入手(注意:サインインの際に問題が起こる可能性があります) + 暗号化されたメッセージの履歴にアクセスできません。鍵の安全なバックアップと認証用の鍵をリセットして、やり直してください。 + この端末を認証できません + セッション + アンケートの履歴 + 音声配信を開始しました + 位置情報(ライブ)を共有しました + プレーンテキストメッセージの前に (╯°□°)╯︵ ┻━┻ を付ける + このリンクを開けません:コミュニティー機能はスペース機能に変更されました + 電子メールを入力してください + %sの利用規約と運営方針を確認してください + サーバーの運営方針 + 問い合わせる + 自分でサーバーを運営したいですか? + サーバーのURL + あなたのサーバーのアドレスを入力してください + あなたのサーバーのアドレスを指定してください。サーバーにはあなたの全てのデータが保管されます + サーバーを選択 + 編集 + 8文字以上にしてください + アカウントを作成 + ホームに移動 + プロフィールを変更 + ${app_name}は職場利用にも最適です。世界で最も安全な組織によって信頼されています。 + 音声配信 + スペースの一覧を開く + 新しい会話またはルームを作成 + 通知方法をリセット + セッションID: + 続行 + データをアップデートしています… + 編集中 + バックアップにはこのユーザーによる有効な署名があります。 + 開発者ツールの画面を開く + ルームが見つかりませんでした。 +\n後でやり直してください。%s + 直接共有を有効にする + 信頼済の信頼レベル + 警告の信頼レベル + %1$sと相談しています + 初めに相談 + 実施中の通話(%1$s)・ + + %1$d件の実施中の通話・ + + 実施中の通話(%1$s) + 不在着信(ビデオ) + 不在着信(音声) + 実施中のビデオ通話 + 実施中の音声通話 + 新しい生体認証の方法が最近追加されたため、生体認証は無効になりました。設定から再び有効にできます。 + このIDとの連携は現在ありません。 + このホームサーバーは数字だけからなるユーザー名を承諾しません。 + 最初のメッセージを送信すると、%sを会話に招待 + Nightly build + あなたの他の端末でコードをスキャンするか、もしくは反対に、このデバイスでスキャンしてください + Element Matrix Services(EMS)は、高速、安全でリアルタイムのコミュニケーション向きの、堅牢で安定したホスティングサービスです。<a href=\"${ftue_ems_url}\">element.io/ems</a>で方法を調べましょう。 + アカウントにサインインするサーバー + アカウントを作成するサーバー + スレッドは、改良した通知など新機能の追加作業中です。フィードバックをお聞かせください! + 🔒 セキュリティーの設定で、全てのルームに関して認証済のセッションにのみ暗号化を行うよう設定しました。 + プレゼンス(ステータス表示) + 取り込み中 + 他の人は %s であなたを見つけることができます + 有効: + プロフィールのタグ: + 問題が発生しました。ネットワークの接続を確認して、もう一度やり直してください。 + 引用 + チーム、友達、組織向けのオールインワンの安全なチャットアプリです。はじめに、チャットを作成するか既存のルームに参加しましょう。 \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-pl/strings.xml b/library/ui-strings/src/main/res/values-pl/strings.xml index 4419187ba5..2bdd6e806d 100644 --- a/library/ui-strings/src/main/res/values-pl/strings.xml +++ b/library/ui-strings/src/main/res/values-pl/strings.xml @@ -345,7 +345,7 @@ Importuj klucze z lokalnego pliku Importuj Szyfruj wiadomości tylko do zaufanych sesji - Nigdy nie wysyłaj szyfrowanych wiadomości do niezweryfikowanych sesji (bez zielonej tarczy) z tego urządzenia. + Nigdy nie wysyłaj szyfrowanych wiadomości do niezweryfikowanych sesji (bez zielonej tarczy) z tej sesji. Aby sprawdzić czy ta sesja jest zaufana, skontaktuj się z jej właścicielem używając innych form (np. osobiście lub telefonicznie) i zapytaj czy klucz, który widzą w ustawieniach użytkownika dla tego urządzenia pasuje do klucza poniżej: Jeśli klucz pasuje, potwierdź to przyciskiem poniżej. Jeśli nie, to ktoś inny najprawdopodobniej przejmuje lub podszywa się pod tą sesję i powinieneś dodać tę sesję do czarnej listy. W przyszłości proces weryfikacji będzie bardziej skomplikowany. Wyślij naklejkę diff --git a/library/ui-strings/src/main/res/values-ru/strings.xml b/library/ui-strings/src/main/res/values-ru/strings.xml index 5938200c1e..bf329b89ec 100644 --- a/library/ui-strings/src/main/res/values-ru/strings.xml +++ b/library/ui-strings/src/main/res/values-ru/strings.xml @@ -2540,7 +2540,7 @@ Домашний сервер не принимает имя пользователя, состоящее только из цифр. Пропустить этот шаг Сохранить и продолжить - Зайдите в настройки чтобы изменить Ваш профиль + Ваши предпочтения были сохранены Выглядит хорошо! ${app_name} также отлично подходит для работы. Ему доверяют самые надёжные организации в мире. Резервная копия имеет действительную подпись для данного пользователя. diff --git a/library/ui-strings/src/main/res/values-sk/strings.xml b/library/ui-strings/src/main/res/values-sk/strings.xml index c9e92d323b..82deefb371 100644 --- a/library/ui-strings/src/main/res/values-sk/strings.xml +++ b/library/ui-strings/src/main/res/values-sk/strings.xml @@ -2979,4 +2979,5 @@ Nemôžete spustiť hlasovú správu, pretože práve nahrávate živé vysielanie. Ukončite prosím živé vysielanie, aby ste mohli začať nahrávať hlasovú správu Nemožno spustiť hlasovú správu Chyba pripojenia - nahrávanie pozastavené + Použiť formát riadkového kódu \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-sq/strings.xml b/library/ui-strings/src/main/res/values-sq/strings.xml index 374080cb23..447a2b52d7 100644 --- a/library/ui-strings/src/main/res/values-sq/strings.xml +++ b/library/ui-strings/src/main/res/values-sq/strings.xml @@ -2887,4 +2887,23 @@ S’arrihet të luhet ky transmetim zanor. Nisni një transmetim zanor Shërbyesi juaj Home s’mbulon ende paraqitje rrjedhash. - + Apliko format kodi brendazi + Gabim në sjellje pyetësorësh. + Ngarko më tepër pyetësorë + Shfaqje pyetësorësh + + S’ka pyetësorë të kaluar për ditën e kaluar. +\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë. + S’ka pyetësorë aktivë për %1$d ditët e kaluara. +\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë. + + + S’ka pyetësorë aktivë për ditën e kaluar. +\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë. + S’ka pyetësorë aktivë për%1$d ditët e kaluara. +\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë. + + Gabim lidhjeje - Incizimi u ndal + S’mund të nisni një mesazh zanor teksa jeni aktualisht duke incizuar një transmetim të drejtpërdrejtë. Ju lutemi, përfundoni transmetimin tuaj të drejtpërdrejtë, që të mund të nisni incizimin e një mesazhi zanor + S’niset dot mesazh zanor + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-sv/strings.xml b/library/ui-strings/src/main/res/values-sv/strings.xml index 877a95f2de..caf9913299 100644 --- a/library/ui-strings/src/main/res/values-sv/strings.xml +++ b/library/ui-strings/src/main/res/values-sv/strings.xml @@ -2898,4 +2898,25 @@ Omröstningshistorik Din hemserver har inte stöd för att lista trådar än. Ja, sluta - + Fel vid hämtning av omröstningar. + Laddar fler omröstning + Visar omröstningar + + Det finns inga aktiva omröstningar från förra dagen. +\nLadda fler omröstningar för att se omröstningar från tidigare dagar. + Det finns inga aktiva omröstningar från senaste %1$d dagarna. +\nLadda fler omröstningar för att se omröstningar från tidigare dagar. + + + Det finns inga omröstningar från förra dagen. +\nLadda fler omröstningar för att se omröstningar från tidigare dagar. + Det finns inga omröstningar från senaste %1$d dagarna. +\nLadda fler omröstningar för att se omröstningar från tidigare dagar. + + På grund av avkrypteringsfel så kanske vissa röster inte räknas + Anslutningsfel - Inspelning pausad + Kan inte spela den här röstsändningen. + Du kan inte påbörja ett röstmeddelande eftersom du för närvarande spelar in en röstsändning. Vänligen avsluta din röstsändning för att börja spela in ett röstmeddelande + Kan inte starta röstsändning + Startade en röstsändning + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-uk/strings.xml b/library/ui-strings/src/main/res/values-uk/strings.xml index 0f6027903f..26d38bb324 100644 --- a/library/ui-strings/src/main/res/values-uk/strings.xml +++ b/library/ui-strings/src/main/res/values-uk/strings.xml @@ -3039,4 +3039,5 @@ Ви не можете розпочати запис голосового повідомлення, оскільки ви записуєте трансляцію наживо. Будь ласка, заверште її, щоб розпочати запис голосового повідомлення Не вдалося розпочати запис голосового повідомлення Помилка з\'єднання - Запис призупинено + Застосовувати вбудований формат коду \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml index c650a1e6b2..b3845e550d 100644 --- a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml +++ b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml @@ -2856,4 +2856,8 @@ 過去 %1$d 天沒有活躍的投票。 \n載入更多投票以檢視過去幾天的投票。 - + 連線錯誤 - 錄製已暫停 + 您無法開始語音訊息,因為您目前正在錄製直播。請結束您的直播以開始錄製語音訊息 + 無法開始語音訊息 + 套用內嵌程式碼格式 + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 6a9d3e583d..15ee44bb36 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3513,6 +3513,7 @@ Set link Toggle numbered list Toggle bullet list + Apply inline code format Toggle full screen mode Text diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt index 634e71c43b..127b14e5d5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/summary/RoomSummaryConstants.kt @@ -35,5 +35,6 @@ object RoomSummaryConstants { EventType.REACTION ) + EventType.POLL_START.values + + EventType.POLL_END.values + EventType.STATE_ROOM_BEACON_INFO.values } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt index 38024b7aa8..b5114ec1dd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt @@ -320,7 +320,7 @@ internal class LocalEchoEventFactory @Inject constructor( val permalink = permalinkFactory.createPermalink(roomId, originalEvent.root.eventId ?: "", false) val userLink = originalEvent.root.senderId?.let { permalinkFactory.createPermalink(it, false) } ?: "" - val body = bodyForReply(originalEvent.getLastMessageContent(), originalEvent.isReply()) + val body = bodyForReply(timelineEvent = originalEvent) // As we always supply formatted body for replies we should force the MarkdownParser to produce html. val newBodyFormatted = markdownParser.parse(newBodyText, force = true, advanced = autoMarkdown).takeFormatted() // Body of the original message may not have formatted version, so may also have to convert to html. @@ -613,7 +613,7 @@ internal class LocalEchoEventFactory @Inject constructor( val userId = eventReplied.root.senderId ?: return null val userLink = permalinkFactory.createPermalink(userId, false) ?: return null - val body = bodyForReply(eventReplied.getLastMessageContent(), eventReplied.isReply(), isRedactedEvent) + val body = bodyForReply(timelineEvent = eventReplied, isRedactedEvent = isRedactedEvent) // As we always supply formatted body for replies we should force the MarkdownParser to produce html. val finalReplyTextFormatted = replyTextFormatted?.toString() ?: markdownParser.parse(replyText, force = true, advanced = autoMarkdown).takeFormatted() @@ -725,6 +725,20 @@ internal class LocalEchoEventFactory @Inject constructor( } } + private fun bodyForReply(timelineEvent: TimelineEvent, isRedactedEvent: Boolean = false): TextContent { + val content = when (timelineEvent.root.getClearType()) { + in EventType.POLL_END.values -> { + // for end poll event, we use the content of the start poll event + localEchoRepository + .getRelatedPollEvent(timelineEvent) + ?.getLastMessageContent() + ?: timelineEvent.getLastMessageContent() + } + else -> timelineEvent.getLastMessageContent() + } + return bodyForReply(content = content, isReply = timelineEvent.isReply(), isRedactedEvent = isRedactedEvent) + } + /** * Returns a TextContent used for the fallback event representation in a reply message. * In case of an edit of a reply the last content is not @@ -755,6 +769,7 @@ internal class LocalEchoEventFactory @Inject constructor( MessageType.MSGTYPE_POLL_START -> { return TextContent((content as? MessagePollContent)?.getBestPollCreationInfo()?.question?.getBestQuestion() ?: "") } + MessageType.MSGTYPE_POLL_END -> return TextContent("Ended poll") else -> { return if (isRedactedEvent) { TextContent("message removed.") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt index 394cb8944f..4a5b394144 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt @@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.getRelationContent import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.asyncTransaction import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper @@ -228,4 +229,15 @@ internal class LocalEchoRepository @Inject constructor( EventEntity.where(realm, eventId = rootThreadEventId).findFirst()?.threadSummaryLatestMessage?.eventId } ?: rootThreadEventId } + + fun getRelatedPollEvent(timelineEvent: TimelineEvent): TimelineEvent? { + val roomId = timelineEvent.roomId + val pollEventId = timelineEvent.getRelationContent()?.eventId ?: return null + + return realmSessionProvider.withRealm { realm -> + TimelineEventEntity.where(realm, roomId = roomId, eventId = pollEventId).findFirst()?.let { + timelineEventMapper.map(it) + } + } + } } diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index b4d7ebae1f..d12ace911b 100755 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -176,7 +176,7 @@ PreferenceManager\.getDefaultSharedPreferences==2 R\.string\.template_ ### Use the Clock interface, or use `measureTimeMillis` -System\.currentTimeMillis\(\)===2 +System\.currentTimeMillis\(\)===3 ### Remove extra space between the name and the description \* @\w+ \w+ + diff --git a/vector/build.gradle b/vector/build.gradle index fa11034fea..d5223a1f6a 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -236,7 +236,7 @@ dependencies { kapt libs.dagger.hiltCompiler // Analytics - implementation('com.posthog.android:posthog:2.0.0') { + implementation('com.posthog.android:posthog:2.0.1') { exclude group: 'com.android.support', module: 'support-annotations' } implementation libs.sentry.sentryAndroid @@ -311,7 +311,7 @@ dependencies { // Fix issue with Jitsi. Inspired from https://github.com/android/android-test/issues/861#issuecomment-872067868 // Error was lots of `Duplicate class org.checkerframework.common.reflection.qual.MethodVal found in modules jetified-checker-3.1 (org.checkerframework:checker:3.1.1) and jetified-checker-qual-3.12.0 (org.checkerframework:checker-qual:3.12.0) //noinspection GradleDependency Cannot use latest 3.15.0 since it required min API 26. - implementation "org.checkerframework:checker:3.29.0" + implementation "org.checkerframework:checker:3.30.0" androidTestImplementation libs.androidx.testCore androidTestImplementation libs.androidx.testRunner diff --git a/vector/src/androidTest/java/im/vector/app/core/utils/TestSpan.kt b/vector/src/androidTest/java/im/vector/app/core/utils/TestSpan.kt index e31dc6942c..1d0d6548e1 100644 --- a/vector/src/androidTest/java/im/vector/app/core/utils/TestSpan.kt +++ b/vector/src/androidTest/java/im/vector/app/core/utils/TestSpan.kt @@ -19,9 +19,10 @@ package im.vector.app.core.utils import android.graphics.Canvas import android.graphics.Paint import android.text.Layout -import android.text.Spannable +import android.text.Spanned import androidx.core.text.getSpans import im.vector.app.features.html.HtmlCodeSpan +import io.element.android.wysiwyg.spans.InlineCodeSpan import io.mockk.justRun import io.mockk.mockk import io.mockk.slot @@ -31,9 +32,9 @@ import io.noties.markwon.core.spans.OrderedListItemSpan import io.noties.markwon.core.spans.StrongEmphasisSpan import me.gujun.android.span.style.CustomTypefaceSpan -fun Spannable.toTestSpan(): String { +fun Spanned.toTestSpan(): String { var output = toString() - readSpansWithContent().forEach { + readSpansWithContent().reversed().forEach { val tags = it.span.readTags() val remappedContent = it.span.remapContent(source = this, originalContent = it.content) output = output.replace(it.content, "${tags.open}$remappedContent${tags.close}") @@ -41,7 +42,7 @@ fun Spannable.toTestSpan(): String { return output } -private fun Spannable.readSpansWithContent() = getSpans().map { span -> +private fun Spanned.readSpansWithContent() = getSpans().map { span -> val start = getSpanStart(span) val end = getSpanEnd(span) SpanWithContent( @@ -51,12 +52,24 @@ private fun Spannable.readSpansWithContent() = getSpans().map { span -> }.reversed() private fun Any.readTags(): SpanTags { - return when (this::class) { - OrderedListItemSpan::class -> SpanTags("[list item]", "[/list item]") - HtmlCodeSpan::class -> SpanTags("[code]", "[/code]") - StrongEmphasisSpan::class -> SpanTags("[bold]", "[/bold]") - EmphasisSpan::class, CustomTypefaceSpan::class -> SpanTags("[italic]", "[/italic]") - else -> throw IllegalArgumentException("Unknown ${this::class}") + val tagName = when (this::class) { + OrderedListItemSpan::class -> "list item" + HtmlCodeSpan::class -> + if ((this as HtmlCodeSpan).isBlock) "code block" else "inline code" + StrongEmphasisSpan::class -> "bold" + EmphasisSpan::class, CustomTypefaceSpan::class -> "italic" + InlineCodeSpan::class -> "inline code" + else -> if (this::class.qualifiedName!!.startsWith("android.widget")) { + null + } else { + throw IllegalArgumentException("Unknown ${this::class}") + } + } + + return if (tagName == null) { + SpanTags("", "") + } else { + SpanTags("[$tagName]", "[/$tagName]") } } diff --git a/vector/src/androidTest/java/im/vector/app/features/html/EventHtmlRendererTest.kt b/vector/src/androidTest/java/im/vector/app/features/html/EventHtmlRendererTest.kt index a2e489dd70..7f3293e7d1 100644 --- a/vector/src/androidTest/java/im/vector/app/features/html/EventHtmlRendererTest.kt +++ b/vector/src/androidTest/java/im/vector/app/features/html/EventHtmlRendererTest.kt @@ -16,7 +16,8 @@ package im.vector.app.features.html -import androidx.core.text.toSpannable +import android.widget.TextView +import androidx.core.text.toSpanned import androidx.test.platform.app.InstrumentationRegistry import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.ColorProvider @@ -36,16 +37,19 @@ class EventHtmlRendererTest { private val context = InstrumentationRegistry.getInstrumentation().targetContext private val fakeVectorPreferences = mockk().also { every { it.latexMathsIsEnabled() } returns false + every { it.isRichTextEditorEnabled() } returns false } private val fakeSessionHolder = mockk() private val renderer = EventHtmlRenderer( - MatrixHtmlPluginConfigure(ColorProvider(context), context.resources), + MatrixHtmlPluginConfigure(ColorProvider(context), context.resources, fakeVectorPreferences), context, fakeVectorPreferences, fakeSessionHolder, ) + private val textView: TextView = TextView(context) + @Test fun takesInitialListPositionIntoAccount() { val result = """
  1. first entry
""".renderAsTestSpan() @@ -57,7 +61,7 @@ class EventHtmlRendererTest { fun doesNotProcessMarkdownWithinCodeBlocks() { val result = """__italic__ **bold**""".renderAsTestSpan() - result shouldBeEqualTo "[code]__italic__ **bold**[/code]" + result shouldBeEqualTo "[inline code]__italic__ **bold**[/inline code]" } @Test @@ -71,7 +75,15 @@ class EventHtmlRendererTest { fun processesHtmlWithinCodeBlocks() { val result = """italic bold""".renderAsTestSpan() - result shouldBeEqualTo "[code][italic]italic[/italic] [bold]bold[/bold][/code]" + result shouldBeEqualTo "[inline code][italic]italic[/italic] [bold]bold[/bold][/inline code]" + } + + @Test + fun processesHtmlWithinCodeBlocks_givenRichTextEditorEnabled() { + every { fakeVectorPreferences.isRichTextEditorEnabled() } returns true + val result = """italic bold""".renderAsTestSpan() + + result shouldBeEqualTo "[inline code][italic]italic[/italic] [bold]bold[/bold][/inline code]" } @Test @@ -81,5 +93,9 @@ class EventHtmlRendererTest { result shouldBeEqualTo """& < > ' """" } - private fun String.renderAsTestSpan() = renderer.render(this).toSpannable().toTestSpan() + private fun String.renderAsTestSpan(): String { + textView.text = renderer.render(this).toSpanned() + renderer.plugins.forEach { markwonPlugin -> markwonPlugin.afterSetText(textView) } + return textView.text.toSpanned().toTestSpan() + } } diff --git a/vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt b/vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt index ca7608166c..917c3468c6 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt @@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @@ -60,6 +61,9 @@ class DefaultVectorAnalytics @Inject constructor( private var userConsent: Boolean? = null private var analyticsId: String? = null + // Cache for the properties to send + private var pendingUserProperties: UserProperties? = null + override fun init() { observeUserConsent() observeAnalyticsId() @@ -112,6 +116,7 @@ class DefaultVectorAnalytics @Inject constructor( private suspend fun identifyPostHog() { val id = analyticsId ?: return + if (!userConsent.orFalse()) return if (id.isEmpty()) { Timber.tag(analyticsTag.value).d("reset") posthog?.reset() @@ -126,7 +131,7 @@ class DefaultVectorAnalytics @Inject constructor( .onEach { consent -> Timber.tag(analyticsTag.value).d("User consent updated to $consent") userConsent = consent - optOutPostHog() + initOrStopPostHog() initOrStopSentry() } .launchIn(globalScope) @@ -141,8 +146,22 @@ class DefaultVectorAnalytics @Inject constructor( } } - private fun optOutPostHog() { - userConsent?.let { posthog?.optOut(!it) } + private suspend fun initOrStopPostHog() { + userConsent?.let { _userConsent -> + when (_userConsent) { + true -> { + posthog?.optOut(false) + identifyPostHog() + pendingUserProperties?.let { doUpdateUserProperties(it) } + pendingUserProperties = null + } + false -> { + // When opting out, ensure that the queue is flushed first, or it will be flushed later (after user has revoked consent) + posthog?.flush() + posthog?.optOut(true) + } + } + } } override fun capture(event: VectorAnalyticsEvent) { @@ -160,7 +179,17 @@ class DefaultVectorAnalytics @Inject constructor( } override fun updateUserProperties(userProperties: UserProperties) { - posthog?.identify(REUSE_EXISTING_ID, userProperties.getProperties()?.toPostHogUserProperties(), IGNORED_OPTIONS) + if (userConsent == true) { + doUpdateUserProperties(userProperties) + } else { + pendingUserProperties = userProperties + } + } + + private fun doUpdateUserProperties(userProperties: UserProperties) { + posthog + ?.takeIf { userConsent == true } + ?.identify(REUSE_EXISTING_ID, userProperties.getProperties()?.toPostHogUserProperties(), IGNORED_OPTIONS) } private fun Map?.toPostHogProperties(): Properties? { diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 0bf70690ba..9c65d94a94 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -166,7 +166,7 @@ class WebRtcCall( private var videoSender: RtpSender? = null private var screenSender: RtpSender? = null - private val timer = CountUpTimer(1000L).apply { + private val timer = CountUpTimer(intervalInMs = 1000L).apply { tickListener = CountUpTimer.TickListener { milliseconds -> val formattedDuration = formatDuration(Duration.ofMillis(milliseconds)) listeners.forEach { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt index 900de041d0..1929abcc4f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/AudioMessageHelper.kt @@ -198,7 +198,7 @@ class AudioMessageHelper @Inject constructor( private fun startRecordingAmplitudes() { amplitudeTicker?.stop() - amplitudeTicker = CountUpTimer(50).apply { + amplitudeTicker = CountUpTimer(intervalInMs = 50).apply { tickListener = CountUpTimer.TickListener { onAmplitudeTick() } resume() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt index 1bb82b41fe..2c0d77045e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt @@ -246,6 +246,9 @@ internal class RichTextComposerLayout @JvmOverloads constructor( addRichTextMenuItem(R.drawable.ic_composer_numbered_list, R.string.rich_text_editor_numbered_list, ComposerAction.ORDERED_LIST) { views.richTextComposerEditText.toggleList(ordered = true) } + addRichTextMenuItem(R.drawable.ic_composer_inline_code, R.string.rich_text_editor_inline_code, ComposerAction.INLINE_CODE) { + views.richTextComposerEditText.toggleInlineFormat(InlineFormat.InlineCode) + } } fun setLink(link: String?) = diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 858b0512f5..d56bf18fa8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -220,6 +220,9 @@ class MessageActionsViewModel @AssistedInject constructor( (timelineEvent.getVectorLastMessageContent() as? MessagePollContent)?.getBestPollCreationInfo()?.question?.getBestQuestion() ?: stringProvider.getString(R.string.message_reply_to_poll_preview) } + in EventType.POLL_END.values -> { + stringProvider.getString(R.string.message_reply_to_ended_poll_preview) + } else -> null } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 219ccbe11c..9cb1608415 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -160,6 +160,9 @@ class MessageItemFactory @Inject constructor( textRendererFactory.create(roomId) } + private val useRichTextEditorStyle: Boolean get() = + vectorPreferences.isRichTextEditorEnabled() + fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? { val event = params.event val highlight = params.isHighlighted @@ -480,6 +483,7 @@ class MessageItemFactory @Inject constructor( highlight, callback, attributes, + useRichTextEditorStyle = vectorPreferences.isRichTextEditorEnabled(), ) } @@ -586,7 +590,7 @@ class MessageItemFactory @Inject constructor( val replyToContent = messageContent.relatesTo?.inReplyTo buildFormattedTextItem(matrixFormattedBody, informationData, highlight, callback, attributes, replyToContent) } else { - buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes) + buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes, useRichTextEditorStyle) } } @@ -610,6 +614,7 @@ class MessageItemFactory @Inject constructor( highlight, callback, attributes, + useRichTextEditorStyle, ) } @@ -620,6 +625,7 @@ class MessageItemFactory @Inject constructor( highlight: Boolean, callback: TimelineEventController.Callback?, attributes: AbsMessageItem.Attributes, + useRichTextEditorStyle: Boolean, ): MessageTextItem? { val renderedBody = textRenderer.render(body) val bindingOptions = spanUtils.getBindingOptions(renderedBody) @@ -640,6 +646,7 @@ class MessageItemFactory @Inject constructor( .previewUrlRetriever(callback?.getPreviewUrlRetriever()) .imageContentRenderer(imageContentRenderer) .previewUrlCallback(callback) + .useRichTextEditorStyle(useRichTextEditorStyle) .leftGuideline(avatarSizeProvider.leftGuideline) .attributes(attributes) .highlighted(highlight) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt index 072c3dcd27..a9cd25ae19 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt @@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.item import android.text.Spanned import android.text.method.MovementMethod +import android.view.ViewStub import androidx.appcompat.widget.AppCompatTextView import androidx.core.text.PrecomputedTextCompat import androidx.core.view.isVisible @@ -67,6 +68,9 @@ abstract class MessageTextItem : AbsMessageItem() { @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var markwonPlugins: (List)? = null + @EpoxyAttribute + var useRichTextEditorStyle: Boolean = false + private val previewUrlViewUpdater = PreviewUrlViewUpdater() override fun bind(holder: Holder) { @@ -82,27 +86,28 @@ abstract class MessageTextItem : AbsMessageItem() { holder.previewUrlView.delegate = previewUrlCallback holder.previewUrlView.renderMessageLayout(attributes.informationData.messageLayout) + val messageView: AppCompatTextView = if (useRichTextEditorStyle) holder.richMessageView else holder.plainMessageView if (useBigFont) { - holder.messageView.textSize = 44F + messageView.textSize = 44F } else { - holder.messageView.textSize = 15.5F + messageView.textSize = 15.5F } if (searchForPills) { message?.charSequence?.findPillsAndProcess(coroutineScope) { // mmm.. not sure this is so safe in regards to cell reuse - it.bind(holder.messageView) + it.bind(messageView) } } message?.charSequence.let { charSequence -> - markwonPlugins?.forEach { plugin -> plugin.beforeSetText(holder.messageView, charSequence as Spanned) } + markwonPlugins?.forEach { plugin -> plugin.beforeSetText(messageView, charSequence as Spanned) } } super.bind(holder) - holder.messageView.movementMethod = movementMethod - renderSendState(holder.messageView, holder.messageView) - holder.messageView.onClick(attributes.itemClickListener) - holder.messageView.onLongClickIgnoringLinks(attributes.itemLongClickListener) - holder.messageView.setTextWithEmojiSupport(message?.charSequence, bindingOptions) - markwonPlugins?.forEach { plugin -> plugin.afterSetText(holder.messageView) } + messageView.movementMethod = movementMethod + renderSendState(messageView, messageView) + messageView.onClick(attributes.itemClickListener) + messageView.onLongClickIgnoringLinks(attributes.itemLongClickListener) + messageView.setTextWithEmojiSupport(message?.charSequence, bindingOptions) + markwonPlugins?.forEach { plugin -> plugin.afterSetText(messageView) } } private fun AppCompatTextView.setTextWithEmojiSupport(message: CharSequence?, bindingOptions: BindingOptions?) { @@ -125,8 +130,15 @@ abstract class MessageTextItem : AbsMessageItem() { override fun getViewStubId() = STUB_ID class Holder : AbsMessageItem.Holder(STUB_ID) { - val messageView by bind(R.id.messageTextView) val previewUrlView by bind(R.id.messageUrlPreview) + private val richMessageStub by bind(R.id.richMessageTextViewStub) + private val plainMessageStub by bind(R.id.plainMessageTextViewStub) + val richMessageView: AppCompatTextView by lazy { + richMessageStub.inflate().findViewById(R.id.messageTextView) + } + val plainMessageView: AppCompatTextView by lazy { + plainMessageStub.inflate().findViewById(R.id.messageTextView) + } } inner class PreviewUrlViewUpdater : PreviewUrlRetriever.PreviewUrlRetrieverListener { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCase.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCase.kt index ff814d4cbc..d6e97e0ef9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/render/ProcessBodyOfReplyToEventUseCase.kt @@ -19,12 +19,13 @@ package im.vector.app.features.home.room.detail.timeline.render import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.StringProvider +import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.getPollQuestion +import org.matrix.android.sdk.api.session.events.model.getRelationContent import org.matrix.android.sdk.api.session.events.model.isAudioMessage import org.matrix.android.sdk.api.session.events.model.isFileMessage import org.matrix.android.sdk.api.session.events.model.isImageMessage import org.matrix.android.sdk.api.session.events.model.isLiveLocation -import org.matrix.android.sdk.api.session.events.model.isPoll import org.matrix.android.sdk.api.session.events.model.isPollEnd import org.matrix.android.sdk.api.session.events.model.isPollStart import org.matrix.android.sdk.api.session.events.model.isSticker @@ -32,7 +33,9 @@ import org.matrix.android.sdk.api.session.events.model.isVideoMessage import org.matrix.android.sdk.api.session.events.model.isVoiceMessage import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.getTimelineEvent +import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.relation.ReplyToContent +import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import javax.inject.Inject private const val IN_REPLY_TO = "In reply to" @@ -94,16 +97,22 @@ class ProcessBodyOfReplyToEventUseCase @Inject constructor( stringProvider.getString(R.string.message_reply_to_sender_sent_sticker) ) } - repliedToEvent.isPoll() -> { - val fallbackText = when { - repliedToEvent.isPollStart() -> stringProvider.getString(R.string.message_reply_to_sender_created_poll) - repliedToEvent.isPollEnd() -> stringProvider.getString(R.string.message_reply_to_sender_ended_poll) - else -> "" - } + repliedToEvent.isPollEnd() -> { + val fallbackText = stringProvider.getString(R.string.message_reply_to_sender_ended_poll) + val repliedText = getPollQuestionFromPollEnd(repliedToEvent) matrixFormattedBody.replaceRange( afterBreakingLineIndex, endOfBlockQuoteIndex, - repliedToEvent.getPollQuestion() ?: fallbackText + repliedText ?: fallbackText, + ) + } + repliedToEvent.isPollStart() -> { + val fallbackText = stringProvider.getString(R.string.message_reply_to_sender_created_poll) + val repliedText = repliedToEvent.getPollQuestion() + matrixFormattedBody.replaceRange( + afterBreakingLineIndex, + endOfBlockQuoteIndex, + repliedText ?: fallbackText, ) } repliedToEvent.isLiveLocation() -> { @@ -126,8 +135,25 @@ class ProcessBodyOfReplyToEventUseCase @Inject constructor( } private fun getEvent(eventId: String, roomId: String) = + getTimelineEvent(eventId, roomId) + ?.root + + private fun getTimelineEvent(eventId: String, roomId: String) = activeSessionHolder.getSafeActiveSession() ?.getRoom(roomId) ?.getTimelineEvent(eventId) - ?.root + + private fun getPollQuestionFromPollEnd(event: Event): String? { + val eventId = event.getRelationContent()?.eventId.orEmpty() + val roomId = event.roomId.orEmpty() + return if (eventId.isEmpty() || roomId.isEmpty()) { + null + } else { + (getTimelineEvent(eventId, roomId) + ?.getLastMessageContent() as? MessagePollContent) + ?.getBestPollCreationInfo() + ?.question + ?.getBestQuestion() + } + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCase.kt b/vector/src/main/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCase.kt index 6a50e87562..94f9136a2f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCase.kt @@ -17,6 +17,7 @@ package im.vector.app.features.home.room.list.usecase import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.voicebroadcast.isLive import im.vector.app.features.voicebroadcast.isVoiceBroadcast import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent @@ -35,14 +36,21 @@ import javax.inject.Inject class GetLatestPreviewableEventUseCase @Inject constructor( private val sessionHolder: ActiveSessionHolder, private val getRoomLiveVoiceBroadcastsUseCase: GetRoomLiveVoiceBroadcastsUseCase, + private val vectorPreferences: VectorPreferences, ) { fun execute(roomId: String): TimelineEvent? { val room = sessionHolder.getSafeActiveSession()?.getRoom(roomId) ?: return null val roomSummary = room.roomSummary() ?: return null - return getCallEvent(roomSummary) - ?: getLiveVoiceBroadcastEvent(room) - ?: getDefaultLatestEvent(room, roomSummary) + // FIXME Observing live broadcasts results in many db requests, + // to prevent performances issues, we only enable this mechanism if the voice broadcast flag is enabled + return if (vectorPreferences.isVoiceBroadcastEnabled()) { + getCallEvent(roomSummary) + ?: getLiveVoiceBroadcastEvent(room) + ?: getDefaultLatestEvent(room, roomSummary) + } else { + roomSummary.latestPreviewableEvent + } } private fun getCallEvent(roomSummary: RoomSummary): TimelineEvent? { diff --git a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt index 21fcbffb03..bc9ba0b85a 100644 --- a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt @@ -30,6 +30,8 @@ import android.content.res.Resources import android.graphics.Typeface import android.graphics.drawable.Drawable import android.text.Spannable +import android.text.SpannableStringBuilder +import android.widget.TextView import androidx.core.text.toSpannable import com.bumptech.glide.Glide import com.bumptech.glide.RequestBuilder @@ -38,6 +40,7 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.settings.VectorPreferences +import io.element.android.wysiwyg.spans.InlineCodeSpan import io.noties.markwon.AbstractMarkwonPlugin import io.noties.markwon.Markwon import io.noties.markwon.MarkwonPlugin @@ -64,8 +67,8 @@ import javax.inject.Singleton @Singleton class EventHtmlRenderer @Inject constructor( htmlConfigure: MatrixHtmlPluginConfigure, - context: Context, - vectorPreferences: VectorPreferences, + private val context: Context, + private val vectorPreferences: VectorPreferences, private val activeSessionHolder: ActiveSessionHolder ) { @@ -73,73 +76,121 @@ class EventHtmlRenderer @Inject constructor( fun afterRender(renderedText: Spannable) } - private val builder = Markwon.builder(context) - .usePlugin(HtmlPlugin.create(htmlConfigure)) - .usePlugin(GlideImagesPlugin.create(object : GlideImagesPlugin.GlideStore { - override fun load(drawable: AsyncDrawable): RequestBuilder { - val url = drawable.destination - if (url.isMxcUrl()) { - val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() - val imageUrl = contentUrlResolver.resolveFullSize(url) - // Override size to avoid crashes for huge pictures - return Glide.with(context).load(imageUrl).override(500) - } - // We don't want to support other url schemes here, so just return a request for null - return Glide.with(context).load(null as String?) - } + private val glidePlugin = GlideImagesPlugin.create(object : GlideImagesPlugin.GlideStore { + override fun load(drawable: AsyncDrawable): RequestBuilder { + val url = drawable.destination + if (url.isMxcUrl()) { + val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() + val imageUrl = contentUrlResolver.resolveFullSize(url) + // Override size to avoid crashes for huge pictures + return Glide.with(context).load(imageUrl).override(500) + } + // We don't want to support other url schemes here, so just return a request for null + return Glide.with(context).load(null as String?) + } - override fun cancel(target: Target<*>) { - Glide.with(context).clear(target) - } - })) + override fun cancel(target: Target<*>) { + Glide.with(context).clear(target) + } + }) - private val markwon = if (vectorPreferences.latexMathsIsEnabled()) { - // If latex maths is enabled in app preferences, refomat it so Markwon recognises it - // It needs to be in this specific format: https://noties.io/Markwon/docs/v4/ext-latex - builder - .usePlugin(object : AbstractMarkwonPlugin() { - override fun processMarkdown(markdown: String): String { - return markdown - .replace(Regex(""".*?""")) { matchResult -> - "$$" + matchResult.groupValues[1] + "$$" - } - .replace(Regex(""".*?""")) { matchResult -> - "\n$$\n" + matchResult.groupValues[1] + "\n$$\n" - } - } - }) - .usePlugin(JLatexMathPlugin.create(44F) { builder -> - builder.inlinesEnabled(true) - builder.theme().inlinePadding(JLatexMathTheme.Padding.symmetric(24, 8)) - }) - } else { - builder - } - .usePlugin( - MarkwonInlineParserPlugin.create( - /* Configuring the Markwon inline formatting processor. - * Default settings are all Markdown features. Turn those off, only using the - * inline HTML processor and HTML entities processor. - */ - MarkwonInlineParser.factoryBuilderNoDefaults() - .addInlineProcessor(HtmlInlineProcessor()) // use inline HTML processor - .addInlineProcessor(EntityInlineProcessor()) // use HTML entities processor - ) - ) - .usePlugin(object : AbstractMarkwonPlugin() { - override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) { - builder.setFactory( - Emphasis::class.java - ) { _, _ -> CustomTypefaceSpan(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)) } + private val latexPlugins = listOf( + object : AbstractMarkwonPlugin() { + override fun processMarkdown(markdown: String): String { + return markdown + .replace(Regex(""".*?""")) { matchResult -> + "$$" + matchResult.groupValues[1] + "$$" + } + .replace(Regex(""".*?""")) { matchResult -> + "\n$$\n" + matchResult.groupValues[1] + "\n$$\n" + } } + }, + JLatexMathPlugin.create(44F) { builder -> + builder.inlinesEnabled(true) + builder.theme().inlinePadding(JLatexMathTheme.Padding.symmetric(24, 8)) + } + ) - override fun configureParser(builder: Parser.Builder) { - /* Configuring the Markwon block formatting processor. - * Default settings are all Markdown blocks. Turn those off. + private val markwonInlineParserPlugin = + MarkwonInlineParserPlugin.create( + /* Configuring the Markwon inline formatting processor. + * Default settings are all Markdown features. Turn those off, only using the + * inline HTML processor and HTML entities processor. */ - builder.enabledBlockTypes(kotlin.collections.emptySet()) + MarkwonInlineParser.factoryBuilderNoDefaults() + .addInlineProcessor(HtmlInlineProcessor()) // use inline HTML processor + .addInlineProcessor(EntityInlineProcessor()) // use HTML entities processor + ) + + private val italicPlugin = object : AbstractMarkwonPlugin() { + override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) { + builder.setFactory( + Emphasis::class.java + ) { _, _ -> CustomTypefaceSpan(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)) } + } + + override fun configureParser(builder: Parser.Builder) { + /* Configuring the Markwon block formatting processor. + * Default settings are all Markdown blocks. Turn those off. + */ + builder.enabledBlockTypes(emptySet()) + } + } + + private val cleanUpIntermediateCodePlugin = object : AbstractMarkwonPlugin() { + override fun afterSetText(textView: TextView) { + super.afterSetText(textView) + + // Remove any intermediate spans + val text = textView.text.toSpannable() + text.getSpans(0, text.length, IntermediateCodeSpan::class.java) + .forEach { span -> + text.removeSpan(span) + } + } + } + + /** + * Workaround for https://github.com/noties/Markwon/issues/423 + */ + private val removeLeadingNewlineForInlineCode = object : AbstractMarkwonPlugin() { + override fun afterSetText(textView: TextView) { + super.afterSetText(textView) + + val text = SpannableStringBuilder(textView.text.toSpannable()) + val inlineCodeSpans = text.getSpans(0, textView.length(), InlineCodeSpan::class.java).toList() + val legacyInlineCodeSpans = text.getSpans(0, textView.length(), HtmlCodeSpan::class.java).filter { !it.isBlock } + val spans = inlineCodeSpans + legacyInlineCodeSpans + + if (spans.isEmpty()) return + + spans.forEach { span -> + val start = text.getSpanStart(span) + if (text[start] == '\n') { + text.replace(start, start + 1, "") } - }) + } + + textView.text = text + } + } + + private val markwon = Markwon.builder(context) + .usePlugin(HtmlRootTagPlugin()) + .usePlugin(HtmlPlugin.create(htmlConfigure)) + .usePlugin(removeLeadingNewlineForInlineCode) + .usePlugin(glidePlugin) + .apply { + if (vectorPreferences.latexMathsIsEnabled()) { + // If latex maths is enabled in app preferences, refomat it so Markwon recognises it + // It needs to be in this specific format: https://noties.io/Markwon/docs/v4/ext-latex + latexPlugins.forEach(::usePlugin) + } + } + .usePlugin(markwonInlineParserPlugin) + .usePlugin(italicPlugin) + .usePlugin(cleanUpIntermediateCodePlugin) .textSetter(PrecomputedFutureTextSetterCompat.create()) .build() @@ -185,7 +236,11 @@ class EventHtmlRenderer @Inject constructor( } } -class MatrixHtmlPluginConfigure @Inject constructor(private val colorProvider: ColorProvider, private val resources: Resources) : HtmlPlugin.HtmlConfigure { +class MatrixHtmlPluginConfigure @Inject constructor( + private val colorProvider: ColorProvider, + private val resources: Resources, + private val vectorPreferences: VectorPreferences, +) : HtmlPlugin.HtmlConfigure { override fun configureHtml(plugin: HtmlPlugin) { plugin @@ -193,6 +248,7 @@ class MatrixHtmlPluginConfigure @Inject constructor(private val colorProvider: C .addHandler(FontTagHandler()) .addHandler(ParagraphHandler(DimensionConverter(resources))) .addHandler(MxReplyTagHandler()) + .addHandler(CodePostProcessorTagHandler(vectorPreferences)) .addHandler(CodePreTagHandler()) .addHandler(CodeTagHandler()) .addHandler(SpanHandler(colorProvider)) diff --git a/vector/src/main/java/im/vector/app/features/html/HtmlCodeHandlers.kt b/vector/src/main/java/im/vector/app/features/html/HtmlCodeHandlers.kt index 1010625370..295b74c7a9 100644 --- a/vector/src/main/java/im/vector/app/features/html/HtmlCodeHandlers.kt +++ b/vector/src/main/java/im/vector/app/features/html/HtmlCodeHandlers.kt @@ -16,20 +16,29 @@ package im.vector.app.features.html +import im.vector.app.features.settings.VectorPreferences +import io.element.android.wysiwyg.spans.InlineCodeSpan import io.noties.markwon.MarkwonVisitor import io.noties.markwon.SpannableBuilder +import io.noties.markwon.core.MarkwonTheme import io.noties.markwon.html.HtmlTag import io.noties.markwon.html.MarkwonHtmlRenderer import io.noties.markwon.html.TagHandler -class CodeTagHandler : TagHandler() { +/** + * Span to be added to any found during initial pass. + * The actual code spans can then be added on a second pass using this + * span as a reference. + */ +internal class IntermediateCodeSpan( + var isBlock: Boolean +) + +internal class CodeTagHandler : TagHandler() { override fun handle(visitor: MarkwonVisitor, renderer: MarkwonHtmlRenderer, tag: HtmlTag) { SpannableBuilder.setSpans( - visitor.builder(), - HtmlCodeSpan(visitor.configuration().theme(), false), - tag.start(), - tag.end() + visitor.builder(), IntermediateCodeSpan(isBlock = false), tag.start(), tag.end() ) } @@ -42,15 +51,13 @@ class CodeTagHandler : TagHandler() { * Pre tag are already handled by HtmlPlugin to keep the formatting. * We are only using it to check for
*
tags. */ -class CodePreTagHandler : TagHandler() { +internal class CodePreTagHandler : TagHandler() { override fun handle(visitor: MarkwonVisitor, renderer: MarkwonHtmlRenderer, tag: HtmlTag) { - val htmlCodeSpan = visitor.builder() - .getSpans(tag.start(), tag.end()) - .firstOrNull { - it.what is HtmlCodeSpan - } - if (htmlCodeSpan != null) { - (htmlCodeSpan.what as HtmlCodeSpan).isBlock = true + val codeSpan = visitor.builder().getSpans(tag.start(), tag.end()).firstOrNull { + it.what is IntermediateCodeSpan + } + if (codeSpan != null) { + (codeSpan.what as IntermediateCodeSpan).isBlock = true } } @@ -58,3 +65,42 @@ class CodePreTagHandler : TagHandler() { return listOf("pre") } } + +internal class CodePostProcessorTagHandler( + private val vectorPreferences: VectorPreferences, +) : TagHandler() { + + override fun supportedTags() = listOf(HtmlRootTagPlugin.ROOT_TAG_NAME) + + override fun handle(visitor: MarkwonVisitor, renderer: MarkwonHtmlRenderer, tag: HtmlTag) { + if (tag.attributes()[HtmlRootTagPlugin.ROOT_ATTRIBUTE] == null) { + return + } + + if (tag.isBlock) { + visitChildren(visitor, renderer, tag.asBlock) + } + + // Replace any intermediate code spans with the real formatting spans + visitor.builder() + .getSpans(tag.start(), tag.end()) + .filter { + it.what is IntermediateCodeSpan + }.forEach { code -> + val intermediateCodeSpan = code.what as IntermediateCodeSpan + val theme = visitor.configuration().theme() + val span = intermediateCodeSpan.toFinalCodeSpan(theme) + SpannableBuilder.setSpans( + visitor.builder(), span, code.start, code.end + ) + } + } + + private fun IntermediateCodeSpan.toFinalCodeSpan( + markwonTheme: MarkwonTheme + ): Any = if (vectorPreferences.isRichTextEditorEnabled() && !isBlock) { + InlineCodeSpan() + } else { + HtmlCodeSpan(markwonTheme, isBlock) + } +} diff --git a/vector/src/main/java/im/vector/app/features/html/HtmlRootTagPlugin.kt b/vector/src/main/java/im/vector/app/features/html/HtmlRootTagPlugin.kt new file mode 100644 index 0000000000..59f2cda00b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/html/HtmlRootTagPlugin.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.html + +import io.noties.markwon.AbstractMarkwonPlugin + +/** + * A root node enables post-processing of optionally nested tags. + * See: [im.vector.app.features.html.CodePostProcessorTagHandler] + */ +internal class HtmlRootTagPlugin : AbstractMarkwonPlugin() { + companion object { + const val ROOT_ATTRIBUTE = "data-root" + const val ROOT_TAG_NAME = "div" + } + override fun processMarkdown(html: String): String { + return "<$ROOT_TAG_NAME $ROOT_ATTRIBUTE>$html" + } +} diff --git a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationUserItem.kt b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationUserItem.kt index c108e83e76..724b2c9b6f 100644 --- a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationUserItem.kt +++ b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationUserItem.kt @@ -105,7 +105,7 @@ abstract class LiveLocationUserItem : VectorEpoxyModel(R.id.itemUserAvatarImageView) val itemUserDisplayNameTextView by bind(R.id.itemUserDisplayNameTextView) val itemRemainingTimeTextView by bind(R.id.itemRemainingTimeTextView) diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt index 2559f1a7d6..bc07e174d3 100644 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt @@ -206,7 +206,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor( } } State.Buffering -> { - val savedPosition = currentVoiceBroadcast?.voiceBroadcastId?.let { playbackTracker.getPlaybackTime(it) } + val savedPosition = currentVoiceBroadcast?.let { playbackTracker.getPlaybackTime(it.voiceBroadcastId) } when { // resume playback from the next sequence item playlist.currentSequence != null -> playlist.getNextItem()?.let { startPlayback(it.startTime) } @@ -223,24 +223,42 @@ class VoiceBroadcastPlayerImpl @Inject constructor( } } - private fun startPlayback(position: Int) { + private fun startPlayback(playbackPosition: Int) { stopPlayer() + playingState = State.Buffering + + val playlistItem = playlist.findByPosition(playbackPosition) ?: run { + Timber.w("## Voice Broadcast | No content to play at position $playbackPosition"); stop(); return + } + val sequence = playlistItem.sequence ?: run { + Timber.w("## Voice Broadcast | Playlist item has no sequence"); stop(); return + } + + currentVoiceBroadcast?.let { + val percentage = tryOrNull { playbackPosition.toFloat() / playlist.duration } ?: 0f + playbackTracker.updatePausedAtPlaybackTime(it.voiceBroadcastId, playbackPosition, percentage) + } - val playlistItem = playlist.findByPosition(position) - val content = playlistItem?.audioEvent?.content ?: run { Timber.w("## Voice Broadcast | No content to play at position $position"); return } - val sequence = playlistItem.sequence ?: run { Timber.w("## Voice Broadcast | Playlist item has no sequence"); return } - val sequencePosition = position - playlistItem.startTime prepareCurrentPlayerJob = sessionScope.launch { try { - val mp = prepareMediaPlayer(content) + val mp = prepareMediaPlayer(playlistItem.audioEvent.content) + + // Take the difference between the duration given from the media player and the duration given from the chunk event + // If the offset is smaller than 500ms, we consider there is no offset to keep the normal behaviour + val offset = (mp.duration - playlistItem.duration).takeUnless { it < 500 }?.coerceAtLeast(0) ?: 0 + val sequencePosition = offset + (playbackPosition - playlistItem.startTime) + playlist.currentSequence = sequence - 1 // will be incremented in onNextMediaPlayerStarted mp.start() if (sequencePosition > 0) { mp.seekTo(sequencePosition) } + onNextMediaPlayerStarted(mp) } catch (failure: VoiceBroadcastFailure.ListeningError) { - playingState = State.Error(failure) + if (failure.cause !is CancellationException) { + playingState = State.Error(failure) + } } } } @@ -259,7 +277,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor( playingState = State.Playing currentMediaPlayer?.start() } else { - val savedPosition = currentVoiceBroadcast?.voiceBroadcastId?.let { playbackTracker.getPlaybackTime(it) } ?: 0 + val savedPosition = currentVoiceBroadcast?.let { playbackTracker.getPlaybackTime(it.voiceBroadcastId) } ?: 0 startPlayback(savedPosition) } } @@ -301,7 +319,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor( } catch (failure: VoiceBroadcastFailure.ListeningError) { // Do not change the playingState if the current player is still valid, // the error will be thrown again when switching to the next player - if (playingState == State.Buffering || tryOrNull { currentMediaPlayer?.isPlaying } != true) { + if (failure.cause !is CancellationException && (playingState == State.Buffering || tryOrNull { currentMediaPlayer?.isPlaying } != true)) { playingState = State.Error(failure) } } @@ -355,6 +373,8 @@ class VoiceBroadcastPlayerImpl @Inject constructor( private fun stopPlayer() { tryOrNull { currentMediaPlayer?.stop() } + playbackTicker.stopPlaybackTicker() + currentMediaPlayer?.release() currentMediaPlayer = null @@ -376,7 +396,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor( State.Paused, State.Buffering, is State.Error, - State.Idle -> playbackTicker.stopPlaybackTicker(voiceBroadcastId) + State.Idle -> playbackTicker.stopPlaybackTicker() } // Notify playback tracker about error @@ -416,22 +436,6 @@ class VoiceBroadcastPlayerImpl @Inject constructor( prepareNextMediaPlayer() } - private fun getCurrentPlaybackPosition(): Int? { - val voiceBroadcastId = currentVoiceBroadcast?.voiceBroadcastId ?: return null - val computedPosition = tryOrNull { currentMediaPlayer?.currentPosition }?.let { playlist.currentItem?.startTime?.plus(it) } - val savedPosition = playbackTracker.getPlaybackTime(voiceBroadcastId) - return computedPosition ?: savedPosition - } - - private fun getCurrentPlaybackPercentage(): Float? { - val playlistPosition = playlist.currentItem?.startTime - val computedPosition = tryOrNull { currentMediaPlayer?.currentPosition }?.let { playlistPosition?.plus(it) } ?: playlistPosition - val duration = playlist.duration - val computedPercentage = if (computedPosition != null && duration > 0) computedPosition.toFloat() / duration else null - val savedPercentage = currentVoiceBroadcast?.voiceBroadcastId?.let { playbackTracker.getPercentage(it) } - return computedPercentage ?: savedPercentage - } - private inner class MediaPlayerListener : MediaPlayer.OnInfoListener, MediaPlayer.OnCompletionListener, @@ -488,40 +492,41 @@ class VoiceBroadcastPlayerImpl @Inject constructor( fun startPlaybackTicker(id: String) { playbackTicker?.stop() - playbackTicker = CountUpTimer(50L).apply { - tickListener = CountUpTimer.TickListener { onPlaybackTick(id) } + playbackTicker = CountUpTimer( + initialTime = playbackTracker.getPlaybackTime(id)?.toLong() ?: 0L, + intervalInMs = 50L + ).apply { + tickListener = CountUpTimer.TickListener { onPlaybackTick(id, it.toInt()) } resume() } - onPlaybackTick(id) } - fun stopPlaybackTicker(id: String) { + fun stopPlaybackTicker() { playbackTicker?.stop() + playbackTicker?.tickListener = null playbackTicker = null - onPlaybackTick(id) } - private fun onPlaybackTick(id: String) { - val playbackTime = getCurrentPlaybackPosition() - val percentage = getCurrentPlaybackPercentage() + private fun onPlaybackTick(id: String, position: Int) { + val percentage = tryOrNull { position.toFloat() / playlist.duration } when (playingState) { State.Playing -> { - if (playbackTime != null && percentage != null) { - playbackTracker.updatePlayingAtPlaybackTime(id, playbackTime, percentage) + if (percentage != null) { + playbackTracker.updatePlayingAtPlaybackTime(id, position, percentage) } } State.Paused, State.Buffering -> { - if (playbackTime != null && percentage != null) { - playbackTracker.updatePausedAtPlaybackTime(id, playbackTime, percentage) + if (percentage != null) { + playbackTracker.updatePausedAtPlaybackTime(id, position, percentage) } } State.Idle -> { - // restart the playback time if player completed with less than 250 ms remaining time - if (playbackTime == null || percentage == null || (playlist.duration - playbackTime) < 250) { + // restart the playback time if player completed with less than 1s remaining time + if (percentage == null || (playlist.duration - position) < 1000) { playbackTracker.stopPlayback(id) } else { - playbackTracker.updatePausedAtPlaybackTime(id, playbackTime, percentage) + playbackTracker.updatePausedAtPlaybackTime(id, position, percentage) } } is State.Error -> Unit diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlaylist.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlaylist.kt index 36b737f23f..437b216d77 100644 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlaylist.kt +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlaylist.kt @@ -65,6 +65,6 @@ class VoiceBroadcastPlaylist( } data class PlaylistItem(val audioEvent: MessageAudioEvent, val startTime: Int) { - val sequence: Int? - get() = audioEvent.sequence + val sequence: Int? = audioEvent.sequence + val duration: Int = audioEvent.duration } diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/usecase/GetLiveVoiceBroadcastChunksUseCase.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/usecase/GetLiveVoiceBroadcastChunksUseCase.kt index b2aebd9932..6f7444849a 100644 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/usecase/GetLiveVoiceBroadcastChunksUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/usecase/GetLiveVoiceBroadcastChunksUseCase.kt @@ -24,17 +24,15 @@ import im.vector.app.features.voicebroadcast.model.VoiceBroadcastEvent import im.vector.app.features.voicebroadcast.model.VoiceBroadcastState import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent import im.vector.app.features.voicebroadcast.sequence -import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastStateEventLiveUseCase +import im.vector.app.features.voicebroadcast.usecase.GetVoiceBroadcastStateEventUseCase import im.vector.app.features.voicebroadcast.voiceBroadcastId import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.emptyFlow -import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.runningReduce -import kotlinx.coroutines.runBlocking import org.matrix.android.sdk.api.session.events.model.RelationType import org.matrix.android.sdk.api.session.room.model.message.MessageAudioEvent import org.matrix.android.sdk.api.session.room.model.message.asMessageAudioEvent @@ -48,7 +46,7 @@ import javax.inject.Inject */ class GetLiveVoiceBroadcastChunksUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, - private val getVoiceBroadcastEventUseCase: GetVoiceBroadcastStateEventLiveUseCase, + private val getVoiceBroadcastEventUseCase: GetVoiceBroadcastStateEventUseCase, ) { fun execute(voiceBroadcast: VoiceBroadcast): Flow> { @@ -60,7 +58,7 @@ class GetLiveVoiceBroadcastChunksUseCase @Inject constructor( val existingChunks = room.timelineService().getTimelineEventsRelatedTo(RelationType.REFERENCE, voiceBroadcast.voiceBroadcastId) .mapNotNull { timelineEvent -> timelineEvent.root.asMessageAudioEvent().takeIf { it.isVoiceBroadcast() } } - val voiceBroadcastEvent = runBlocking { getVoiceBroadcastEventUseCase.execute(voiceBroadcast).firstOrNull()?.getOrNull() } + val voiceBroadcastEvent = getVoiceBroadcastEventUseCase.execute(voiceBroadcast) val voiceBroadcastState = voiceBroadcastEvent?.content?.voiceBroadcastState return if (voiceBroadcastState == null || voiceBroadcastState == VoiceBroadcastState.STOPPED) { diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/model/MessageVoiceBroadcastInfoContent.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/model/MessageVoiceBroadcastInfoContent.kt index d882d4049e..333e211772 100644 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/model/MessageVoiceBroadcastInfoContent.kt +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/model/MessageVoiceBroadcastInfoContent.kt @@ -23,7 +23,6 @@ import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageType.MSGTYPE_VOICE_BROADCAST_INFO import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent -import timber.log.Timber /** * Content of the state event of type [VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO]. @@ -50,8 +49,4 @@ data class MessageVoiceBroadcastInfoContent( val voiceBroadcastState: VoiceBroadcastState? = VoiceBroadcastState.values() .find { it.value == voiceBroadcastStateStr } - ?: run { - Timber.w("Invalid value for state: `$voiceBroadcastStateStr`") - null - } } diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/recording/VoiceBroadcastRecorderQ.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/recording/VoiceBroadcastRecorderQ.kt index 7ca6ab3c9c..5af3b2f05b 100644 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/recording/VoiceBroadcastRecorderQ.kt +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/recording/VoiceBroadcastRecorderQ.kt @@ -248,30 +248,20 @@ class VoiceBroadcastRecorderQ( recordingTicker = CountUpTimer().apply { tickListener = CountUpTimer.TickListener { onTick(elapsedTime()) } resume() - onTick(elapsedTime()) } } fun pause() { - recordingTicker?.apply { - pause() - onTick(elapsedTime()) - } + recordingTicker?.pause() } fun resume() { - recordingTicker?.apply { - resume() - onTick(elapsedTime()) - } + recordingTicker?.resume() } fun stop() { - recordingTicker?.apply { - stop() - onTick(elapsedTime()) - recordingTicker = null - } + recordingTicker?.stop() + recordingTicker = null } private fun onTick(elapsedTimeMillis: Long) { diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/usecase/GetVoiceBroadcastStateEventUseCase.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/usecase/GetVoiceBroadcastStateEventUseCase.kt index e821e09119..d1b1c21b57 100644 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/usecase/GetVoiceBroadcastStateEventUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/usecase/GetVoiceBroadcastStateEventUseCase.kt @@ -49,14 +49,15 @@ class GetVoiceBroadcastStateEventUseCase @Inject constructor( * Get the most recent event related to the given voice broadcast. */ private fun getMostRecentRelatedEvent(room: Room, voiceBroadcast: VoiceBroadcast): VoiceBroadcastEvent? { - val startedEvent = room.getTimelineEvent(voiceBroadcast.voiceBroadcastId) - return if (startedEvent?.root?.isRedacted().orTrue()) { + val startedEvent = room.getTimelineEvent(voiceBroadcast.voiceBroadcastId)?.root + return if (startedEvent?.isRedacted().orTrue()) { null } else { room.timelineService().getTimelineEventsRelatedTo(RelationType.REFERENCE, voiceBroadcast.voiceBroadcastId) .mapNotNull { timelineEvent -> timelineEvent.root.asVoiceBroadcastEvent() } .filterNot { it.root.isRedacted() } .maxByOrNull { it.root.originServerTs ?: 0 } + ?: startedEvent?.asVoiceBroadcastEvent() } } } diff --git a/vector/src/main/res/drawable/ic_composer_inline_code.xml b/vector/src/main/res/drawable/ic_composer_inline_code.xml new file mode 100644 index 0000000000..1743b757af --- /dev/null +++ b/vector/src/main/res/drawable/ic_composer_inline_code.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/vector/src/main/res/layout/item_timeline_event_text_message_plain_stub.xml b/vector/src/main/res/layout/item_timeline_event_text_message_plain_stub.xml new file mode 100644 index 0000000000..1d94632686 --- /dev/null +++ b/vector/src/main/res/layout/item_timeline_event_text_message_plain_stub.xml @@ -0,0 +1,11 @@ + + + diff --git a/vector/src/main/res/layout/item_timeline_event_text_message_rich_stub.xml b/vector/src/main/res/layout/item_timeline_event_text_message_rich_stub.xml new file mode 100644 index 0000000000..bedff8bd4a --- /dev/null +++ b/vector/src/main/res/layout/item_timeline_event_text_message_rich_stub.xml @@ -0,0 +1,11 @@ + + + diff --git a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml index 5c5280ad4e..32785a41af 100644 --- a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml @@ -7,14 +7,17 @@ android:orientation="vertical" tools:viewBindingIgnore="true"> - + android:layout="@layout/item_timeline_event_text_message_plain_stub" /> + + () + val eventId = "event-id" + every { event.eventId } returns eventId + every { event.roomId } returns A_ROOM_ID timelineEvent?.let { every { it.root } returns event } fakeActiveSessionHolder .fakeSession .roomService() .getRoom(A_ROOM_ID) .timelineService() - .givenTimelineEvent(timelineEvent) + .givenTimelineEventReturns(eventId, timelineEvent) return event } @@ -259,7 +279,8 @@ class ProcessBodyOfReplyToEventUseCaseTest { isImageMessage: Boolean = false, isVideoMessage: Boolean = false, isStickerMessage: Boolean = false, - isPollMessage: Boolean = false, + isPollEndMessage: Boolean = false, + isPollStartMessage: Boolean = false, isLiveLocationMessage: Boolean = false, ) { every { fakeRepliedEvent.isFileMessage() } returns isFileMessage @@ -268,7 +289,8 @@ class ProcessBodyOfReplyToEventUseCaseTest { every { fakeRepliedEvent.isImageMessage() } returns isImageMessage every { fakeRepliedEvent.isVideoMessage() } returns isVideoMessage every { fakeRepliedEvent.isSticker() } returns isStickerMessage - every { fakeRepliedEvent.isPoll() } returns isPollMessage + every { fakeRepliedEvent.isPollEnd() } returns isPollEndMessage + every { fakeRepliedEvent.isPollStart() } returns isPollStartMessage every { fakeRepliedEvent.isLiveLocation() } returns isLiveLocationMessage } @@ -276,7 +298,27 @@ class ProcessBodyOfReplyToEventUseCaseTest { fakeStringProvider.given(R.string.message_reply_to_prefix, A_NEW_PREFIX) } - private fun givenNewContentForId(@StringRes resId: Int) { - fakeStringProvider.given(resId, A_NEW_CONTENT) + private fun givenContentForId(@StringRes resId: Int, content: String) { + fakeStringProvider.given(resId, content) + } + + private fun givenPollQuestionReturns(pollEndEvent: Event, question: String?) { + val eventId = "start-event-id" + val relationContent = mockk() + every { relationContent.eventId } returns eventId + every { pollEndEvent.getRelationContent() } returns relationContent + val timelineEvent = mockk() + val messagePollContent = MessagePollContent( + pollCreationInfo = PollCreationInfo( + question = PollQuestion(unstableQuestion = question) + ) + ) + every { timelineEvent.getLastMessageContent() } returns messagePollContent + fakeActiveSessionHolder + .fakeSession + .roomService() + .getRoom(A_ROOM_ID) + .timelineService() + .givenTimelineEventReturns(eventId, timelineEvent) } } diff --git a/vector/src/test/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCaseTest.kt index 5d526c783b..f7dd5da30e 100644 --- a/vector/src/test/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/home/room/list/usecase/GetLatestPreviewableEventUseCaseTest.kt @@ -23,6 +23,7 @@ import im.vector.app.features.voicebroadcast.model.asVoiceBroadcastEvent import im.vector.app.features.voicebroadcast.usecase.GetRoomLiveVoiceBroadcastsUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeRoom +import im.vector.app.test.fakes.FakeVectorPreferences import io.mockk.every import io.mockk.mockk import org.amshove.kluent.shouldBe @@ -46,10 +47,12 @@ internal class GetLatestPreviewableEventUseCaseTest { private val fakeSessionHolder = FakeActiveSessionHolder() private val fakeRoomSummary = mockk() private val fakeGetRoomLiveVoiceBroadcastsUseCase = mockk() + private val fakeVectorPreferences = FakeVectorPreferences() private val getLatestPreviewableEventUseCase = GetLatestPreviewableEventUseCase( fakeSessionHolder.instance, fakeGetRoomLiveVoiceBroadcastsUseCase, + fakeVectorPreferences.instance, ) @Before @@ -62,6 +65,7 @@ internal class GetLatestPreviewableEventUseCaseTest { every { eventId } returns firstArg() } } + fakeVectorPreferences.givenIsVoiceBroadcastEnabled(true) } @Test diff --git a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt index 491834db5b..1979f7872c 100644 --- a/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/poll/create/CreatePollViewModelTest.kt @@ -68,7 +68,7 @@ class CreatePollViewModelTest { .roomService() .getRoom(A_FAKE_ROOM_ID) .timelineService() - .givenTimelineEvent(A_POLL_START_TIMELINE_EVENT) + .givenTimelineEventReturns(A_POLL_START_TIMELINE_EVENT.eventId, A_POLL_START_TIMELINE_EVENT) } @After diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt index a5fac5f1a1..e6a6214c90 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeTimelineService.kt @@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService class FakeTimelineService : TimelineService by mockk() { - fun givenTimelineEvent(event: TimelineEvent?) { - every { getTimelineEvent(any()) } returns event + fun givenTimelineEventReturns(eventId: String, event: TimelineEvent?) { + every { getTimelineEvent(eventId) } returns event } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt index 3d3f415778..7a5831ffed 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt @@ -85,4 +85,8 @@ class FakeVectorPreferences { fun verifySetIpAddressVisibilityInDeviceManagerScreens(isVisible: Boolean) { verify { instance.setIpAddressVisibilityInDeviceManagerScreens(isVisible) } } + + fun givenIsVoiceBroadcastEnabled(isEnabled: Boolean) { + every { instance.isVoiceBroadcastEnabled() } returns isEnabled + } }