Merge branch 'release/v2.2.0'

* release/v2.2.0: (774 commits)
  Minor change in build settings
  Hide lottie animation when user logs out
  Added missing english translation
  Hide navigation bar on launch screen
  MESSENGER-4073 fix version of html formatter package
  fixed merge issues
  Changes in new features and build settings
  Updated element version to 1.9.14
  MESSENGER-4078 permalinks only in open rooms, better texts and icons
  Scan verification screen shows again the old icon instead of the activity indicator
  MESSENGER-4032 disable thread options
  MESSENGER-3418 text changes chrosssigning
  Enable cross signing
  Bugfixes
  MESSENGER-4030 and MESSENGER-4031 creation of multiple dms with one user...
  Added two missing translations in alerts
  Replaced icon with activity indicator
  Changed text
  MESSENGER-4008 add clickable copyright to staticlocationview
  MESSENGER-3977 disable Threadpopup if threads are disabled
  ...
This commit is contained in:
Arnfried Griesert
2023-01-24 09:06:44 +01:00
276 changed files with 5775 additions and 2867 deletions
+3 -6
View File
@@ -4,7 +4,6 @@ on:
# Triggers the workflow on any pull request
pull_request:
types: [ labeled, synchronized, opened, reopened ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@@ -90,11 +89,9 @@ jobs:
- name: Build Ad-hoc release and send it to Diawi
run: bundle exec fastlane alpha
env:
# Automatically bypass 2FA upgrade if possible on Apple account.
SPACESHIP_SKIP_2FA_UPGRADE: true
APPLE_ID: ${{ secrets.FASTLANE_USER }}
FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
APPSTORECONNECT_KEY_ID: ${{ secrets.APPSTORECONNECT_KEY_ID }}
APPSTORECONNECT_KEY_ISSUER_ID: ${{ secrets.APPSTORECONNECT_KEY_ISSUER_ID }}
APPSTORECONNECT_KEY_CONTENT: ${{ secrets.APPSTORECONNECT_KEY_CONTENT }}
DIAWI_API_TOKEN: ${{ secrets.DIAWI_API_TOKEN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
+21 -21
View File
@@ -59,8 +59,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -68,7 +68,7 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc0sUA"
PROJECT_ID: "PVT_kwDOAM0swc0sUA"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
add_product_issues_to_project:
@@ -83,8 +83,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -92,7 +92,7 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc4AAg6N"
PROJECT_ID: "PVT_kwDOAM0swc4AAg6N"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
Delight_issues_to_board:
@@ -107,8 +107,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -116,7 +116,7 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc1HvQ"
PROJECT_ID: "PVT_kwDOAM0swc1HvQ"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_voice-message_issues:
@@ -130,8 +130,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -139,7 +139,7 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc2KCw"
PROJECT_ID: "PVT_kwDOAM0swc2KCw"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_message_bubble_issues:
name: A-Message-Bubbles to Message bubble board
@@ -152,8 +152,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -161,7 +161,7 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc3m-g"
PROJECT_ID: "PVT_kwDOAM0swc3m-g"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_FTUE_issues:
@@ -175,8 +175,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -184,7 +184,7 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc4AAqVx"
PROJECT_ID: "PVT_kwDOAM0swc4AAqVx"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_WTF_issues:
@@ -198,8 +198,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -207,7 +207,7 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc4AArk0"
PROJECT_ID: "PVT_kwDOAM0swc4AArk0"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
ps_features1:
+7 -7
View File
@@ -58,8 +58,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!, $contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -67,12 +67,12 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.pull_request.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc0sUA"
PROJECT_ID: "PVT_kwDOAM0swc0sUA"
TEAM: "design"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
add_product_pr_to_project:
name: Move PRs asking for design review to the design board
name: Move PRs asking for product review to the product board
runs-on: ubuntu-latest
steps:
- uses: octokit/graphql-action@v2.x
@@ -125,8 +125,8 @@ jobs:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!, $contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
item {
id
}
}
@@ -134,6 +134,6 @@ jobs:
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.pull_request.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc4AAg6N"
PROJECT_ID: "PVT_kwDOAM0swc4AAg6N"
TEAM: "product"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
+207
View File
@@ -1,3 +1,210 @@
## Changes in 1.9.14 (2022-12-13)
🙌 Improvements
- Add badge for messages in spaces button. ([#7088](https://github.com/vector-im/element-ios/pull/7088))
- Session: Do not retry initial sync on fatal errors ([#7115](https://github.com/vector-im/element-ios/pull/7115))
- Labs: VoiceBroadcast: Be able to pause the playback when it is buffering ([#7125](https://github.com/vector-im/element-ios/pull/7125))
- Rich Text Editor: Design Improvements. ([#7127](https://github.com/vector-im/element-ios/pull/7127))
- Add localization for authentication errors. ([#7131](https://github.com/vector-im/element-ios/pull/7131))
- Labs: VoiceBroadcast: Prompt the user before ending a voice broadcast ([#7132](https://github.com/vector-im/element-ios/pull/7132))
- Update unverifiable sessions copies in the Device Manager. ([#7138](https://github.com/vector-im/element-ios/pull/7138))
- Refine badge for messages logic on spaces button. ([#7140](https://github.com/vector-im/element-ios/pull/7140))
- Add message id for to-device events ([#7141](https://github.com/vector-im/element-ios/pull/7141))
- Upgrade MatrixSDK version ([v0.24.6](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.6)).
- Turn on Threads for all users ([#7156](https://github.com/vector-im/element-ios/issues/7156))
🐛 Bugfixes
- Labs: VoiceBroadcast: Remove the voice broadcast chunks from the attachments list ([#7133](https://github.com/vector-im/element-ios/pull/7133))
- Labs: VoiceBroadcast: Add the last sequence number in the paused/stopped state event ([#7136](https://github.com/vector-im/element-ios/pull/7136))
- Fix E2EE set up failure whilst signing in using QR code ([#7142](https://github.com/vector-im/element-ios/pull/7142))
- Rich Text Editor: Fixed a bug that prevented fullscreen mode to work on iOS 15. ([#7118](https://github.com/vector-im/element-ios/issues/7118))
- Rich Text Editor: Fixed a bug that did not resize the composer after a change of orientation. ([#7124](https://github.com/vector-im/element-ios/issues/7124))
- Rich Text Composer: Fix for fullscreen mode breaking sometimes when opening it when keyboard is not showing. ([#7130](https://github.com/vector-im/element-ios/issues/7130))
- Threads: Use cross-platform consistent naming for threads in labs ([#7147](https://github.com/vector-im/element-ios/issues/7147))
- Threads: Thread preview doesn't update in main timeline ([#7151](https://github.com/vector-im/element-ios/issues/7151))
🧱 Build
- Update Ruby gems. ([#7148](https://github.com/vector-im/element-ios/pull/7148))
## Changes in 1.9.13 (2022-11-29)
✨ Features
- Add the left time in the Voice Broadcast tile recorder. ([#7103](https://github.com/vector-im/element-ios/pull/7103))
🙌 Improvements
- CryptoV2: Import progress for room keys ([#7078](https://github.com/vector-im/element-ios/pull/7078))
- Add support in the new Device Manager to sessions without crypto support. ([#7083](https://github.com/vector-im/element-ios/pull/7083))
- Loading: Display sync progress on the loading screen ([#7101](https://github.com/vector-im/element-ios/pull/7101))
- Refactor bottom sheet presentation in the device manager. ([#7107](https://github.com/vector-im/element-ios/pull/7107))
- Upgrade MatrixSDK version ([v0.24.5](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.5)).
- Rich Text Composer: Fullscreen mode now is matching the design requirements. ([#7058](https://github.com/vector-im/element-ios/issues/7058))
- Rich Text Editor: on iPhones when in landscape mode the fullscreen mode is disabled. ([#7096](https://github.com/vector-im/element-ios/issues/7096))
🐛 Bugfixes
- Fix scroll issues with VoiceBroadcast and Poll cells ([#7105](https://github.com/vector-im/element-ios/pull/7105))
- VoiceBroadcast: Display the playback duration in the default state ([#7110](https://github.com/vector-im/element-ios/pull/7110))
- Polls: mitigate flickering on vote. ([#5329](https://github.com/vector-im/element-ios/issues/5329))
- Labs: Rich text editor: Fix smart punctuation (e.g. double space transforms into dot) ([#6930](https://github.com/vector-im/element-ios/issues/6930))
- Labs: Rich text editor: Fix input for keyboards that use symbols composition and replacement (e.g. Japanese Romaji, Korean) ([#6983](https://github.com/vector-im/element-ios/issues/6983))
- Labs: Rich text editor: Fix keyboard suggestions for non-latin keyboards (e.g. Chinese Pinyin) ([#7042](https://github.com/vector-im/element-ios/issues/7042))
- Voice Messages: Fix crash when voice message finishes playing. ([#7074](https://github.com/vector-im/element-ios/issues/7074))
- Rich Text Composer: Bottom Sheet is sized to always show all the elements inside, and in case it reaches the top, is also scrollable. ([#7082](https://github.com/vector-im/element-ios/issues/7082))
- Labs: Rich text editor: Fix broken backspace around some type of whitespaces ([#7086](https://github.com/vector-im/element-ios/issues/7086))
- Support voice broadcast live playback ([#7094](https://github.com/vector-im/element-ios/issues/7094))
- Rich Text Editor: Fixed a bug that prevented the drag gesture to dismiss the fullscreen mode when there is a lot of text. ([#7116](https://github.com/vector-im/element-ios/issues/7116))
🚧 In development 🚧
- Labs: VoiceBroadcast - Add the Voice Broadcast option in the room functionalities ([#6721](https://github.com/vector-im/element-ios/issues/6721))
## Changes in 1.9.12 (2022-11-15)
✨ Features
- Threads: added support to read receipts (MSC3771) ([#6663](https://github.com/vector-im/element-ios/issues/6663))
- Threads: added support to notifications count (MSC3773) ([#6664](https://github.com/vector-im/element-ios/issues/6664))
- Threads: added support to labs flag for read receipts ([#7029](https://github.com/vector-im/element-ios/issues/7029))
- Threads: notification count in main timeline including un participated threads ([#7038](https://github.com/vector-im/element-ios/issues/7038))
- Unverified sessions alert. ([#7056](https://github.com/vector-im/element-ios/issues/7056))
- Labs: Rich-text editor: enable translations between Markdown and HTML when toggling text formatting ([#7061](https://github.com/vector-im/element-ios/issues/7061))
🙌 Improvements
- Add informational sheets for user's session states. ([#6992](https://github.com/vector-im/element-ios/pull/6992))
- Add the sign out option in the menu in the session overview. ([#7001](https://github.com/vector-im/element-ios/pull/7001))
- Add show/hide sessions' ip address in the new session manager. ([#7028](https://github.com/vector-im/element-ios/pull/7028))
- Updated GBDeviceInfo pod. ([#7051](https://github.com/vector-im/element-ios/pull/7051))
- Improve device manager code coverage. ([#7065](https://github.com/vector-im/element-ios/pull/7065))
- Initial sync: Remove 10s wait on failed initial sync ([#7068](https://github.com/vector-im/element-ios/pull/7068))
- Labs: Rich text-editor - Add support for plain text mode ([#6980](https://github.com/vector-im/element-ios/issues/6980))
🐛 Bugfixes
- Prevent autolayout crashes when showing toast notifications ([#7046](https://github.com/vector-im/element-ios/pull/7046))
- Fixed timeline layout issues for reactions and attachments ([#7064](https://github.com/vector-im/element-ios/pull/7064))
- Rich Text Composer: Voice Dictation is supported (only plain text can be dictated). ([#6945](https://github.com/vector-im/element-ios/issues/6945))
- Rich Text Composer dismisses the keyboard when sending custom iOS emojis as images, like the normal composer. ([#6946](https://github.com/vector-im/element-ios/issues/6946))
- Fixed IRC-style message and commands support in Rich text editor ([#6962](https://github.com/vector-im/element-ios/issues/6962))
- Fixed the missing keystrokes issue on the Rich Text Editor ([#7005](https://github.com/vector-im/element-ios/issues/7005))
- Fixed the long press deleting issue skipping some text on the Rich Text Editor ([#7006](https://github.com/vector-im/element-ios/issues/7006))
- Hide push toggles for http pushers when there is no server support. ([#7022](https://github.com/vector-im/element-ios/issues/7022))
- Synchronise composer and toolbar resizing animation duration for smoother height updates. ([#7025](https://github.com/vector-im/element-ios/issues/7025))
- Device Manager: Session list item is not tappable everywhere. ([#7035](https://github.com/vector-im/element-ios/issues/7035))
- Labs: Rich-text editor - Fix text formatting enabled inconsistent state ([#7052](https://github.com/vector-im/element-ios/issues/7052))
- Labs: Rich-text editor - Fix text formatting switch losing the current content of the composer ([#7054](https://github.com/vector-im/element-ios/issues/7054))
- Threads: removed "unread_thread_notifications" from sync filters for server that doesn't support MSC3773 ([#7066](https://github.com/vector-im/element-ios/issues/7066))
- Poll not usable after logging out and back in. ([#7070](https://github.com/vector-im/element-ios/issues/7070))
- Threads: Display number of unread messages above threads button ([#7076](https://github.com/vector-im/element-ios/issues/7076))
🚧 In development 🚧
- Device Manager: Multi-session sign out. ([#6963](https://github.com/vector-im/element-ios/issues/6963))
## Changes in 1.9.12 (2022-11-15)
✨ Features
- Threads: added support to read receipts (MSC3771) ([#6663](https://github.com/vector-im/element-ios/issues/6663))
- Threads: added support to notifications count (MSC3773) ([#6664](https://github.com/vector-im/element-ios/issues/6664))
- Threads: added support to labs flag for read receipts ([#7029](https://github.com/vector-im/element-ios/issues/7029))
- Threads: notification count in main timeline including un participated threads ([#7038](https://github.com/vector-im/element-ios/issues/7038))
- Unverified sessions alert. ([#7056](https://github.com/vector-im/element-ios/issues/7056))
- Labs: Rich-text editor: enable translations between Markdown and HTML when toggling text formatting ([#7061](https://github.com/vector-im/element-ios/issues/7061))
🙌 Improvements
- Add informational sheets for user's session states. ([#6992](https://github.com/vector-im/element-ios/pull/6992))
- Add the sign out option in the menu in the session overview. ([#7001](https://github.com/vector-im/element-ios/pull/7001))
- Add show/hide sessions' ip address in the new session manager. ([#7028](https://github.com/vector-im/element-ios/pull/7028))
- Updated GBDeviceInfo pod. ([#7051](https://github.com/vector-im/element-ios/pull/7051))
- Improve device manager code coverage. ([#7065](https://github.com/vector-im/element-ios/pull/7065))
- Initial sync: Remove 10s wait on failed initial sync ([#7068](https://github.com/vector-im/element-ios/pull/7068))
- Labs: Rich text-editor - Add support for plain text mode ([#6980](https://github.com/vector-im/element-ios/issues/6980))
🐛 Bugfixes
- Prevent autolayout crashes when showing toast notifications ([#7046](https://github.com/vector-im/element-ios/pull/7046))
- Fixed timeline layout issues for reactions and attachments ([#7064](https://github.com/vector-im/element-ios/pull/7064))
- Rich Text Composer: Voice Dictation is supported (only plain text can be dictated). ([#6945](https://github.com/vector-im/element-ios/issues/6945))
- Rich Text Composer dismisses the keyboard when sending custom iOS emojis as images, like the normal composer. ([#6946](https://github.com/vector-im/element-ios/issues/6946))
- Fixed IRC-style message and commands support in Rich text editor ([#6962](https://github.com/vector-im/element-ios/issues/6962))
- Fixed the missing keystrokes issue on the Rich Text Editor ([#7005](https://github.com/vector-im/element-ios/issues/7005))
- Fixed the long press deleting issue skipping some text on the Rich Text Editor ([#7006](https://github.com/vector-im/element-ios/issues/7006))
- Hide push toggles for http pushers when there is no server support. ([#7022](https://github.com/vector-im/element-ios/issues/7022))
- Synchronise composer and toolbar resizing animation duration for smoother height updates. ([#7025](https://github.com/vector-im/element-ios/issues/7025))
- Device Manager: Session list item is not tappable everywhere. ([#7035](https://github.com/vector-im/element-ios/issues/7035))
- Labs: Rich-text editor - Fix text formatting enabled inconsistent state ([#7052](https://github.com/vector-im/element-ios/issues/7052))
- Labs: Rich-text editor - Fix text formatting switch losing the current content of the composer ([#7054](https://github.com/vector-im/element-ios/issues/7054))
- Threads: removed "unread_thread_notifications" from sync filters for server that doesn't support MSC3773 ([#7066](https://github.com/vector-im/element-ios/issues/7066))
- Poll not usable after logging out and back in. ([#7070](https://github.com/vector-im/element-ios/issues/7070))
- Threads: Display number of unread messages above threads button ([#7076](https://github.com/vector-im/element-ios/issues/7076))
🚧 In development 🚧
- Device Manager: Multi-session sign out. ([#6963](https://github.com/vector-im/element-ios/issues/6963))
## Changes in 1.9.12 (2022-11-15)
✨ Features
- Threads: added support to read receipts (MSC3771) ([#6663](https://github.com/vector-im/element-ios/issues/6663))
- Threads: added support to notifications count (MSC3773) ([#6664](https://github.com/vector-im/element-ios/issues/6664))
- Threads: added support to labs flag for read receipts ([#7029](https://github.com/vector-im/element-ios/issues/7029))
- Threads: notification count in main timeline including un participated threads ([#7038](https://github.com/vector-im/element-ios/issues/7038))
- Unverified sessions alert. ([#7056](https://github.com/vector-im/element-ios/issues/7056))
- Labs: Rich-text editor: enable translations between Markdown and HTML when toggling text formatting ([#7061](https://github.com/vector-im/element-ios/issues/7061))
🙌 Improvements
- Add informational sheets for user's session states. ([#6992](https://github.com/vector-im/element-ios/pull/6992))
- Add the sign out option in the menu in the session overview. ([#7001](https://github.com/vector-im/element-ios/pull/7001))
- Add show/hide sessions' ip address in the new session manager. ([#7028](https://github.com/vector-im/element-ios/pull/7028))
- Updated GBDeviceInfo pod. ([#7051](https://github.com/vector-im/element-ios/pull/7051))
- Improve device manager code coverage. ([#7065](https://github.com/vector-im/element-ios/pull/7065))
- Initial sync: Remove 10s wait on failed initial sync ([#7068](https://github.com/vector-im/element-ios/pull/7068))
- Upgrade MatrixSDK version ([v0.24.3](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.24.3)).
- Labs: Rich text-editor - Add support for plain text mode ([#6980](https://github.com/vector-im/element-ios/issues/6980))
🐛 Bugfixes
- Prevent autolayout crashes when showing toast notifications ([#7046](https://github.com/vector-im/element-ios/pull/7046))
- Fixed timeline layout issues for reactions and attachments ([#7064](https://github.com/vector-im/element-ios/pull/7064))
- Rich Text Composer: Voice Dictation is supported (only plain text can be dictated). ([#6945](https://github.com/vector-im/element-ios/issues/6945))
- Rich Text Composer dismisses the keyboard when sending custom iOS emojis as images, like the normal composer. ([#6946](https://github.com/vector-im/element-ios/issues/6946))
- Fixed IRC-style message and commands support in Rich text editor ([#6962](https://github.com/vector-im/element-ios/issues/6962))
- Fixed the missing keystrokes issue on the Rich Text Editor ([#7005](https://github.com/vector-im/element-ios/issues/7005))
- Fixed the long press deleting issue skipping some text on the Rich Text Editor ([#7006](https://github.com/vector-im/element-ios/issues/7006))
- Hide push toggles for http pushers when there is no server support. ([#7022](https://github.com/vector-im/element-ios/issues/7022))
- Synchronise composer and toolbar resizing animation duration for smoother height updates. ([#7025](https://github.com/vector-im/element-ios/issues/7025))
- Device Manager: Session list item is not tappable everywhere. ([#7035](https://github.com/vector-im/element-ios/issues/7035))
- Labs: Rich-text editor - Fix text formatting enabled inconsistent state ([#7052](https://github.com/vector-im/element-ios/issues/7052))
- Labs: Rich-text editor - Fix text formatting switch losing the current content of the composer ([#7054](https://github.com/vector-im/element-ios/issues/7054))
- Threads: removed "unread_thread_notifications" from sync filters for server that doesn't support MSC3773 ([#7066](https://github.com/vector-im/element-ios/issues/7066))
- Poll not usable after logging out and back in. ([#7070](https://github.com/vector-im/element-ios/issues/7070))
- Threads: Display number of unread messages above threads button ([#7076](https://github.com/vector-im/element-ios/issues/7076))
🚧 In development 🚧
- Device Manager: Multi-session sign out. ([#6963](https://github.com/vector-im/element-ios/issues/6963))
## Changes in 1.9.11 (2022-11-08)
🐛 Bugfixes
- Prevent autolayout crashes when showing toast notifications ([#7046](https://github.com/vector-im/element-ios/pull/7046))
## Changes in 1.9.10 (2022-11-01)
✨ Features
+22 -30
View File
@@ -1,3 +1,25 @@
Changes in BWI project 2.2.0 (2022-12-16)
===================================================
Upstream merge ✨:
- v1.9.14
Features ✨:
Improvements 🙌:
- Text and screen changes for crosssigning (#3418)
Bugfix 🐛:
- Poll not usable after logging out and back in. (#7070)
Translations 🗣 :
SDK API changes ⚠️:
+Build 🧱:
Changes in BWI project 2.1.0 (2022-12-14)
===================================================
@@ -59,36 +81,6 @@ SDK API changes ⚠️:
+Build 🧱:
Changes in BWI project 2.0.0 (2022-11-23)
===================================================
Upstream merge ✨:
- v1.9.10
Features ✨:
- Chat bubbles enabled
- Praise the birthday (#3646)
Improvements 🙌:
- New Logo (#3719)
- Refactored Buildsettings (#3626)
- Remove Element terms of service view (#3791)
- Remove room settings for DMs to be more similar to Android (#3639)
- being able to change pusher url and change it to push-local (#3637)
Bugfix 🐛:
- Disable sharing toolbar for pdfs (#3880)
- Fix going into app without pin log in some cases (#3891)
Translations 🗣 :
SDK API changes ⚠️:
+Build 🧱:
Changes in BWI project 1.26.0 (2022-10-21)
===================================================
+1 -1
View File
@@ -16,5 +16,5 @@
//
// Version
MARKETING_VERSION = 2.1.0
MARKETING_VERSION = 2.2.0
CURRENT_PROJECT_VERSION = 20220714163152
+14 -4
View File
@@ -77,7 +77,7 @@ class BWIBuildSettings: NSObject {
// Location Sharing
// (this disables error messages when map laoding failed)
var locationSharingSSLProblemWorkaround = true
var locationSharingEnabled = true
var locationSharingEnabled = false
// Integration check
var forcedPinProtection = true
@@ -128,7 +128,7 @@ class BWIBuildSettings: NSObject {
var bwiAutoCreateAliasOnRoomCreation = true
var bwiLocationShareButtonVisible = true
var bwiLocationShareButtonVisible = false
var bwiUseCustomPersonalNotesAvatar = true
var bwiBetterIgnoredUsers = true
var bwiSettingsShowInAppNotifications = false
@@ -169,7 +169,17 @@ class BWIBuildSettings: NSObject {
"1be0b314a6c915d4475290522baef5b642db1b6d68937992b8e0eb5b7b0d6666",
"3deb73db8cafcd1d5a59e25e259c35816162e1f6ee67b5d7d011da0e8d6ef931",
"42e57985d61202c2c7dd87d898cef9bdce020877a4c7a8c7cd699f6a28f58c0c",
"e1c3c7cac12bd65bd48de79a2698187d2e768d2769377627534023588b8d7a33"]
"e1c3c7cac12bd65bd48de79a2698187d2e768d2769377627534023588b8d7a33",
"300f100961520d2909686f405bf97f53273f8ea82fa5329d981af8bf755f56ea",
"642e9a5b1276d65cd12f913b96a3d05fe022489f5487e0c888dfd0654b25177d",
"f7b8efdec2f424dbc912f4592d2489cc26232a624feecade73c33205a0a5cd8a",
"7cfd1c9b9405146681e43f6339ea487f083a3a92cea7cf669810ea160407781a",
"72d9a018893555073840bd90d80301417d2caa8b6ada7973d3365bcf929d6321",
"28e0940e355717de28a9b48add20ebb7ed178875937015033d394129d9356cb3",
"58077bffe53341e53ad18363dafc09498c314dd05a4fbaa2150c48dbd5d35e09",
"74c038bb4e26fb1d0fcc14474ec9ff6fe3ec158e13286a787b90a22ee638ac18",
"3740163f98aeda7dba285d2af1bfc351db395868268e2759ca701f926a6605a5",
"4d5b6dcf02396274be58a69c4bbeba975b529f6b19c504fc99a37892ee1cf0b5"]
// use a different badge color if the user was mentioned in a room
var showMentionsInRoom = true
@@ -441,7 +451,7 @@ class BWIBuildSettings: NSObject {
var passwordIndicatorOnLogin = true
// MARK: Displays the element base version on the settings screen
var elementBaseVersion = "1.9.10"
var elementBaseVersion = "1.9.14"
var showElementBaseVersion = true
+4 -1
View File
@@ -409,7 +409,7 @@ final class BuildSettings: NSObject {
// MARK: - Voice Broadcast
static let voiceBroadcastChunkLength: Int = 120
static let voiceBroadcastMaxLength: UInt64 = 144000
static let voiceBroadcastMaxLength: UInt = 14400 // 240min.
// MARK: - MXKAppSettings
static let enableBotCreation: Bool = false
@@ -437,4 +437,7 @@ final class BuildSettings: NSObject {
static let qrLoginEnableDisplayingQRs = false
static let rendezvousServerBaseURL = URL(string: "https://rendezvous.lab.element.dev/")!
// MARK: - Alerts
static let showUnverifiedSessionsAlert = true
}
+37 -36
View File
@@ -3,7 +3,7 @@ GEM
specs:
CFPropertyList (3.0.5)
rexml
activesupport (6.1.6.1)
activesupport (6.1.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@@ -17,20 +17,20 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.621.0)
aws-sdk-core (3.134.0)
aws-partitions (1.674.0)
aws-sdk-core (3.168.4)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.58.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (1.61.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-s3 (1.117.2)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.1)
aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
@@ -85,9 +85,9 @@ GEM
dotenv (2.8.1)
emoji_regex (3.2.3)
escape (0.0.4)
ethon (0.15.0)
ethon (0.16.0)
ffi (>= 1.15.0)
excon (0.92.4)
excon (0.94.0)
faraday (1.10.2)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
@@ -117,7 +117,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.209.1)
fastlane (2.211.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -159,7 +159,8 @@ GEM
fastlane-plugin-brew (0.1.1)
fastlane-plugin-diawi (2.1.0)
rest-client (>= 2.0.0)
fastlane-plugin-sentry (1.12.2)
fastlane-plugin-sentry (1.14.0)
os (~> 1.1, >= 1.1.4)
fastlane-plugin-versioning (0.5.1)
fastlane-plugin-xcodegen (1.1.0)
fastlane-plugin-brew (~> 0.1.1)
@@ -167,9 +168,9 @@ GEM
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.25.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-core (0.7.0)
google-apis-androidpublisher_v3 (0.31.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-core (0.9.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -178,27 +179,27 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.13.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-playcustomapp_v1 (0.10.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-storage_v1 (0.17.0)
google-apis-core (>= 0.7, < 2.a)
google-apis-iamcredentials_v1 (0.16.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-playcustomapp_v1 (0.12.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.38.0)
google-cloud-errors (1.3.0)
google-cloud-storage (1.44.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.17.0)
google-apis-storage_v1 (~> 0.19.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.2.0)
googleauth (1.3.0)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@@ -212,14 +213,14 @@ GEM
httpclient (2.8.3)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jmespath (1.6.1)
json (2.6.2)
jwt (2.4.1)
jmespath (1.6.2)
json (2.6.3)
jwt (2.5.0)
memoist (0.16.2)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
mini_magick (4.11.0)
mini_magick (4.12.0)
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.16.3)
@@ -230,14 +231,14 @@ GEM
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
nokogiri (1.13.8)
nokogiri (1.13.10)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
public_suffix (4.0.7)
racc (1.6.0)
racc (1.6.1)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
@@ -263,11 +264,11 @@ GEM
simctl (1.6.8)
CFPropertyList
naturally
slather (2.7.2)
slather (2.7.3)
CFPropertyList (>= 2.2, < 4)
activesupport
clamp (~> 1.3)
nokogiri (~> 1.12)
nokogiri (>= 1.13.9)
xcodeproj (~> 1.21)
terminal-notifier (2.0.0)
terminal-table (1.8.0)
@@ -302,7 +303,7 @@ GEM
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
zeitwerk (2.6.0)
zeitwerk (2.6.6)
PLATFORMS
ruby
+4 -4
View File
@@ -16,7 +16,7 @@ use_frameworks!
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI
#
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
$matrixSDKVersion = '= 0.24.2'
$matrixSDKVersion = '= 0.24.6'
# $matrixSDKVersion = :local
# $matrixSDKVersion = { :branch => 'develop'}
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }
@@ -43,7 +43,7 @@ when String # specific MatrixSDK released version
$matrixSDKVersionSpec = $matrixSDKVersion
end
$matrixSDKVersionSpec = { :git => 'https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios-matrix-sdk', :tag => 'v0.24.2_bwi' }
$matrixSDKVersionSpec = { :git => 'https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk', :tag => 'v0.24.6_bwi_beta' }
# Method to import the MatrixSDK
def import_MatrixSDK
@@ -55,7 +55,7 @@ end
def import_MatrixKit_pods
pod 'libPhoneNumber-iOS', '~> 0.9.13'
pod 'DTCoreText', '~> 1.6.25'
pod 'DTCoreText', '1.6.26'
#pod 'DTCoreText/Extension', '~> 1.6.25'
pod 'Down', '~> 0.11.0'
end
@@ -68,7 +68,7 @@ end
abstract_target 'RiotPods' do
pod 'GBDeviceInfo', '~> 6.6.0'
pod 'GBDeviceInfo', '~> 7.1.0'
pod 'Reusable', '~> 4.1'
pod 'KeychainAccess', '~> 4.2.2'
pod 'WeakDictionary', '~> 2.0'
+29 -29
View File
@@ -21,13 +21,13 @@ PODS:
- Down (0.11.0)
- DSBottomSheet (0.3.0)
- DSWaveformImage (6.1.1)
- DTCoreText (1.6.26):
- DTCoreText/Core (= 1.6.26)
- DTCoreText (1.6.27):
- DTCoreText/Core (= 1.6.27)
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
- DTFoundation/UIKit (~> 1.7.5)
- DTCoreText/Core (1.6.26):
- DTCoreText/Core (1.6.27):
- DTFoundation/Core (~> 1.7.5)
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
- DTFoundation/DTHTMLParser (~> 1.7.5)
@@ -41,9 +41,9 @@ PODS:
- DTTJailbreakDetection (0.4.0)
- FLEX (4.5.0)
- FlowCommoniOS (1.12.2)
- GBDeviceInfo (6.6.0):
- GBDeviceInfo/Core (= 6.6.0)
- GBDeviceInfo/Core (6.6.0)
- GBDeviceInfo (7.1.0):
- GBDeviceInfo/Core (= 7.1.0)
- GBDeviceInfo/Core (7.1.0)
- GZIP (1.3.0)
- Introspect (0.1.4)
- JitsiMeetSDK (5.0.2)
@@ -59,9 +59,9 @@ PODS:
- MatomoTracker (7.4.1):
- MatomoTracker/Core (= 7.4.1)
- MatomoTracker/Core (7.4.1)
- MatrixSDK (0.24.2):
- MatrixSDK/Core (= 0.24.2)
- MatrixSDK/Core (0.24.2):
- MatrixSDK (0.24.6):
- MatrixSDK/Core (= 0.24.6)
- MatrixSDK/Core (0.24.6):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.3.0)
- libbase58 (~> 0.1.4)
@@ -69,12 +69,12 @@ PODS:
- OLMKit (~> 3.2.5)
- Realm (= 10.27.0)
- SwiftyBeaver (= 1.9.5)
- MatrixSDK/CryptoSDK (0.24.2):
- MatrixSDKCrypto (= 0.1.5)
- MatrixSDK/JingleCallStack (0.24.2):
- MatrixSDK/CryptoSDK (0.24.6):
- MatrixSDKCrypto (= 0.1.6)
- MatrixSDK/JingleCallStack (0.24.6):
- JitsiMeetSDK (= 5.0.2)
- MatrixSDK/Core
- MatrixSDKCrypto (0.1.5)
- MatrixSDKCrypto (0.1.6)
- OLMKit (3.2.12):
- OLMKit/olmc (= 3.2.12)
- OLMKit/olmcpp (= 3.2.12)
@@ -95,7 +95,7 @@ PODS:
- Sentry/Core (7.15.0)
- SideMenu (6.5.0)
- SwiftBase32 (0.9.0)
- SwiftFormat/CLI (0.50.2)
- SwiftFormat/CLI (0.50.7)
- SwiftGen (6.6.2)
- SwiftJWT (3.6.200):
- BlueCryptor (~> 1.0)
@@ -103,7 +103,7 @@ PODS:
- BlueRSA (~> 1.0)
- KituraContracts (~> 1.2)
- LoggerAPI (~> 1.7)
- SwiftLint (0.49.1)
- SwiftLint (0.50.3)
- SwiftyBeaver (1.9.5)
- UICollectionViewLeftAlignedLayout (1.0.2)
- UICollectionViewRightAlignedLayout (0.0.3)
@@ -122,14 +122,14 @@ DEPENDENCIES:
- DTTJailbreakDetection (~> 0.4.0)
- FLEX (~> 4.5.0)
- FlowCommoniOS (~> 1.12.0)
- GBDeviceInfo (~> 6.6.0)
- GBDeviceInfo (~> 7.1.0)
- Introspect (~> 0.1)
- KeychainAccess (~> 4.2.2)
- KTCenterFlowLayout (~> 1.3.1)
- libPhoneNumber-iOS (~> 0.9.13)
- MatomoTracker (~> 7.4.1)
- MatrixSDK (from `https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios-matrix-sdk`, tag `v0.24.2_bwi`)
- MatrixSDK/JingleCallStack (from `https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios-matrix-sdk`, tag `v0.24.2_bwi`)
- MatrixSDK (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v0.24.6_bwi_beta`)
- MatrixSDK/JingleCallStack (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v0.24.6_bwi_beta`)
- OLMKit
- PostHog (~> 1.4.4)
- ReadMoreTextView (~> 3.0.1)
@@ -198,16 +198,16 @@ EXTERNAL SOURCES:
:branch: release/swift
:git: https://github.com/matrix-org/matrix-analytics-events.git
MatrixSDK:
:git: https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios-matrix-sdk
:tag: v0.24.2_bwi
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
:tag: v0.24.6_bwi_beta
CHECKOUT OPTIONS:
AnalyticsEvents:
:commit: 53ad46ba1ea1ee8f21139dda3c351890846a202f
:git: https://github.com/matrix-org/matrix-analytics-events.git
MatrixSDK:
:git: https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios-matrix-sdk
:tag: v0.24.2_bwi
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
:tag: v0.24.6_bwi_beta
SPEC CHECKSUMS:
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
@@ -218,12 +218,12 @@ SPEC CHECKSUMS:
Down: b6ba1bc985c9d2f4e15e3b293d2207766fa12612
DSBottomSheet: ca0ac37eb5af2dd54663f86b84382ed90a59be2a
DSWaveformImage: 3c718a0cf99291887ee70d1d0c18d80101d3d9ce
DTCoreText: ec749e013f2e1f76de5e7c7634642e600a7467ce
DTCoreText: ac297b565abd3b12390d33cd6e076d875f0c0a5e
DTFoundation: a53f8cda2489208cbc71c648be177f902ee17536
DTTJailbreakDetection: 5e356c5badc17995f65a83ed9483f787a0057b71
FLEX: e51461dd6f0bfb00643c262acdfea5d5d12c596b
FlowCommoniOS: ca92071ab526dc89905495a37844fd7e78d1a7f2
GBDeviceInfo: ed0db16230d2fa280e1cbb39a5a7f60f6946aaec
GBDeviceInfo: 5d62fa85bdcce3ed288d83c28789adf1173e4376
GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3
Introspect: b62c4dd2063072327c21d618ef2bedc3c87bc366
JitsiMeetSDK: edcac8e2b92ee0c7f3e75bd0aefefbe9faccfc93
@@ -235,8 +235,8 @@ SPEC CHECKSUMS:
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
Logging: beeb016c9c80cf77042d62e83495816847ef108b
MatomoTracker: 24a846c9d3aa76933183fe9d47fd62c9efa863fb
MatrixSDK: 1b64384084050652fcffafdf8641200f1ab25060
MatrixSDKCrypto: dcab554bc7157cad31c01fc1137cf5acb01959a4
MatrixSDK: 2bd63890d709683741452de2f215cfcda840fe64
MatrixSDKCrypto: b9e9bced53510f063bb203ccbec919f08d8f2641
OLMKit: da115f16582e47626616874e20f7bb92222c7a51
PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
@@ -245,10 +245,10 @@ SPEC CHECKSUMS:
Sentry: 63ca44f5e0c8cea0ee5a07686b02e56104f41ef7
SideMenu: f583187d21c5b1dd04c72002be544b555a2627a2
SwiftBase32: 9399c25a80666dc66b51e10076bf591e3bbb8f17
SwiftFormat: 710117321c55c82675c0dc03055128efbb13c38f
SwiftFormat: 4fcf72ee44c7198255108c22ed7135c38a36ba6b
SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c
SwiftJWT: 88c412708f58c169d431d344c87bc79a87c830ae
SwiftLint: 32ee33ded0636d0905ef6911b2b67bbaeeedafa5
SwiftLint: 77f7cb2b9bb81ab4a12fcc86448ba3f11afa50c6
SwiftyBeaver: 84069991dd5dca07d7069100985badaca7f0ce82
UICollectionViewLeftAlignedLayout: 830bf6fa5bab9f9b464f62e3384f9d2e00b3c0f6
UICollectionViewRightAlignedLayout: 823eef8c567eba4a44c21bc2ffcb0d0d5f361e2d
@@ -256,6 +256,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: e5afdb028a9f676c2ecf32f131614a0753736f3e
PODFILE CHECKSUM: 2046a454e97a09b21239c91eeeabb97af1089baf
COCOAPODS: 1.11.3
+2 -2
View File
@@ -13,7 +13,7 @@ Wir freuen uns, dass Du Dich für den BundesMessenger interessierst.
Fangen wir mit dem Wichtigsten an. Hier findest Du die offizielle App für iOS:
<p align="center">
<a href=https://apps.apple.com/us/app/bundesmessenger/id1616866351>
<a href=https://apps.apple.com/de/app/bundesmessenger/id1616866351>
<img alt="Download Apple App Store" src="https://linkmaker.itunes.apple.com/images/badges/en-us/badge_appstore-lrg.svg" width=160>
</a>
</p>
@@ -65,7 +65,7 @@ Wir nehmen euch diese Arbeit ab, da wir dies für den BwMessenger ohnehin machen
## Nutzung
Um die BundesMessenger App aus dem Play Store nutzen zu können, muss ihr euer Backend registrieren lassen. Weitere Infos dazu [hier](https://messenger.bwi.de/ich-will-bum).
Um die BundesMessenger App aus dem Play Store nutzen zu können, müsst ihr euer Backend registrieren lassen. Weitere Infos dazu [hier](https://messenger.bwi.de/ich-will-bum).
Wenn Du Dein Backend noch nicht erfolgreich aufgebaut hast, aber trotzdem schon einen Blick in die App werfen möchtest, bieten wir Dir eine Demo Umgebung an. Bitte kontaktiere uns per [Email](mailto:bundesmessenger@bwi.de&subject=Ich%20will%20testen).
@@ -32,7 +32,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift",
"state" : {
"revision" : "d5ef7054fb43924d5b92d5d627347ca2bc333717"
"revision" : "38ad28bedbe63b3587126158245659b6c989ec2c"
}
},
{
-795
View File
@@ -1,795 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="H1p-Uh-vWS">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<<<<<<< HEAD
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
=======
>>>>>>> 9792605e19cb683f1991f354dbc575b2b1e910bb
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--HomeNav-->
<scene sceneID="pY4-Hu-kfo">
<objects>
<navigationController id="RMx-3f-FxP" userLabel="HomeNav" customClass="RiotNavigationController" sceneMemberID="viewController">
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="Pmd-2v-anx">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="xaQ-tG-rlO" kind="relationship" relationship="rootViewController" id="Bmb-5J-cpB"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8fS-aE-onr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1375" y="-2202"/>
</scene>
<!--Room-->
<scene sceneID="UrN-g2-oG1">
<objects>
<viewController storyboardIdentifier="RoomViewControllerStoryboardId" title="Room" hidesBottomBarWhenPushed="YES" id="msb-ol-2LB" customClass="RoomViewController" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="3Zt-Wl-J6o">
<nil key="title"/>
<view key="titleView" contentMode="scaleToFill" id="aas-th-FW1" userLabel="Room title view container">
<rect key="frame" x="8" y="2" width="312" height="40"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</navigationItem>
<connections>
<outlet property="roomTitleViewContainer" destination="aas-th-FW1" id="SFz-1s-ywg"/>
<segue destination="KDg-aD-xlK" kind="show" identifier="showRoomSearch" id="hdA-V1-9AF"/>
<segue destination="gkO-rP-nGK" kind="show" identifier="showContactDetails" id="f5u-Y1-7nt"/>
<segue destination="ZZb-IS-a1F" kind="presentation" identifier="showUnknownDevices" id="wUx-4y-ybn"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="94y-cU-qQD" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-153" y="-419"/>
</scene>
<!--Room Member Details View Controller-->
<scene sceneID="eq5-qi-gDd">
<objects>
<viewController id="nDS-pp-sWM" customClass="RoomMemberDetailsViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="AgI-3V-llt"/>
<viewControllerLayoutGuide type="bottom" id="6ie-9b-cBo"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="N8z-LO-417">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="e8Z-uW-oDv" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5047" y="-1437"/>
</scene>
<!--Room Context Timeline-->
<scene sceneID="Htr-h8-baq">
<objects>
<viewController title="Room Context Timeline" hidesBottomBarWhenPushed="YES" id="Too-LV-OLW" customClass="RoomViewController" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="yLe-Hk-Sol">
<nil key="title"/>
<view key="titleView" contentMode="scaleToFill" id="djN-zB-Vni" userLabel="Room title view container">
<rect key="frame" x="8" y="2" width="312" height="40"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</navigationItem>
<connections>
<outlet property="roomTitleViewContainer" destination="djN-zB-Vni" id="VQG-Mp-hSa"/>
<segue destination="gkO-rP-nGK" kind="show" identifier="showContactDetails" id="ziz-Xl-QVg"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Yjg-uP-Hcy" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3326" y="-1299"/>
</scene>
<!--Room Search View Controller-->
<scene sceneID="rUg-1s-vHX">
<objects>
<viewController storyboardIdentifier="RoomSearch" id="KDg-aD-xlK" customClass="RoomSearchViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="F5n-wr-hGG"/>
<viewControllerLayoutGuide type="bottom" id="BxE-Q4-YjP"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Kg1-rX-y7X">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<connections>
<segue destination="Too-LV-OLW" kind="show" identifier="showTimeline" id="P1V-0d-mYL"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bK5-DX-KSF" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2558" y="-1299"/>
</scene>
<!--Users Devices View Controller-->
<scene sceneID="fKQ-Tq-qUc">
<objects>
<viewController storyboardIdentifier="UsersDevicesViewControllerStoryboardId" id="z83-KC-trJ" customClass="UsersDevicesViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="KBN-JV-gSS"/>
<viewControllerLayoutGuide type="bottom" id="lAN-yJ-zNI"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="b5v-sy-iSu">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="43F-4t-lHi">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="43F-4t-lHi" secondAttribute="trailing" id="6FJ-ku-UE3"/>
<constraint firstItem="43F-4t-lHi" firstAttribute="bottom" secondItem="lAN-yJ-zNI" secondAttribute="top" id="GK2-7h-FE0"/>
<constraint firstItem="43F-4t-lHi" firstAttribute="leading" secondItem="b5v-sy-iSu" secondAttribute="leading" id="Qda-BV-cf8"/>
<constraint firstItem="43F-4t-lHi" firstAttribute="top" secondItem="b5v-sy-iSu" secondAttribute="top" id="uhO-a4-0iq"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="Wgm-wm-4Qq"/>
<connections>
<outlet property="tableView" destination="43F-4t-lHi" id="ebQ-8p-875"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="UVa-0l-PGg" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2558" y="180"/>
</scene>
<!--Segmented View Controller-->
<scene sceneID="NZu-Q0-P0z">
<objects>
<tableViewController id="e7G-NU-7ck" customClass="SegmentedViewController" sceneMemberID="viewController"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="fXh-hO-Zgf" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3326" y="-442"/>
</scene>
<!--People View Controller-->
<scene sceneID="Qba-PP-lco">
<objects>
<viewController id="IGB-jr-yFz" customClass="PeopleViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Mhy-d3-Jh6"/>
<viewControllerLayoutGuide type="bottom" id="Hkk-qB-8tq"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="zXV-CY-rLP">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<tabBarItem key="tabBarItem" tag="2" image="tab_people" id="edr-fK-bgM">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="TabBarItemPeople"/>
</userDefinedRuntimeAttributes>
</tabBarItem>
<connections>
<segue destination="WDS-Ip-RQ9" kind="presentation" identifier="presentStartChat" id="bwO-oZ-2vj"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="TFZ-TK-2WH" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1929" y="-2817"/>
</scene>
<!--Favourites View Controller-->
<scene sceneID="z6B-k5-ano">
<objects>
<viewController id="HnD-LA-psC" customClass="FavouritesViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="pOc-AC-QkD"/>
<viewControllerLayoutGuide type="bottom" id="W6L-Au-CaZ"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Caq-TK-JOm">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<tabBarItem key="tabBarItem" tag="1" image="tab_favourites" id="UVh-Xd-zDZ">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="TabBarItemFavourites"/>
</userDefinedRuntimeAttributes>
</tabBarItem>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4qY-qn-l6L" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="942" y="-2049"/>
</scene>
<!--Unified Search View Controller-->
<scene sceneID="ijO-nb-yi4">
<objects>
<viewController id="nJt-uq-tV9" customClass="UnifiedSearchViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="V3l-gx-WNN"/>
<viewControllerLayoutGuide type="bottom" id="fYW-Kr-Hqf"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="laS-bb-xrK">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<connections>
<segue destination="aHG-CH-koI" kind="show" identifier="showDirectory" id="ndE-eu-9lm"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="G2g-bd-dSj" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="476" y="-3899"/>
</scene>
<!--Home View Controller-->
<scene sceneID="SZi-Ac-WJp">
<objects>
<viewController id="pBa-To-3YT" customClass="HomeViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="m3s-18-JgR"/>
<viewControllerLayoutGuide type="bottom" id="2lp-r9-RR5"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="hxX-1O-zT8">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<tabBarItem key="tabBarItem" title="" image="tab_home" id="hNI-yH-EXj">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="TabBarItemHome"/>
</userDefinedRuntimeAttributes>
</tabBarItem>
<navigationItem key="navigationItem" id="rA5-PM-GBU"/>
<connections>
<segue destination="WDS-Ip-RQ9" kind="presentation" identifier="presentStartChat" id="mhb-l9-pM3"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="pEk-LO-Ij0" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="942" y="-2818"/>
</scene>
<!--Master Tab Bar Controller-->
<scene sceneID="iBe-Y5-gBt">
<objects>
<tabBarController storyboardIdentifier="MasterTabBarController" id="xaQ-tG-rlO" customClass="MasterTabBarController" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="m6O-wq-yrc">
<barButtonItem key="leftBarButtonItem" image="settings_icon" id="QSE-cg-V2m">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="MasterTabBarControllerSettingsBarButton"/>
</userDefinedRuntimeAttributes>
<connections>
<segue destination="taU-5Q-sdv" kind="show" identifier="showSettings" id="3jh-kY-vVn"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" image="search_icon" id="pud-Fh-Usd">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="MasterTabBarControllerSearchBarButton"/>
</userDefinedRuntimeAttributes>
<connections>
<segue destination="nJt-uq-tV9" kind="show" identifier="showUnifiedSearch" id="5no-rS-zX7"/>
</connections>
</barButtonItem>
</navigationItem>
<tabBar key="tabBar" contentMode="scaleToFill" id="7jP-3G-C0b">
<rect key="frame" x="0.0" y="0.0" width="375" height="49"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tabBar>
<connections>
<outlet property="searchBarButtonIem" destination="pud-Fh-Usd" id="DiH-Re-nZE"/>
<outlet property="settingsBarButtonItem" destination="QSE-cg-V2m" id="N6b-Ju-w9g"/>
<segue destination="ZlD-EU-ncw" kind="presentation" identifier="showAuth" modalPresentationStyle="fullScreen" id="fpJ-zM-Qpo"/>
<segue destination="b5O-ib-y0h" kind="presentation" identifier="showSplash" modalPresentationStyle="fullScreen" id="bVC-XL-DlN"/>
<segue destination="HnD-LA-psC" kind="relationship" relationship="viewControllers" id="Bb8-fT-UTm"/>
<segue destination="IGB-jr-yFz" kind="relationship" relationship="viewControllers" id="UF6-Mc-MHx"/>
<segue destination="HPQ-zg-lZR" kind="relationship" relationship="viewControllers" id="Zd0-4h-jSn"/>
<segue destination="pBa-To-3YT" kind="relationship" relationship="viewControllers" id="m13-xQ-VwN"/>
<segue destination="SLx-Wj-p7E" kind="relationship" relationship="viewControllers" id="MgW-UB-uYW"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="k1S-FF-3Zu" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-516" y="-2203"/>
</scene>
<!--Authentication View Controller-->
<scene sceneID="FoA-N2-3aF">
<objects>
<viewController hidesBottomBarWhenPushed="YES" id="ZlD-EU-ncw" customClass="AuthenticationViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="crg-iM-twR"/>
<viewControllerLayoutGuide type="bottom" id="gbK-Nm-HUT"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="wIi-Yi-2pi">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="mvZ-se-pqQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1375" y="-3024"/>
</scene>
<!--Settings-->
<scene sceneID="9we-7Q-LBo">
<objects>
<tableViewController storyboardIdentifier="SettingsViewController" title="Settings" id="taU-5Q-sdv" customClass="SettingsViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="egL-pK-Xhr">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
<connections>
<outlet property="dataSource" destination="taU-5Q-sdv" id="Ipf-IM-E39"/>
<outlet property="delegate" destination="taU-5Q-sdv" id="kIU-uT-h9Y"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="s7I-UT-YCd" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-516" y="-3023"/>
</scene>
<!--RecentsSplitVC-->
<scene sceneID="Nki-YV-4Qg">
<objects>
<splitViewController storyboardIdentifier="RiotSplitViewController" title="RecentsSplitVC" id="H1p-Uh-vWS" customClass="RiotSplitViewController" sceneMemberID="viewController">
<toolbarItems/>
<navigationItem key="navigationItem" id="EB5-8V-irH"/>
<connections>
<segue destination="RMx-3f-FxP" kind="relationship" relationship="masterViewController" id="BlO-5A-QYV"/>
<segue destination="vC3-pB-5Vb" kind="relationship" relationship="detailViewController" id="0ws-cL-0tk"/>
</connections>
</splitViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="cZU-Oi-B1e" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2722" y="-1658"/>
</scene>
<!--Directory View Controller-->
<scene sceneID="96e-HZ-Idz">
<objects>
<tableViewController id="aHG-CH-koI" customClass="DirectoryViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="tbG-uL-KGT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<connections>
<outlet property="dataSource" destination="aHG-CH-koI" id="Ftx-LW-VkD"/>
<outlet property="delegate" destination="aHG-CH-koI" id="LIG-gR-Lz9"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="b5t-fe-rSJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1223" y="-3899"/>
</scene>
<!--Riot Navigation Controller-->
<scene sceneID="TbB-77-7oK">
<objects>
<navigationController id="qAW-wR-KyU" customClass="RiotNavigationController" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="r5V-3P-3Lg">
<rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="mRq-hp-dod" kind="relationship" relationship="rootViewController" id="fqQ-aW-08c"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="T7q-ez-UVO" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3326" y="-2050"/>
</scene>
<!--Contact Details View Controller-->
<scene sceneID="grY-bt-CcD">
<objects>
<viewController id="gkO-rP-nGK" customClass="ContactDetailsViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="0f8-Tg-Zlw"/>
<viewControllerLayoutGuide type="bottom" id="GF2-be-Jca"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="eRR-tG-G8a">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="01q-h6-40E" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5046" y="-711"/>
</scene>
<!--RoomNav-->
<scene sceneID="r7l-gg-dq7">
<objects>
<navigationController title="RoomNav" id="vC3-pB-5Vb" customClass="RiotNavigationController" sceneMemberID="viewController">
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="DjV-YW-jjY">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="Cpr-Tz-Az0" kind="relationship" relationship="rootViewController" id="OND-Rf-nLf"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="SLD-UC-DBI" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1375" y="-1121"/>
</scene>
<!--Placeholder Detail View Controller-->
<scene sceneID="2wP-Cu-Wca">
<objects>
<viewController storyboardIdentifier="EmptyDetailsViewControllerStoryboardId" id="Cpr-Tz-Az0" customClass="PlaceholderDetailViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="yS4-RU-AsN"/>
<viewControllerLayoutGuide type="bottom" id="VKG-pW-vMU"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="FdE-yP-vzj">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_logo" translatesAutoresizingMaskIntoConstraints="NO" id="6LG-qc-7jf">
<rect key="frame" x="127.5" y="273.5" width="120" height="120"/>
<constraints>
<constraint firstAttribute="width" secondItem="6LG-qc-7jf" secondAttribute="height" multiplier="1:1" id="4Qy-7P-CuE"/>
<constraint firstAttribute="width" constant="120" id="E2Y-gX-itg"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="6LG-qc-7jf" firstAttribute="centerY" secondItem="FdE-yP-vzj" secondAttribute="centerY" id="AF1-hZ-uOX"/>
<constraint firstItem="6LG-qc-7jf" firstAttribute="centerX" secondItem="FdE-yP-vzj" secondAttribute="centerX" id="WGk-oE-AqR"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="c9s-dM-eEg"/>
<connections>
<outlet property="logoImageView" destination="6LG-qc-7jf" id="vLR-KE-0aH"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="pZm-ap-zdK" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-153" y="-1121"/>
</scene>
<!--Groups View Controller-->
<scene sceneID="Rqp-Ti-qpu">
<objects>
<viewController id="SLx-Wj-p7E" customClass="GroupsViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="N1j-ye-uQa"/>
<viewControllerLayoutGuide type="bottom" id="FYD-2t-u4k"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Sl8-9u-7yE">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<tabBarItem key="tabBarItem" title="" image="tab_groups" id="5x2-xc-uIB"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="xpc-LV-krz" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="942" y="-1299"/>
</scene>
<!--Rooms View Controller-->
<scene sceneID="SDg-Pp-8Uj">
<objects>
<viewController id="HPQ-zg-lZR" customClass="RoomsViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Hkg-kw-ioH"/>
<viewControllerLayoutGuide type="bottom" id="UI8-oQ-9M9"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="rNJ-Yf-mVB">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<tabBarItem key="tabBarItem" tag="3" image="tab_rooms" id="7eS-Ei-00V">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="TabBarItemRooms"/>
</userDefinedRuntimeAttributes>
</tabBarItem>
<connections>
<segue destination="qAW-wR-KyU" kind="presentation" identifier="presentDirectoryServerPicker" id="1mb-Wk-zpt"/>
<segue destination="WDS-Ip-RQ9" kind="presentation" identifier="presentStartChat" id="Tfl-tq-LQp"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Kb9-ek-2v5" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1929" y="-2049"/>
</scene>
<!--Riot Navigation Controller-->
<scene sceneID="Fbq-8h-gyk">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="WDS-Ip-RQ9" customClass="RiotNavigationController" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="CtR-n9-ztG">
<rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="NCJ-FV-8di" kind="relationship" relationship="rootViewController" id="ZIA-Hu-sD4"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="gfz-1Q-Si0" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2735" y="-3760"/>
</scene>
<!--Start Chat View Controller-->
<scene sceneID="rVX-eZ-8XT">
<objects>
<viewController id="NCJ-FV-8di" customClass="StartChatViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="ybc-ex-KQ3"/>
<viewControllerLayoutGuide type="bottom" id="0pc-6H-UO9"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="rVj-X8-v0f">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<navigationItem key="navigationItem" id="Sre-eV-Crk"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4YW-Hr-WyR" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3610" y="-3761"/>
</scene>
<!--Riot Navigation Controller-->
<scene sceneID="Qyz-FA-hw5">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="ZZb-IS-a1F" customClass="RiotNavigationController" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="MHE-SG-tnL">
<rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="z83-KC-trJ" kind="relationship" relationship="rootViewController" id="83C-0z-Ld8"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="aTW-5P-KnU" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1385" y="180"/>
</scene>
<!--Contacts Table View Controller-->
<scene sceneID="2zi-xJ-RQo">
<objects>
<viewController id="udm-55-AMb" customClass="ContactsTableViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Jch-ZS-1Mm"/>
<viewControllerLayoutGuide type="bottom" id="7q1-ig-sPp"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="6G9-nj-ktC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="uv3-zI-b3q" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="374" y="449"/>
</scene>
<!--Directory Server Picker View Controller-->
<scene sceneID="t8d-GX-ntZ">
<objects>
<tableViewController storyboardIdentifier="DirectoryServerPickerViewControllerStoryboardId" id="mRq-hp-dod" customClass="DirectoryServerPickerViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="YbK-Rh-uRf">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<connections>
<outlet property="dataSource" destination="mRq-hp-dod" id="71E-8v-wpk"/>
<outlet property="delegate" destination="mRq-hp-dod" id="0Nu-Wt-eJD"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="6vB-s9-qMc"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Q9W-8f-BvC" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4174" y="-2050"/>
</scene>
<!--Splash View Controller-->
<scene sceneID="1CK-dy-3Dl">
<objects>
<viewController id="b5O-ib-y0h" customClass="SplashViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="ro1-wH-Fjd">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TBj-TV-uVU">
<rect key="frame" x="0.0" y="44" width="375" height="579"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wHg-o0-ZpU" userLabel="contentView">
<rect key="frame" x="0.0" y="0.0" width="375" height="579"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eKT-SY-ZYa">
<rect key="frame" x="15" y="40" width="345" height="400"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_logo" translatesAutoresizingMaskIntoConstraints="NO" id="QtR-0L-xed">
<rect key="frame" x="102.5" y="20" width="140" height="140"/>
<constraints>
<constraint firstAttribute="height" constant="140" id="EFA-Sp-TGr"/>
<constraint firstAttribute="width" constant="140" id="NL6-UM-OOC"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="eKj-M6-iOK">
<rect key="frame" x="15" y="190" width="315" height="50"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Dein Messenger für unser Land" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sdQ-s4-7JH">
<rect key="frame" x="0.0" y="0.0" width="315" height="50"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="50" id="tzj-Od-eza"/>
</constraints>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="6dK-tp-np2" userLabel="MO Stack View">
<rect key="frame" x="15" y="260" width="315" height="105"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="oDT-T5-XDJ">
<rect key="frame" x="0.0" y="0.0" width="315" height="25"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="message_circle" translatesAutoresizingMaskIntoConstraints="NO" id="n9Z-Dk-v3Y" userLabel="Secure Image View">
<rect key="frame" x="0.0" y="0.0" width="25" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="25" id="W2w-Mk-hQk"/>
<constraint firstAttribute="height" constant="25" id="fqE-fH-Lre"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Chats mit Kameraden und Kollegen" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3mK-7O-R4F">
<rect key="frame" x="33" y="3.5" width="282" height="18"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" systemColor="systemGrayColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="D6V-73-qCf">
<rect key="frame" x="0.0" y="40" width="315" height="25"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="attachment_gallery" translatesAutoresizingMaskIntoConstraints="NO" id="afm-3N-Ldu">
<rect key="frame" x="0.0" y="0.0" width="25" height="25"/>
<constraints>
<constraint firstAttribute="height" constant="25" id="2fI-3F-tEl"/>
<constraint firstAttribute="width" constant="25" id="G7q-Fi-UWQ"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sicher Medien und Dateien übertragen" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="R2a-ue-nbj">
<rect key="frame" x="33" y="3.5" width="282" height="18"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" systemColor="systemGrayColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="dBM-HE-DOv">
<rect key="frame" x="0.0" y="80" width="315" height="25"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="lock" translatesAutoresizingMaskIntoConstraints="NO" id="Zq6-4E-UaZ">
<rect key="frame" x="0.0" y="0.0" width="25" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="25" id="RVF-Bb-t46"/>
<constraint firstAttribute="height" constant="25" id="j9w-s6-NOZ"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Immer verschlüsselt" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6sI-9S-OAa">
<rect key="frame" x="33" y="3.5" width="282" height="18"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" systemColor="systemGrayColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="eKj-M6-iOK" firstAttribute="top" secondItem="QtR-0L-xed" secondAttribute="bottom" constant="30" id="0Fh-gF-c45"/>
<constraint firstAttribute="trailing" secondItem="6dK-tp-np2" secondAttribute="trailing" constant="15" id="Ta3-qC-Ybb"/>
<constraint firstItem="QtR-0L-xed" firstAttribute="centerX" secondItem="eKT-SY-ZYa" secondAttribute="centerX" id="Tx8-Bf-8oO"/>
<constraint firstItem="eKj-M6-iOK" firstAttribute="leading" secondItem="eKT-SY-ZYa" secondAttribute="leading" constant="15" id="aXX-09-Kfp"/>
<constraint firstItem="6dK-tp-np2" firstAttribute="top" secondItem="eKj-M6-iOK" secondAttribute="bottom" constant="20" id="c08-AQ-J6R"/>
<constraint firstItem="QtR-0L-xed" firstAttribute="top" secondItem="eKT-SY-ZYa" secondAttribute="top" constant="20" id="cRi-bF-78A"/>
<constraint firstAttribute="height" constant="400" id="fRB-2C-9N3"/>
<constraint firstAttribute="trailing" secondItem="eKj-M6-iOK" secondAttribute="trailing" constant="15" id="osP-RI-bkG"/>
<constraint firstItem="6dK-tp-np2" firstAttribute="leading" secondItem="eKT-SY-ZYa" secondAttribute="leading" constant="15" id="pF5-vu-uI6"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vnT-RP-hNw">
<rect key="frame" x="30" y="440" width="315" height="32"/>
<color key="backgroundColor" red="0.46247136589999999" green="0.81734329459999999" blue="0.47220504279999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<state key="normal" title="Loslegen">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<segue destination="em3-BB-kbd" kind="unwind" identifier="showSplash" unwindAction="unwindSplashScreen:" id="bNH-T9-nKA"/>
</connections>
</button>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="powered_by_BWI_blk" translatesAutoresizingMaskIntoConstraints="NO" id="Zs3-Ps-eXI">
<rect key="frame" x="117.5" y="517" width="140" height="80"/>
<constraints>
<constraint firstAttribute="width" constant="140" id="t4i-kE-F4F"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="vnT-RP-hNw" firstAttribute="trailing" secondItem="6dK-tp-np2" secondAttribute="trailing" id="2j2-KP-YJe"/>
<constraint firstItem="eKT-SY-ZYa" firstAttribute="leading" secondItem="wHg-o0-ZpU" secondAttribute="leading" constant="15" id="5G5-mP-KOL"/>
<constraint firstAttribute="trailing" secondItem="eKT-SY-ZYa" secondAttribute="trailing" constant="15" id="7Df-lX-t7F"/>
<constraint firstItem="vnT-RP-hNw" firstAttribute="leading" secondItem="6dK-tp-np2" secondAttribute="leading" id="OoQ-Je-zl1"/>
<constraint firstItem="vnT-RP-hNw" firstAttribute="top" secondItem="dBM-HE-DOv" secondAttribute="bottom" constant="35" id="QA1-gN-h1m"/>
<constraint firstItem="eKT-SY-ZYa" firstAttribute="centerY" secondItem="wHg-o0-ZpU" secondAttribute="centerY" constant="-49.5" id="RS1-Ic-GMt"/>
<constraint firstItem="eKT-SY-ZYa" firstAttribute="centerX" secondItem="wHg-o0-ZpU" secondAttribute="centerX" id="ZlM-uL-bd1"/>
<constraint firstAttribute="bottom" secondItem="Zs3-Ps-eXI" secondAttribute="bottom" constant="-18" id="iBS-6v-qAH"/>
<constraint firstItem="Zs3-Ps-eXI" firstAttribute="centerX" secondItem="wHg-o0-ZpU" secondAttribute="centerX" id="oAH-oe-yQ9"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="wHg-o0-ZpU" secondAttribute="trailing" id="DYy-4n-RwM"/>
<constraint firstItem="wHg-o0-ZpU" firstAttribute="centerY" secondItem="TBj-TV-uVU" secondAttribute="centerY" id="Dgd-eL-QiY"/>
<constraint firstItem="wHg-o0-ZpU" firstAttribute="centerX" secondItem="TBj-TV-uVU" secondAttribute="centerX" id="QDI-Ne-Cuc"/>
<constraint firstItem="wHg-o0-ZpU" firstAttribute="leading" secondItem="TBj-TV-uVU" secondAttribute="leading" id="gXa-iz-1MA"/>
<constraint firstItem="wHg-o0-ZpU" firstAttribute="centerY" secondItem="TBj-TV-uVU" secondAttribute="centerY" id="kxE-hG-N99"/>
<constraint firstItem="wHg-o0-ZpU" firstAttribute="top" secondItem="TBj-TV-uVU" secondAttribute="top" id="pvC-X2-Axo"/>
<constraint firstAttribute="bottom" secondItem="wHg-o0-ZpU" secondAttribute="bottom" id="t8l-2d-XF5"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="TBj-TV-uVU" firstAttribute="leading" secondItem="ro1-wH-Fjd" secondAttribute="leading" id="DDL-fn-YYU"/>
<constraint firstItem="TBj-TV-uVU" firstAttribute="centerX" secondItem="ro1-wH-Fjd" secondAttribute="centerX" id="GpD-0W-Wkq"/>
<constraint firstItem="TBj-TV-uVU" firstAttribute="top" secondItem="ro1-wH-Fjd" secondAttribute="top" constant="44" id="McY-o6-ej5"/>
<constraint firstItem="TBj-TV-uVU" firstAttribute="centerY" secondItem="ro1-wH-Fjd" secondAttribute="centerY" id="T38-ue-icu"/>
<constraint firstItem="TBj-TV-uVU" firstAttribute="trailing" secondItem="ro1-wH-Fjd" secondAttribute="trailing" id="ZOs-TH-Ms5"/>
<constraint firstAttribute="bottom" secondItem="TBj-TV-uVU" secondAttribute="bottom" priority="250" id="y1K-jp-f44"/>
</constraints>
<viewLayoutGuide key="safeArea" id="mxh-hM-KYC"/>
</view>
<connections>
<outlet property="appLogoImageView" destination="QtR-0L-xed" id="bcn-Xy-bom"/>
<outlet property="comImageView" destination="afm-3N-Ldu" id="QE6-3d-mNA"/>
<outlet property="doneButton" destination="vnT-RP-hNw" id="92v-hI-jsD"/>
<outlet property="encryptImageView" destination="Zq6-4E-UaZ" id="gDw-hv-c2r"/>
<outlet property="firstInfoLabel" destination="3mK-7O-R4F" id="IUx-HH-cWL"/>
<outlet property="secondInfoLabel" destination="R2a-ue-nbj" id="RIl-dq-gzp"/>
<outlet property="secureImageView" destination="n9Z-Dk-v3Y" id="qzU-yU-J1P"/>
<outlet property="thirdInfoLabel" destination="6sI-9S-OAa" id="QgV-Y4-bUy"/>
<outlet property="titleLabel" destination="sdQ-s4-7JH" id="wso-r1-E3w"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="oND-oq-oFz" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
<exit id="em3-BB-kbd" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="-2127.1999999999998" y="-3025.6371814092954"/>
</scene>
</scenes>
<inferredMetricsTieBreakers>
<segue reference="Tfl-tq-LQp"/>
<segue reference="f5u-Y1-7nt"/>
</inferredMetricsTieBreakers>
<resources>
<<<<<<< HEAD
<image name="attachment_gallery" width="24" height="24"/>
<image name="integrations_icon" width="24" height="24"/>
=======
>>>>>>> 9792605e19cb683f1991f354dbc575b2b1e910bb
<image name="launch_screen_logo" width="240" height="240"/>
<image name="lock" width="24" height="24"/>
<image name="message_circle" width="24" height="24"/>
<image name="powered_by_BWI_blk" width="417" height="80"/>
<image name="search_icon" width="24" height="24"/>
<image name="settings_icon" width="24" height="24"/>
<image name="tab_favourites" width="24" height="24"/>
<image name="tab_groups" width="24" height="24"/>
<image name="tab_home" width="20" height="23.5"/>
<image name="tab_people" width="24" height="24"/>
<image name="tab_rooms" width="24" height="24"/>
<systemColor name="groupTableViewBackgroundColor">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "permalink 2.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "permalink 1.svg",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "permalink.svg",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,34 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 25 25"
id="vector">
<path
id="path"
d="M 17.5 17.5 L 6.5 12.5 L 17.5 7.5"
fill="#00000000"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"/>
<path
id="path_1"
d="M 17.5 7.5 M 15.5 7.5 C 15.5 6.97 15.711 6.461 16.086 6.086 C 16.461 5.711 16.97 5.5 17.5 5.5 C 18.03 5.5 18.539 5.711 18.914 6.086 C 19.289 6.461 19.5 6.97 19.5 7.5 C 19.5 8.03 19.289 8.539 18.914 8.914 C 18.539 9.289 18.03 9.5 17.5 9.5 C 16.97 9.5 16.461 9.289 16.086 8.914 C 15.711 8.539 15.5 8.03 15.5 7.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
<path
id="path_2"
d="M 17.5 17.5 M 15.5 17.5 C 15.5 16.97 15.711 16.461 16.086 16.086 C 16.461 15.711 16.97 15.5 17.5 15.5 C 18.03 15.5 18.539 15.711 18.914 16.086 C 19.289 16.461 19.5 16.97 19.5 17.5 C 19.5 18.03 19.289 18.539 18.914 18.914 C 18.539 19.289 18.03 19.5 17.5 19.5 C 16.97 19.5 16.461 19.289 16.086 18.914 C 15.711 18.539 15.5 18.03 15.5 17.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
<path
id="path_3"
d="M 6.5 12.5 M 4.5 12.5 C 4.5 11.97 4.711 11.461 5.086 11.086 C 5.461 10.711 5.97 10.5 6.5 10.5 C 7.03 10.5 7.539 10.711 7.914 11.086 C 8.289 11.461 8.5 11.97 8.5 12.5 C 8.5 13.03 8.289 13.539 7.914 13.914 C 7.539 14.289 7.03 14.5 6.5 14.5 C 5.97 14.5 5.461 14.289 5.086 13.914 C 4.711 13.539 4.5 13.03 4.5 12.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,34 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 25 25"
id="vector">
<path
id="path"
d="M 17.5 17.5 L 6.5 12.5 L 17.5 7.5"
fill="#00000000"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"/>
<path
id="path_1"
d="M 17.5 7.5 M 15.5 7.5 C 15.5 6.97 15.711 6.461 16.086 6.086 C 16.461 5.711 16.97 5.5 17.5 5.5 C 18.03 5.5 18.539 5.711 18.914 6.086 C 19.289 6.461 19.5 6.97 19.5 7.5 C 19.5 8.03 19.289 8.539 18.914 8.914 C 18.539 9.289 18.03 9.5 17.5 9.5 C 16.97 9.5 16.461 9.289 16.086 8.914 C 15.711 8.539 15.5 8.03 15.5 7.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
<path
id="path_2"
d="M 17.5 17.5 M 15.5 17.5 C 15.5 16.97 15.711 16.461 16.086 16.086 C 16.461 15.711 16.97 15.5 17.5 15.5 C 18.03 15.5 18.539 15.711 18.914 16.086 C 19.289 16.461 19.5 16.97 19.5 17.5 C 19.5 18.03 19.289 18.539 18.914 18.914 C 18.539 19.289 18.03 19.5 17.5 19.5 C 16.97 19.5 16.461 19.289 16.086 18.914 C 15.711 18.539 15.5 18.03 15.5 17.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
<path
id="path_3"
d="M 6.5 12.5 M 4.5 12.5 C 4.5 11.97 4.711 11.461 5.086 11.086 C 5.461 10.711 5.97 10.5 6.5 10.5 C 7.03 10.5 7.539 10.711 7.914 11.086 C 8.289 11.461 8.5 11.97 8.5 12.5 C 8.5 13.03 8.289 13.539 7.914 13.914 C 7.539 14.289 7.03 14.5 6.5 14.5 C 5.97 14.5 5.461 14.289 5.086 13.914 C 4.711 13.539 4.5 13.03 4.5 12.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,34 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 25 25"
id="vector">
<path
id="path"
d="M 17.5 17.5 L 6.5 12.5 L 17.5 7.5"
fill="#00000000"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"/>
<path
id="path_1"
d="M 17.5 7.5 M 15.5 7.5 C 15.5 6.97 15.711 6.461 16.086 6.086 C 16.461 5.711 16.97 5.5 17.5 5.5 C 18.03 5.5 18.539 5.711 18.914 6.086 C 19.289 6.461 19.5 6.97 19.5 7.5 C 19.5 8.03 19.289 8.539 18.914 8.914 C 18.539 9.289 18.03 9.5 17.5 9.5 C 16.97 9.5 16.461 9.289 16.086 8.914 C 15.711 8.539 15.5 8.03 15.5 7.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
<path
id="path_2"
d="M 17.5 17.5 M 15.5 17.5 C 15.5 16.97 15.711 16.461 16.086 16.086 C 16.461 15.711 16.97 15.5 17.5 15.5 C 18.03 15.5 18.539 15.711 18.914 16.086 C 19.289 16.461 19.5 16.97 19.5 17.5 C 19.5 18.03 19.289 18.539 18.914 18.914 C 18.539 19.289 18.03 19.5 17.5 19.5 C 16.97 19.5 16.461 19.289 16.086 18.914 C 15.711 18.539 15.5 18.03 15.5 17.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
<path
id="path_3"
d="M 6.5 12.5 M 4.5 12.5 C 4.5 11.97 4.711 11.461 5.086 11.086 C 5.461 10.711 5.97 10.5 6.5 10.5 C 7.03 10.5 7.539 10.711 7.914 11.086 C 8.289 11.461 8.5 11.97 8.5 12.5 C 8.5 13.03 8.289 13.539 7.914 13.914 C 7.539 14.289 7.03 14.5 6.5 14.5 C 5.97 14.5 5.461 14.289 5.086 13.914 C 4.711 13.539 4.5 13.03 4.5 12.5"
fill="#fcfcfc"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Frame 143.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 143@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 143@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "action_formatting_enabled.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "action_formatting_enabled@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "action_formatting_enabled@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "voice_broadcast_spinner.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.43784 2.15198C1.7003 3.50937 0.583252 5.62423 0.583252 7.99999C0.583252 12.0961 3.90381 15.4167 7.99992 15.4167C12.096 15.4167 15.4166 12.0961 15.4166 7.99999C15.4166 5.64846 14.3222 3.55254 12.615 2.19375L11.5457 3.26305C12.9852 4.3423 13.9166 6.06237 13.9166 7.99999C13.9166 11.2677 11.2676 13.9167 7.99992 13.9167C4.73223 13.9167 2.08325 11.2677 2.08325 7.99999C2.08325 6.03806 3.03817 4.29916 4.50858 3.22272L3.43784 2.15198Z" fill="#737D8C"/>
</svg>

After

Width:  |  Height:  |  Size: 603 B

@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "voice_broadcast_tile_live.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4589 2.7911C13.2328 2.50046 12.814 2.44811 12.5234 2.67415C12.233 2.89995 12.1805 3.31813 12.4057 3.60872L12.4062 3.60937L12.4068 3.61023L12.4159 3.62234C12.4248 3.6342 12.439 3.65358 12.4578 3.68014C12.4956 3.73328 12.5517 3.81499 12.6202 3.92259C12.7574 4.13815 12.9427 4.45557 13.1285 4.85374C13.502 5.6541 13.866 6.756 13.866 8.00039C13.866 9.24478 13.502 10.3467 13.1285 11.147C12.9427 11.5452 12.7574 11.8626 12.6202 12.0782C12.5517 12.1858 12.4956 12.2675 12.4578 12.3206C12.439 12.3472 12.4248 12.3666 12.4159 12.3784L12.4068 12.3905L12.4062 12.3914L12.4056 12.3922C12.1805 12.6828 12.2331 13.1009 12.5234 13.3266C12.814 13.5527 13.2328 13.5003 13.4589 13.2097L12.962 12.8232C13.4589 13.2097 13.4589 13.2097 13.4589 13.2097L13.4602 13.208L13.4621 13.2055L13.4677 13.1983L13.4853 13.1748C13.4999 13.1552 13.5201 13.1277 13.5449 13.0926C13.5947 13.0226 13.6636 12.9221 13.7451 12.794C13.9079 12.5381 14.1226 12.1699 14.3368 11.7109C14.7633 10.797 15.1993 9.49886 15.1993 8.00039C15.1993 6.50192 14.7633 5.20382 14.3368 4.28989C14.1226 3.83092 13.9079 3.46263 13.7451 3.20676C13.6636 3.07865 13.5947 2.97821 13.5449 2.90814C13.5201 2.87309 13.4999 2.84559 13.4853 2.82598L13.4677 2.80251L13.4621 2.79528L13.4602 2.79281L13.4595 2.79185C13.4595 2.79185 13.4589 2.7911 12.9326 3.20039L13.4589 2.7911Z" fill="#737D8C"/>
<path d="M11.7261 5.19124C11.5001 4.90061 11.0812 4.84825 10.7906 5.0743C10.5007 5.29976 10.4479 5.71701 10.6719 6.00755L10.6742 6.0106C10.6772 6.0146 10.6828 6.02225 10.6907 6.03341C10.7066 6.05575 10.7315 6.09192 10.7625 6.1406C10.8246 6.2383 10.91 6.38429 10.9958 6.56817C11.1693 6.93996 11.3332 7.44186 11.3332 8.00054C11.3332 8.55921 11.1693 9.06111 10.9958 9.4329C10.91 9.61678 10.8246 9.76277 10.7625 9.86047C10.7315 9.90915 10.7066 9.94532 10.6907 9.96766C10.6828 9.97881 10.6772 9.98647 10.6742 9.99047L10.6719 9.99353C10.4479 10.2841 10.5007 10.7013 10.7906 10.9268C11.0812 11.1528 11.5001 11.1005 11.7261 10.8098L11.1999 10.4005C11.7261 10.8098 11.7261 10.8098 11.7261 10.8098L11.7273 10.8083L11.7288 10.8064L11.7326 10.8014L11.7436 10.7868C11.7523 10.7751 11.7639 10.7593 11.7778 10.7397C11.8057 10.7004 11.8433 10.6455 11.8873 10.5763C11.9752 10.4383 12.0898 10.2414 12.204 9.99674C12.4305 9.51139 12.6666 8.81329 12.6666 8.00054C12.6666 7.18778 12.4305 6.48968 12.204 6.00433C12.0898 5.75964 11.9752 5.56278 11.8873 5.42476C11.8433 5.35558 11.8057 5.30068 11.7778 5.26141C11.7639 5.24176 11.7523 5.22598 11.7436 5.21424L11.7326 5.19967L11.7288 5.19468L11.7273 5.19276L11.7267 5.19195C11.7267 5.19195 11.7261 5.19124 11.1999 5.60054L11.7261 5.19124Z" fill="#737D8C"/>
<path d="M2.40733 13.2096C2.63337 13.5003 3.05223 13.5526 3.34286 13.3266C3.63317 13.1008 3.68572 12.6826 3.46054 12.392L3.46004 12.3914L3.45939 12.3905L3.45029 12.3784C3.44145 12.3665 3.42722 12.3472 3.40836 12.3206C3.37062 12.2674 3.31448 12.1857 3.246 12.0781C3.10883 11.8626 2.9235 11.5452 2.73768 11.147C2.36418 10.3466 2.00023 9.24473 2.00023 8.00034C2.00023 6.75596 2.36418 5.65406 2.73768 4.8537C2.9235 4.45553 3.10883 4.13811 3.246 3.92255C3.31448 3.81495 3.37062 3.73324 3.40836 3.6801C3.42722 3.65354 3.44145 3.63416 3.45029 3.6223L3.45939 3.61019L3.46004 3.60933L3.46064 3.60855C3.68571 3.31797 3.63313 2.89988 3.34286 2.67411C3.05223 2.44806 2.63337 2.50042 2.40733 2.79105L2.90417 3.17748C2.40732 2.79106 2.40733 2.79105 2.40733 2.79105L2.406 2.79276L2.40409 2.79524L2.39856 2.80247L2.3809 2.82594C2.3663 2.84555 2.34615 2.87305 2.32126 2.9081C2.2715 2.97817 2.20265 3.0786 2.12112 3.20671C1.95829 3.46259 1.74363 3.83088 1.52944 4.28985C1.10294 5.20378 0.666896 6.50188 0.666896 8.00034C0.666896 9.49881 1.10294 10.7969 1.52944 11.7108C1.74363 12.1698 1.95829 12.5381 2.12112 12.794C2.20265 12.9221 2.2715 13.0225 2.32126 13.0926C2.34615 13.1276 2.3663 13.1551 2.3809 13.1747L2.39856 13.1982L2.40409 13.2054L2.406 13.2079L2.40674 13.2089C2.40674 13.2089 2.40733 13.2096 2.93356 12.8003L2.40733 13.2096Z" fill="#737D8C"/>
<path d="M4.14008 10.8095C4.36612 11.1001 4.78497 11.1525 5.0756 10.9264C5.36548 10.701 5.41832 10.2837 5.19431 9.99318L5.19202 9.99013C5.18904 9.98614 5.18341 9.97848 5.17549 9.96732C5.15962 9.94498 5.13473 9.90881 5.10375 9.86014C5.04158 9.76244 4.95625 9.61644 4.87043 9.43256C4.69693 9.06077 4.53298 8.55887 4.53298 8.0002C4.53298 7.44152 4.69693 6.93963 4.87043 6.56784C4.95625 6.38395 5.04158 6.23796 5.10375 6.14026C5.13473 6.09158 5.15962 6.05542 5.17549 6.03307C5.18341 6.02192 5.18904 6.01426 5.19202 6.01026L5.19432 6.0072C5.41832 5.71667 5.36547 5.29942 5.0756 5.07396C4.78497 4.84792 4.36612 4.90027 4.14008 5.19091L4.66631 5.6002C4.14008 5.19091 4.14008 5.19091 4.14008 5.19091L4.13889 5.19243L4.13742 5.19434L4.1336 5.19933L4.12263 5.21391C4.11389 5.22565 4.10234 5.24143 4.08838 5.26107C4.0605 5.30034 4.02289 5.35524 3.97887 5.42442C3.89104 5.56244 3.77638 5.7593 3.66219 6.00399C3.43569 6.48934 3.19964 7.18745 3.19964 8.0002C3.19964 8.81295 3.43569 9.51105 3.66219 9.99641C3.77638 10.2411 3.89104 10.438 3.97887 10.576C4.02289 10.6452 4.0605 10.7001 4.08838 10.7393C4.10234 10.759 4.11389 10.7747 4.12263 10.7865L4.1336 10.8011L4.13742 10.8061L4.13889 10.808L4.13952 10.8088C4.13952 10.8088 4.14008 10.8095 4.66631 10.4002L4.14008 10.8095Z" fill="#737D8C"/>
<circle cx="8.00033" cy="8.00008" r="1.33333" fill="#737D8C"/>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "voice_broadcast_tile_mic.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.39966 4.1C5.39966 2.66406 6.56372 1.5 7.99966 1.5C9.4356 1.5 10.5997 2.66406 10.5997 4.1V7.98837C10.5997 9.42431 9.4356 10.5884 7.99966 10.5884C6.56372 10.5884 5.39966 9.4243 5.39966 7.98836V4.1Z" fill="#737D8C"/>
<path d="M3.44954 7.15837C3.90978 7.15837 4.28288 7.53146 4.28288 7.9917C4.28288 10.0368 5.94052 11.6972 7.98961 11.7025C7.99296 11.7025 7.99632 11.7025 7.99967 11.7025C8.00302 11.7025 8.00636 11.7025 8.00969 11.7025C10.0587 11.6971 11.7162 10.0368 11.7162 7.9917C11.7162 7.53146 12.0893 7.15837 12.5495 7.15837C13.0098 7.15837 13.3829 7.53146 13.3829 7.9917C13.3829 10.6793 11.4097 12.905 8.83301 13.3051V13.8341C8.83301 14.2944 8.45991 14.6675 7.99967 14.6675C7.53944 14.6675 7.16634 14.2944 7.16634 13.8341V13.3052C4.58956 12.9052 2.61621 10.6794 2.61621 7.9917C2.61621 7.53146 2.98931 7.15837 3.44954 7.15837Z" fill="#737D8C"/>
</svg>

After

Width:  |  Height:  |  Size: 961 B

@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "voice_broadcast_time_left.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 1H6V2.33333H10V1ZM7.33333 9.66667H8.66667V5.66667H7.33333V9.66667ZM12.6867 5.26L13.6333 4.31333C13.3467 3.97333 13.0333 3.65333 12.6933 3.37333L11.7467 4.32C10.7133 3.49333 9.41333 3 8 3C4.68667 3 2 5.68667 2 9C2 12.3133 4.68 15 8 15C11.32 15 14 12.3133 14 9C14 7.58667 13.5067 6.28667 12.6867 5.26ZM8 13.6667C5.42 13.6667 3.33333 11.58 3.33333 9C3.33333 6.42 5.42 4.33333 8 4.33333C10.58 4.33333 12.6667 6.42 12.6667 9C12.6667 11.58 10.58 13.6667 8 13.6667Z" fill="#737D8C"/>
</svg>

After

Width:  |  Height:  |  Size: 593 B

+16 -10
View File
@@ -162,8 +162,8 @@
"room_participants_action_unignore" = "Zeige alle Nachrichten von diesem Nutzer";
"room_participants_action_set_moderator" = "Gib Moderationsrechte";
"room_participants_action_set_admin" = "Mache zum Administrator";
"room_participants_action_permalink" = "Nutzer teilen";
"room_event_action_permalink" = "Nachricht teilen";
"room_participants_action_permalink" = "Link zum Nutzer kopieren";
"room_event_action_permalink" = "Link zur Nachricht kopieren";
"bwi_room_participants_section_admin" = "Admin";
"bwi_room_participants_section_moderator" = "Moderator";
"bwi_room_participants_section_member" = "Mitglied";
@@ -263,15 +263,17 @@
"device_verification_verified_got_it_button" = "Fertig";
"device_verification_verified_title" = "Geschafft!";
"device_verification_cancelled" = "Verifizierung abgebrochen. Du kannst sie erneut starten.";
"image_picker_action_remove_photo" = "Foto entfernen";
"room_participants_security_information_room_not_encrypted_for_dm" = "Die Nachrichten hier sind nicht Ende-zu-Ende verschlüsselt.";
"room_participants_security_information_room_encrypted" = "Nachrichten in diesem Raum sind Ende-zu-Ende verschlüsselt.\n\nDeine Nachrichten sind mit digitalen Schlüsseln gesichert, nur du und der/die Empfänger!n haben die einzigen Schlüssel, um jene zu entschlüsseln.";
"security_settings_crypto_sessions_description" = "Vertraue Sitzungen, um Zugriff auf Ende-zu-Ende verschlüsselte Nachrichten zu gewähren. Wenn du eine Sitzung nicht kennst, ändere dein Passwort und setze dein Nachrichtenpasswort für die Nachrichtensicherung zurück.";
"room_participants_security_information_room_encrypted_for_dm" = "Nachrichten hier sind Ende-zu-Ende verschlüsselt.\n\nDeine Nachrichten sind mit digitalen Schlüsseln gesichert, nur du und der/die Empfänger!n haben die einzigen Schlüssel, um jene zu entsperren.";
"room_widget_permission_avatar_url_permission" = "Deine Profilbild-URL";
"device_verification_self_verify_wait_title" = "Verifiziere dieses Gerät";
"device_verification_self_verify_wait_information" = "Verfiziere dieses Gerät von einer Deiner anderen Sitzungen, um Zugriff auf die verschlüsselten Nachrichten zu erhalten.";
"device_verification_self_verify_wait_information_more" = "Benutze die neuste Messenger-Sitzung auf deinem anderen Gerät:";
"device_verification_self_verify_wait_title" = "Diese Anmeldung verifizieren";
"device_verification_self_verify_wait_information" = "Verifiziere diese Anmeldung mit einem Gerät, auf dem du bereits angemeldet bist, um Zugriff auf die verschlüsselten Nachrichten zu erhalten.";
"device_verification_self_verify_wait_information_more" = "";
"device_verification_self_verify_alert_message" = "Bestätige die neue Anmeldung auf Deinem Gerät: %@";
"client_desktop_name" = "BundesMessenger Desktop";
"client_web_name" = "BundesMessenger Web";
@@ -289,12 +291,16 @@
"secure_key_backup_setup_intro_info" = "Damit du deine Nachrichten bei einem erneuten Login auf diesem Gerät entschlüsseln kannst, richte einen Wiederherstellungsschlüssel ein.";
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Wiederherstellungsschlüssel";
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Nutze deinen Wiederherstellungsschlüssel, um alle deine Nachrichten zu entschlüsseln.";
"key_verification_this_session_title" = "Wiederherstellungsschlüssel";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Verschlüsselungskennwort verwenden";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Verschlüsselungskennwort verwenden";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Nutze Dein Wiederherstellungsschlüssel um alle Deine Nachrichten zu entschlüsseln";
"key_verification_verify_qr_code_title" = "Diese Anmeldung verifizieren";
"key_verification_verify_qr_code_information_other_device" = "Scanne den Code mit einem anderen Gerät oder umgekehrt.";
"key_verification_verify_qr_code_cannot_scan_action" = "Stattdessen mit Emojis vergleichen";
"key_verification_this_session_title" = "Diese Anmeldung verifizieren";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Alternative Wiederherstellung";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Alternative Wiederherstellung";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Nutze Deinen Wiederherstellungsschlüssel, um alle Deine Nachrichten zu entschlüsseln.";
"key_verification_verified_new_session_information" = "Du kannst nun sichere Nachrichten auf deinem neuen Gerät lesen. Andere Benutzer wissen, dass sie es vertrauen können.";
"key_verification_verified_this_session_information" = "Deine Chats wurden erfolgreich wiederhergestellt.";
"key_verification_tile_request_alert_title" = "Verifizierung angefragt";
// MARK: - Secrets Recovery
@@ -378,7 +384,7 @@
"room_intro_cell_information_dm_sentence1_part1" = "Das ist der Anfang deiner Direktnachricht mit ";
"room_avatar_view_accessibility_hint" = "Raumbild ändern";
"room_avatar_view_accessibility_label" = "Profilbild";
"room_details_permalink" = "Raum teilen";
"room_details_permalink" = "Link zum Raum kopieren";
"settings_enable_notification_times" = "Benachrichtigungszeiten";
"user_avatar_view_accessibility_hint" = "Profilbild ändern";
+21 -2
View File
@@ -1628,7 +1628,7 @@
"room_event_action_view_in_room" = "Im Raum anzeigen";
"location_sharing_open_open_street_maps" = "In OpenStreetMap öffnen";
"onboarding_use_case_title" = "Mit wem wirst du am meisten schreiben?";
"onboarding_use_case_message" = "Wir helfen dir, dich zu verbinden";
"onboarding_use_case_message" = "Wir helfen dir, dich zu vernetzen";
"onboarding_use_case_personal_messaging" = "Freunde und Familie";
"onboarding_use_case_work_messaging" = "Teams";
"onboarding_use_case_community_messaging" = "Gemeinschaften";
@@ -2638,7 +2638,7 @@
// Send Media Actions
"wysiwyg_composer_start_action_media_picker" = "Fotobibliothek";
"settings_labs_enable_wysiwyg_composer" = "Probiere den Rich-Text-Editor aus (bald auch mit Plain-Text-Modus)";
"settings_labs_enable_wysiwyg_composer" = "Probiere den Textverarbeitungs-Editor aus";
"wysiwyg_composer_start_action_voice_broadcast" = "Sprachübertragung";
"voice_broadcast_already_in_progress_message" = "Du zeichnest bereits eine Sprachübertragung auf. Bitte beende die laufende Übertragung, um eine neue zu beginnen.";
"voice_broadcast_blocked_by_someone_else_message" = "Jemand anderes nimmt bereits eine Sprachübertragung auf. Warte auf das Ende der Übertragung, bevor du eine neue startest.";
@@ -2651,3 +2651,22 @@
"deselect_all" = "Alle abwählen";
"user_other_session_menu_select_sessions" = "Sitzungen auswählen";
"user_other_session_selected_count" = "%@ ausgewählt";
"user_other_session_menu_sign_out_sessions" = "Von %@ Sitzungen abmelden";
"manage_session_sign_out_other_sessions" = "Von allen anderen Sitzungen abmelden";
"user_sessions_hide_location_info" = "IP-Adresse ausblenden";
"user_sessions_show_location_info" = "IP-Adresse anzeigen";
"voice_broadcast_tile" = "Sprachübertragung";
"voice_broadcast_live" = "Live";
"user_session_verified_session_description" = "Auf verifizierte Sitzungen kannst du überall mit Element zugreifen, wenn du deine Passphrase eingegeben oder Element mit einer anderen Sitzung verifiziert hast.\n\nDies bedeutet, dass du alle Schlüssel zum Entsperren deiner verschlüsselten Nachrichten hast und anderen bestätigst, dieser Sitzung zu vertrauen.";
"user_session_got_it" = "Verstanden";
"user_session_rename_session_description" = "Andere Nutzer in Direktnachrichten und Räumen, in denen du dich befindest, können eine vollständige Liste deiner Sitzungen einsehen.\n\nDies gibt ihnen die Sicherheit, dass sie auch wirklich mit dir kommunizieren. Allerdings bedeutet es auch, dass sie die Sitzungsnamen sehen können, die du hier angibst.";
"user_session_rename_session_title" = "Sitzungen umbenennen";
"user_session_inactive_session_description" = "Inaktive Sitzungen sind jene, die du einige Zeit nicht mehr verwendet hast, die aber weiterhin Verschlüsselungs-Schlüssel erhalten.\n\nDas Löschen von inaktiven Sitzungen verbessert Sicherheit und Leistung, und hilft dir zu erkennen, ob eine neue Sitzung verdächtig ist.";
"user_session_inactive_session_title" = "Inaktive Sitzungen";
"user_session_unverified_session_description" = "Nicht verifizierte Sitzungen sind jene, die angemeldet, aber nicht quer signiert sind.\n\nDu solltest besonders sicherstellen, dass du diese Sitzungen erkennst, da sie auf eine nicht autorisierte Nutzung deines Kontos hindeuten könnten.";
"user_session_unverified_session_title" = "Nicht verifizierte Sitzungen";
"user_session_verified_session_title" = "Verifizierte Sitzungen";
"key_verification_alert_body" = "Überprüfe sie, um ein sicheres Konto gewährleisten zu können.";
// Unverified sessions
"key_verification_alert_title" = "Du hast nicht verifizierte Sitzungen";
+21 -4
View File
@@ -132,7 +132,8 @@
// MARK: - Room Participants
"room_participants_cant_leave_prompt_message" = "You cannot leave the room because there are no other admins in the room.";
"room_participants_action_permalink" = "Share user";
"room_participants_action_permalink" = "Share user link";
"room_event_action_permalink" = "Share message link";
"bwi_room_participants_section_admin" = "Admin";
"bwi_room_participants_section_moderator" = "Moderator";
"bwi_room_participants_section_member" = "Member";
@@ -160,7 +161,7 @@
// MARK: - Room Details
"room_details_permalink" = "Share room";
"room_details_permalink" = "Share room link";
"room_details_access_section_access_toggle_bw" = "Public room";
// MARK: - Image Picker
@@ -184,11 +185,23 @@
// MARK: - Device Verification
"key_verification_this_session_title" = "Recovery Key";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Use recovery key";
"key_verification_verify_qr_code_title" = "Verify this session";
"key_verification_this_session_title" = "Verify this session";
"device_verification_self_verify_wait_title" = "Verify this session";
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Other recovery method";
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Other recovery method";
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Use your recovery key to decrypt all your messages.";
"device_verification_self_verify_wait_information" = "Verify your login with a device you are already logged in with to access your encrypted messages.";
"device_verification_self_verify_wait_information_more" = "";
"device_verification_verified_title" = "Completed!";
"device_verification_verified_got_it_button" = "Finish";
"device_verification_cancelled" = "Verification process cancelled. You can restart it again.";
"device_verification_self_verify_alert_message" = "Confirm new login on your device: %@";
"key_verification_verified_this_session_information" = "Your chats have been successfully decrypted.";
"key_verification_verify_qr_code_information_other_device" = "Scan code either with this device or another.";
"key_verification_verify_qr_code_cannot_scan_action" = "Compare with emojis instead";
"key_verification_tile_request_alert_title" = "Verification requested";
// MARK: - Secrets Recovery
@@ -218,7 +231,11 @@
// MARK: - PIN Protection
"pin_protection_confirm_pin" = "Confirm your PIN";
"pin_protection_confirm_pin_to_change" = "Confirm PIN to change PIN";
"pin_protection_settings_section_header_x" = "PIN";
"pin_protection_choose_pin_welcome_after_login" = "Welcome!";
"pin_protection_choose_pin_welcome_after_register" = "Welcome!";
// MARK: - Biometrics Protection
@@ -19,4 +19,3 @@
// MARK: Onboarding Personalization WIP
"image_picker_action_files" = "Choose from files";
"voice_broadcast_in_timeline_title" = "Voice broadcast detected (under active development)";
+36 -6
View File
@@ -255,6 +255,10 @@
"password_validation_error_contain_number" = "Contain a number.";
"password_validation_error_contain_symbol" = "Contain a symbol.";
// MARK: Password policy errors
"password_policy_too_short_pwd_error" = "Too short password";
"password_policy_weak_pwd_error" = "This password is too weak. It must contain at least 8 characters, with at least one character of each type: uppercase, lowercase, digit and special character.";
"password_policy_pwd_in_dict_error" = "This password has been found in a dictionary, and is not allowed.";
// MARK: Legacy Authentication
"auth_login" = "Log in";
@@ -790,14 +794,14 @@ Tap the + to start adding people.";
"settings_labs_message_reaction" = "React to messages with emoji";
"settings_labs_enable_ringing_for_group_calls" = "Ring for group calls";
"settings_labs_enabled_polls" = "Polls";
"settings_labs_enable_threads" = "Threaded messaging";
"settings_labs_enable_threads" = "Threaded messages";
"settings_labs_enable_auto_report_decryption_errors" = "Auto Report Decryption Errors";
"settings_labs_use_only_latest_user_avatar_and_name" = "Show latest avatar and name for users in message history";
"settings_labs_enable_live_location_sharing" = "Live location sharing - share current location (active development, and temporarily, locations persist in room history)";
"settings_labs_enable_new_session_manager" = "New session manager";
"settings_labs_enable_new_client_info_feature" = "Record the client name, version, and url to recognise sessions more easily in session manager";
"settings_labs_enable_new_app_layout" = "New Application Layout";
"settings_labs_enable_wysiwyg_composer" = "Try out the rich text editor (plain text mode coming soon)";
"settings_labs_enable_wysiwyg_composer" = "Try out the rich text editor";
"settings_labs_enable_voice_broadcast" = "Voice broadcast (under active development)";
"settings_version" = "Version %@";
@@ -936,7 +940,7 @@ Tap the + to start adding people.";
"manage_session_not_trusted" = "Not trusted";
"manage_session_sign_out" = "Sign out of this session";
"manage_session_rename" = "Rename session";
"manage_session_sign_out_other_sessions" = "Sign out of all other sessions";
// User sessions management
"user_sessions_settings" = "Manage sessions";
@@ -1548,9 +1552,8 @@ Tap the + to start adding people.";
"key_verification_self_verify_current_session_alert_validate_action" = "Verify";
// Unverified sessions
"key_verification_self_verify_unverified_sessions_alert_title" = "Review where you're logged in";
"key_verification_self_verify_unverified_sessions_alert_message" = "Verify all your sessions to ensure your account & messages are safe.";
"key_verification_alert_title" = "You have unverified sessions";
"key_verification_alert_body" = "Review to ensure your account is safe.";
"key_verification_self_verify_unverified_sessions_alert_validate_action" = "Review";
// MARK: Self verification wait
@@ -1969,6 +1972,12 @@ Tap the + to start adding people.";
"call_transfer_error_title" = "Error";
"call_transfer_error_message" = "Call transfer failed";
// MARK: - Launch loading
"launch_loading_server_syncing" = "Syncing with the server";
"launch_loading_server_syncing_nth_attempt" = "Syncing with the server\n(%@ attempt)";
"launch_loading_processing_response" = "Processing data\n%@ %%";
// MARK: - Home
"home_empty_view_title" = "Welcome to %@,\n%@";
@@ -2195,6 +2204,13 @@ Tap the + to start adding people.";
"voice_broadcast_blocked_by_someone_else_message" = "Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one.";
"voice_broadcast_already_in_progress_message" = "You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.";
"voice_broadcast_playback_loading_error" = "Unable to play this voice broadcast.";
"voice_broadcast_live" = "Live";
"voice_broadcast_tile" = "Voice broadcast";
"voice_broadcast_time_left" = "%@ left";
"voice_broadcast_buffering" = "Buffering...";
"voice_broadcast_stop_alert_title" = "Stop live broadcasting?";
"voice_broadcast_stop_alert_description" = "Are you sure you want to stop your live broadcast? This will end the broadcast, and the full recording will be available in the room.";
"voice_broadcast_stop_alert_agree_button" = "Yes, stop";
// Mark: - Version check
@@ -2421,6 +2437,8 @@ To enable access, tap Settings> Location and select Always";
"user_sessions_overview_other_sessions_section_title" = "Other sessions";
"user_sessions_overview_other_sessions_section_info" = "For best security, verify your sessions and sign out from any session that you dont recognize or use anymore.";
"user_sessions_show_location_info" = "Show IP address";
"user_sessions_hide_location_info" = "Hide IP address";
"user_sessions_overview_current_session_section_title" = "Current session";
"user_sessions_overview_link_device" = "Link a device";
@@ -2441,9 +2459,20 @@ To enable access, tap Settings> Location and select Always";
"user_session_unverified_additional_info" = "Verify your current session for enhanced secure messaging.";
"user_session_verification_unknown_additional_info" = "Verify your current session to reveal this session's verification status.";
"user_other_session_unverified_additional_info" = "Verify or sign out from this session for best security and reliability.";
"user_other_session_permanently_unverified_additional_info" = "This session doesnt support encryption and thus can't be verified.";
"user_other_session_verified_additional_info" = "This session is ready for secure messaging.";
"user_session_push_notifications" = "Push notifications";
"user_session_push_notifications_message" = "When turned on, this session will receive push notifications.";
"user_session_got_it" = "Got it";
"user_session_verified_session_title" = "Verified sessions";
"user_session_verified_session_description" = "Verified sessions are anywhere you are using Element after entering your passphrase or confirming your identity with another verified session.\n\nThis means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session.";
"user_session_unverified_session_title" = "Unverified session";
"user_session_unverified_session_description" = "Unverified sessions are sessions that have logged in with your credentials but not been cross-verified.\n\nYou should make especially certain that you recognise these sessions as they could represent an unauthorised use of your account.";
"user_session_permanently_unverified_session_description" = "This session doesn't support encryption, so it can't be verified.\n\nYou won't be able to participate in rooms where encryption is enabled when using this session.\n\nFor best security and privacy, it is recommended to use Matrix clients that support encryption.";
"user_session_inactive_session_title" = "Inactive sessions";
"user_session_inactive_session_description" = "Inactive sessions are sessions you have not used in some time, but they continue to receive encryption keys.\n\nRemoving inactive sessions improves security and performance, and makes it easier for you to identify if a new session is suspicious.";
"user_session_rename_session_title" = "Renaming sessions";
"user_session_rename_session_description" = "Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.";
"user_other_session_security_recommendation_title" = "Security recommendation";
"user_other_session_unverified_sessions_header_subtitle" = "Verify your sessions for enhanced secure messaging or sign out from those you dont recognize or use anymore.";
@@ -2462,6 +2491,7 @@ To enable access, tap Settings> Location and select Always";
"user_other_session_clear_filter" = "Clear filter";
"user_other_session_selected_count" = "%@ selected";
"user_other_session_menu_select_sessions" = "Select sessions";
"user_other_session_menu_sign_out_sessions" = "Sign out of %@ sessions";
// First item is client name and second item is session display name
"user_session_name" = "%@: %@";
+2 -2
View File
@@ -1,8 +1,8 @@
// Permissions usage explanations
"NSCameraUsageDescription" = "La cámara se usa para sacar fotos, vídeos y hacer videollamadas.";
"NSPhotoLibraryUsageDescription" = "La biblioteca de fotos se usa para enviar fotos y vídeos.";
"NSPhotoLibraryUsageDescription" = "Permite el acceso a fotos para subir fotos y vídeos desde tu galería.";
"NSMicrophoneUsageDescription" = "Element necesita usar tu micrófono para hacer y recibir llamadas y grabar vídeos y mensajes de voz.";
"NSContactsUsageDescription" = "Element te mostrará tus contactos para que les puedas invitar a una conversación.";
"NSContactsUsageDescription" = "Se compartirán con tu servidor de identidad para ayudarte a encontrar tus contactos en Matrix.";
"NSFaceIDUsageDescription" = "Face ID se usa para acceder a tu aplicación.";
"NSCalendarsUsageDescription" = "Mostrar tus reuniones en la aplicación.";
"NSLocationWhenInUseUsageDescription" = "Cuando compartes tu ubicación con otras personas, Element necesita acceso para que puedan verla en el mapa.";
+20 -1
View File
@@ -2575,7 +2575,7 @@
"manage_session_name_info" = "Palun arvesta, et sessioonide nimed on näha ka kõikidele osapooltele, kellega sa suhtled. %@";
"manage_session_name_hint" = "Sinu enda kirjutatud sessiooninimede alusel on sul oma seadmeid lihtsam ära tunda.";
"settings_labs_enable_voice_broadcast" = "Ringhäälingukõne (aktiivses arenduses)";
"settings_labs_enable_wysiwyg_composer" = "Proovi vormindatud teksti alusel töötavat tekstitoimetit (varsti lisandub ka vormindamata teksti režiim)";
"settings_labs_enable_wysiwyg_composer" = "Proovi vormindatud teksti alusel töötavat tekstitoimetit";
"authentication_qr_login_failure_retry" = "Proovi uuesti";
"authentication_qr_login_failure_request_timed_out" = "Sidumine ei lõppenud etteantud aja jooksul.";
"authentication_qr_login_failure_request_denied" = "Teine seade lükkas päringu tagasi.";
@@ -2589,3 +2589,22 @@
"deselect_all" = "Eemalda kõik valikud";
"user_other_session_menu_select_sessions" = "Vali sessioonid";
"user_other_session_selected_count" = "%@ valitud";
"user_other_session_menu_sign_out_sessions" = "Logi välja %@'st sessioonist";
"user_sessions_hide_location_info" = "Peida IP-aadress";
"user_sessions_show_location_info" = "Näita IP-aadressi";
"manage_session_sign_out_other_sessions" = "Logi välja kõikidest oma muudest sessioonidest";
"voice_broadcast_tile" = "Ringhäälingukõne";
"voice_broadcast_live" = "Otse eetris";
"user_session_rename_session_description" = "Teised osapooled nii otsesõnumites kui jututubades näevad sinu kõikide sessioonide loendit.\n\nSee tähendab, et nad võivad uskuda, et tegemist on tõesti sinuga. Samal ajal näevad ka siin sisestatud sessiooninime.";
"user_session_unverified_session_description" = "Verifitseerimata sessioonid on sellised, kuhu sa oled oma kasutajanime ja salasõnaga sisse loginud, kuid mille puhul on risttunnustamine tegemata.\n\nPalun kontrolli, et need on sulle teadaolevad sessioonid. Vastasel korral võib olla tegemist sinu kasutajakonto lubamatu kasutamisega.";
"user_session_rename_session_title" = "Sessioonide nimede muutmine";
"user_session_inactive_session_description" = "Mitteaktiivsed sessioonid on sellised, mida sa pole mõnda aega kasutanud, aga nad saavad jätkuvalt pärida sinu krüptovõtmeid.\n\nSelliste sessioonide eemaldamine parandab jõudlust ja turvalisust ning sul on lihtsam märgata, kui loendisse tekib midagi kahtlast.";
"user_session_inactive_session_title" = "Mitteaktiivsed sessioonid";
"user_session_unverified_session_title" = "Verifitseerimata sessioon";
"user_session_verified_session_description" = "Verifitseeritud sessioonideks loetakse Element'is või mõnes muus Matrix'i rakenduses selliseid sessioone, kus sa kas oled sisestanud oma salafraasi või tuvastanud end mõne teise oma verifitseeritud sessiooni abil.\n\nSee tähendab, et selles sessioonis on ka kõik vajalikud võtmed krüptitud sõnumite lugemiseks ja teistele kasutajatele kinnitamiseks, et sa usaldad seda sessiooni.";
"user_session_verified_session_title" = "Verifitseeritud sessioonid";
"user_session_got_it" = "Selge lugu";
"key_verification_alert_body" = "Tagamaks, et su konto on sinu kontrolli all, vaata andmed üle.";
// Unverified sessions
"key_verification_alert_title" = "Sul on verifitseerimata sessioone";
+10
View File
@@ -2605,3 +2605,13 @@
"authentication_qr_login_start_subtitle" = "Utilisez lappareil photo de cet appareil pour scanner le QR code affiché sur votre autre appareil :";
"authentication_qr_login_start_title" = "Scanner le QR code";
"authentication_login_with_qr" = "Se connecter avec un QR code";
"key_verification_alert_body" = "Passez les en revue pour vous assurer que votre compte nest pas compromis.";
// Unverified sessions
"key_verification_alert_title" = "Vous avez des sessions non-vérifiées";
"manage_session_sign_out_other_sessions" = "Déconnecter toutes les autres sessions";
"manage_session_name_info_link" = "Plus";
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Gardez en tête que les noms des sessions sont aussi visibles par les personnes avec qui vous communiquez. %@";
"manage_session_name_hint" = "Personnaliser les noms des sessions peut vous aider à reconnaître vos appareils plus facilement.";
"settings_labs_enable_wysiwyg_composer" = "Essayez le compositeur de messages visuel";
+20 -1
View File
@@ -2597,7 +2597,7 @@
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Fontos, hogy a munkamenet neve a kommunikációban résztvevők számára látható. %@";
"manage_session_name_hint" = "Az egyedi munkamenet név segíthet az eszköz könnyebb felismerésében.";
"settings_labs_enable_wysiwyg_composer" = "Próbálja ki az új szövegbevitelt (hamarosan érkezik a sima szöveges üzemmód)";
"settings_labs_enable_wysiwyg_composer" = "Próbálja ki az új szövegbevitelt";
"settings_labs_enable_new_client_info_feature" = "Kliens neve, verziója és url felvétele a munkamenet könnyebb azonosításához a munkamenet kezelőben";
"settings_labs_enable_new_session_manager" = "Új munkamenet kezelő";
"authentication_qr_login_failure_retry" = "Próbáld újra";
@@ -2637,3 +2637,22 @@
"deselect_all" = "Semmit nem jelöl ki";
"user_other_session_menu_select_sessions" = "Munkamenetek kiválasztása";
"user_other_session_selected_count" = "%@ kiválasztva";
"user_other_session_menu_sign_out_sessions" = "Kijelentkezés %@ munkamenetből";
"user_sessions_hide_location_info" = "IP címek elrejtése";
"user_sessions_show_location_info" = "IP címek megjelenítése";
"manage_session_sign_out_other_sessions" = "Kijelentkezés minden más munkamenetből";
"user_session_verified_session_description" = "Mindenhol ellenőrzött munkamenetek vannak ahol Elementet használva megadtad a jelmondatodat vagy egy másik már hitelesített munkamenetből megerősítetted az identitásodat.\n\nEz azt jelenti, hogy a titkosított üzenetek visszafejtéséhez rendelkezel a kulcsokkal és megerősíted a többiek felé, hogy megbízol a munkamenetben.";
// Unverified sessions
"key_verification_alert_title" = "Ellenőrizetlen bejelentkezései vannak";
"user_session_rename_session_description" = "Más felhasználók akikkel közvetlenül vagy szobában beszélgetsz látják a teljes listát a munkameneteidről.\n\nEzzel ők biztosak lehetnek abban, hogy ténylegesen veled beszélgetnek. Ez azt is jelenti, hogy látják a munkamenet nevét amit itt megadsz.";
"user_session_rename_session_title" = "Munkamenet átnevezése";
"user_session_inactive_session_description" = "Az inaktív munkamenetek azok amiket egy ideje nem használtál, de továbbra is megkapják a titkosítási kulcsokat.\n\nA nem aktív munkamenetek törlésével növelhető a biztonság és a sebesség valamint könnyebb lesz felismerni a gyanús munkameneteket.";
"user_session_inactive_session_title" = "Nem aktív munkamenetek";
"user_session_unverified_session_description" = "Az ellenőrizetlen munkamenetek azok amikre a felhasználói neveddel és jelszavaddal léptek be de nem lett ellenőrizve.\n\nMindenképpen győződj meg arról, hogy felismered ezeket a munkameneteket mert lehet, hogy illetéktelenül használják a fiókodat.";
"user_session_unverified_session_title" = "Ellenőrizetlen munkamenet";
"user_session_verified_session_title" = "Hitelesített munkamenetek";
"user_session_got_it" = "Értem";
"voice_broadcast_tile" = "Hang közvetítés";
"voice_broadcast_live" = "Élő";
"key_verification_alert_body" = "Tekintsd át, hogy meggyőződj arról, hogy a fiókod biztonságban van.";
+20 -1
View File
@@ -2831,7 +2831,7 @@
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Harap diketahui bahwa nama sesi juga terlihat ke orang-orang yang Anda berkomunikasi. %@";
"manage_session_name_hint" = "Nama sesi khusus dapat membantu Anda mengenal perangkat Anda dengan lebih mudah.";
"settings_labs_enable_wysiwyg_composer" = "Coba editor teks kaya (mode teks biasa akan datang)";
"settings_labs_enable_wysiwyg_composer" = "Coba editor teks kaya";
"wysiwyg_composer_start_action_voice_broadcast" = "Siaran suara";
"voice_broadcast_playback_loading_error" = "Tidak dapat memainkan siaran suara ini.";
"voice_broadcast_already_in_progress_message" = "Anda saat ini merekam sebuah siaran suara. Mohon akhiri siaran suara Anda saat ini untuk memulai yang baru.";
@@ -2844,3 +2844,22 @@
"deselect_all" = "Batalkan Semua Pilihan";
"user_other_session_menu_select_sessions" = "Pilih sesi";
"user_other_session_selected_count" = "%@ dipilih";
"user_other_session_menu_sign_out_sessions" = "Keluar dari %@ sesi";
"manage_session_sign_out_other_sessions" = "Keluarkan semua sesi lain";
"user_sessions_hide_location_info" = "Sembunyikan alamat IP";
"user_sessions_show_location_info" = "Tampilkan alamat IP";
"voice_broadcast_tile" = "Siaran suara";
"voice_broadcast_live" = "Langsung";
"user_session_rename_session_description" = "Pengguna lain dalam pesan langsung dan ruangan yang Anda bergabung dapat melihat daftar sesi Anda yang lengkap.\n\nIni memberikan mereka kepastian bahwa mereka berbicara dengan Anda, tetapi ini juga berarti bahwa mereka dapat melihat nama sesi yang Anda masukkan di sini.";
"user_session_rename_session_title" = "Mengubah nama sesi";
"user_session_inactive_session_description" = "Sesi yang tidak aktif adalah sesi yang Anda tidak gunakan dalam beberapa waktu, tetapi mereka masih mendapatkan kunci enkripsi.\n\nMenghapus sesi yang sudah tidak aktif meningkatkan keamanan dan performa, dan membuatnya lebih mudah untuk mengenal jika sebuah sesi baru.";
"user_session_inactive_session_title" = "Sesi tidak aktif";
"user_session_unverified_session_description" = "Sesi yang belum diverifikasi adalah sesi yang telah masuk dengan kredensial Anda tetapi belum diverifikasi secara silang.\n\nAnda seharusnya yakin bahwa Anda mengenal sesi ini karena mereka bisa saja berarti seseorang menggunakan akun Anda.";
"user_session_unverified_session_title" = "Sesi belum diverifikasi";
"user_session_verified_session_title" = "Sesi terverifikasi";
"user_session_verified_session_description" = "Sesi terverifikasi ada di mana pun Anda menggunakan Element setelah memasukkan frasa sandi atau mengonfirmasi identitas Anda dengan sesi terverifikasi lainnya.\n\nIni berarti Anda memiliki semua kunci yang diperlukan untuk membuka kunci pesan terenkripsi dan mengonfirmasi kepada pengguna lain bahwa Anda memercayai sesi ini.";
"user_session_got_it" = "Mengerti";
"key_verification_alert_body" = "Periksa untuk memastikan akun Anda aman.";
// Unverified sessions
"key_verification_alert_title" = "Anda punya sesi yang belum diverifikasi";
+20 -1
View File
@@ -2604,7 +2604,7 @@
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Ricorda che i nomi di sessione sono anche visibili alle persone con cui comunichi. %@";
"manage_session_name_hint" = "I nomi di sessione personalizzati possono aiutarti a riconoscere i tuoi dispositivi più facilmente.";
"settings_labs_enable_wysiwyg_composer" = "Prova l'editor in rich text (il testo semplice è in arrivo)";
"settings_labs_enable_wysiwyg_composer" = "Prova l'editor in rich text";
"settings_labs_enable_voice_broadcast" = "Trasmissione vocale (in sviluppo attivo)";
"wysiwyg_composer_start_action_voice_broadcast" = "Trasmissione vocale";
"voice_broadcast_playback_loading_error" = "Impossibile avviare questa trasmissione vocale.";
@@ -2617,3 +2617,22 @@
"deselect_all" = "Deseleziona tutti";
"user_other_session_menu_select_sessions" = "Seleziona sessioni";
"user_other_session_selected_count" = "%@ selezionate";
"user_other_session_menu_sign_out_sessions" = "Disconnetti da %@ sessioni";
"user_sessions_hide_location_info" = "Nascondi indirizzo IP";
"user_sessions_show_location_info" = "Mostra indirizzo IP";
"manage_session_sign_out_other_sessions" = "Disconnetti da tutte le altre sessioni";
"user_session_rename_session_description" = "Gli altri utenti nei messaggi diretti e nelle stanze in cui entri, possono vedere una lista completa delle tue sessioni.\n\nIn questo modo hanno la certezza che stanno parlando davvero con te, ma significa anche che possono vedere il nome della sessione che inserisci qui.";
"user_session_rename_session_title" = "Rinominare le sessioni";
"user_session_inactive_session_description" = "Le sessioni inattive sono quelle che non usi da un po' di tempo, ma che continuano a ricevere chiavi di crittografia.\n\nLa rimozione di sessioni inattive migliora la sicurezza e le prestazioni, e ti rende più facile capire se una sessione nuova è sospetta.";
"user_session_inactive_session_title" = "Sessioni inattive";
"user_session_unverified_session_description" = "Le sessioni non verificate sono quelle in cui è stato fatto l'accesso con le tue credenziali, ma che non sono state verificate.\n\nDovresti essere particolarmente sicuro di riconoscere queste sessioni dato che potrebbero rappresentare un uso non autorizzato del tuo account.";
"user_session_unverified_session_title" = "Sessione non verificata";
"user_session_verified_session_description" = "Le sessioni verificate sono ovunque usi Element dopo l'inserimento della password o la conferma della tua identità con un'altra sessione verificata.\n\nCiò significa che hai tutte le chiavi necessarie per sbloccare i tuoi messaggi cifrati e per confermare agli altri utenti che ti fidi di questa sessione.";
"user_session_verified_session_title" = "Sessioni verificate";
"user_session_got_it" = "Capito";
"voice_broadcast_tile" = "Trasmissione vocale";
"voice_broadcast_live" = "In diretta";
"key_verification_alert_body" = "Controlla per assicurarti che l'account sia sicuro.";
// Unverified sessions
"key_verification_alert_title" = "Hai sessioni non verificate";
+32 -26
View File
@@ -25,7 +25,7 @@
"preview" = "プレビュー";
"camera" = "カメラ";
"voice" = "音声";
"video" = "映像";
"video" = "動画";
"active_call" = "通話開始";
"active_call_details" = "通話開始(%@";
"later" = "後で";
@@ -133,8 +133,8 @@
"search_in_progress" = "検索しています…";
// Directory
"directory_cell_title" = "ルーム一覧を見る";
"directory_cell_description" = "%tu ルーム";
"directory_search_results_title" = "ルーム一覧検索結果";
"directory_cell_description" = "%tuつのルーム";
"directory_search_results_title" = "ルーム一覧検索結果";
"directory_searching_title" = "ルーム一覧を検索しています…";
"directory_search_fail" = "一覧を取得できませんでした";
// Contacts
@@ -492,13 +492,13 @@
// Group Details
"group_details_title" = "コミュニティーの詳細";
"group_details_home" = "ホーム";
"group_details_people" = "人々";
"group_details_people" = "連絡先";
"group_details_rooms" = "ルーム";
// Group Home
"group_home_one_member_format" = "1メンバー";
"group_home_multi_members_format" = "%tuメンバー";
"group_home_one_room_format" = "1ルーム";
"group_home_multi_rooms_format" = "%tuルーム";
"group_home_one_member_format" = "1名のメンバー";
"group_home_multi_members_format" = "%tu名のメンバー";
"group_home_one_room_format" = "1つのルーム";
"group_home_multi_rooms_format" = "%tuつのルーム";
"group_invitation_format" = "%@がこのコミュニティーにあなたを招待しました";
// Group participants
"group_participants_add_participant" = "参加者を追加";
@@ -529,7 +529,7 @@
"e2e_room_key_request_ignore_request" = "要求を無視";
// GDPR
"gdpr_consent_not_given_alert_message" = "%@ホームサーバーを引き続き使用するには、利用規約を確認して同意する必要があります。";
"gdpr_consent_not_given_alert_review_now_action" = "今レビュー";
"gdpr_consent_not_given_alert_review_now_action" = "確認";
"deactivate_account_title" = "無効なアカウント";
"deactivate_account_informations_part1" = "これにより、アカウントは永久に使用できなくなります。ログインすることはできず、誰も同じユーザーIDを再登録することはできません。これにより、あなたのアカウントは参加している全てのルームから退去し、あなたのIDサーバーからアカウントの詳細が削除されます。 ";
"deactivate_account_informations_part2_emphasize" = "この動作は元に戻せません。";
@@ -563,7 +563,7 @@
// MARK: - Room Info
"room_info_list_one_member" = "1のメンバー";
"room_info_list_one_member" = "1のメンバー";
"create_room_placeholder_address" = "#testroom:matrix.org";
"create_room_section_header_address" = "アドレス";
"create_room_show_in_directory" = "ルーム一覧に掲載";
@@ -1541,7 +1541,7 @@
"room_intro_cell_information_room_without_topic_sentence2_part1" = "トピックを追加";
"security_settings_secure_backup_restore" = "バックアップから復元";
"settings_device_notifications" = "端末の通知";
"settings_contacts_enable_sync" = "連絡先を探す";
"settings_contacts_enable_sync" = "連絡先を検索";
"settings_analytics_and_crash_data" = "クラッシュ・分析データを送信";
"settings_ui_theme_picker_message_invert_colours" = "「自動」は端末の色の「反転」設定を使用します";
"settings_ui_theme_picker_message_match_system_theme" = "「自動」は端末と同じ外観を自動で使用します";
@@ -1587,7 +1587,7 @@
"biometrics_usage_reason" = "アプリを開くには認証が必要です";
"settings_sending_media" = "画像と動画の送信";
"invite_friends_share_text" = "%@ での連絡先: %@";
"side_menu_action_invite_friends" = "友だちを招待する";
"side_menu_action_invite_friends" = "友だちを招待";
"call_more_actions_change_audio_device" = "オーディオデバイスを変更";
"call_more_actions_dialpad" = "ダイヤルパッド";
"onboarding_splash_login_button_title" = "既にアカウントを持っています";
@@ -1670,8 +1670,8 @@
"sign_out_existing_key_backup_alert_title" = "サインアウトしてよろしいですか?";
"find_your_contacts_message" = "%@ であなたの連絡先を表示し、知人とのチャットを素早く始めます。";
"find_your_contacts_footer" = "この設定はいつでも無効にできます";
"find_your_contacts_button_title" = "連絡先を検索する";
"find_your_contacts_title" = "連絡先をリストアップする";
"find_your_contacts_button_title" = "連絡先を検索";
"find_your_contacts_title" = "連絡先をリストアップ";
// Mark: - Room avatar view
@@ -1679,7 +1679,7 @@
// MARK: - Invite friends
"invite_friends_action" = "友だちを %@ に招待する";
"invite_friends_action" = "友だちを %@ に招待";
"call_transfer_error_title" = "エラー";
"home_context_menu_mark_as_read" = "既読にする";
"home_context_menu_normal_priority" = "通常優先度";
@@ -1690,14 +1690,14 @@
// MARK: - Call Transfer
"call_transfer_title" = "転送";
"room_info_back_button_title" = "ルーム情報";
"create_room_processing" = "ルーム作成";
"create_room_processing" = "ルーム作成しています";
"call_transfer_users" = "ユーザー";
"home_context_menu_notifications" = "通知";
"home_context_menu_make_dm" = "連絡先に移動";
"home_context_menu_make_room" = "ルームに移動";
"leave_space_title" = "%@ を退出";
"room_participants_leave_success" = "ルームを退出しました";
"room_participants_leave_processing" = "退出";
"room_participants_leave_processing" = "退出しています";
"event_formatter_group_call_leave" = "退出";
"home_context_menu_leave" = "退出";
@@ -1756,15 +1756,15 @@
"room_notifs_settings_notify_me_for" = "以下の場合に通知";
"room_details_access_row_title" = "アクセス";
"room_details_notifs" = "通知";
"location_sharing_invalid_power_level_title" = "ライブ現在地共有に必要な権限がありません";
"settings_labs_enable_live_location_sharing" = "ライブ現在地共有 - 現在地を共有します (開発中の機能位置情報が一時的にルームの履歴に残ります)";
"location_sharing_invalid_power_level_title" = "位置情報(ライブ)の共有に必要な権限がありません";
"settings_labs_enable_live_location_sharing" = "位置情報(ライブ)の共有 - 現在の位置情報を共有(開発中の機能位置情報が一時的にルームの履歴に残ります";
"event_formatter_message_deleted" = "削除済みのメッセージ";
"home_context_menu_unfavourite" = "お気に入りから削除";
"home_context_menu_favourite" = "お気に入り";
"all_chats_user_menu_settings" = "ユーザー設定";
"all_chats_edit_layout_show_filters" = "フィルターを表示";
"all_chats_edit_layout_show_recents" = "最近使用したものを表示";
"all_chats_edit_layout_alphabetical_order" = "A-Z で並び替え";
"all_chats_edit_layout_alphabetical_order" = "アルファベット順で並び替え";
"all_chats_edit_layout_activity_order" = "アクティビティで並び替え";
"space_selector_create_space" = "スペースを作成";
"space_selector_empty_view_information" = "スペースは、ルームや連絡先をグループ化する方法です。以下からスペースを作成できます。";
@@ -1776,20 +1776,26 @@
// Mark: - All Chats
"all_chats_title" = "全てのチャット";
"location_sharing_live_loading" = "ライブ現在地共有を読み込み中...";
"location_sharing_live_loading" = "位置情報(ライブ)を読み込んでいます…";
"location_sharing_live_list_item_stop_sharing_action" = "停止";
"location_sharing_live_list_item_current_user_display_name" = "あなた";
"live_location_sharing_banner_stop" = "停止";
"live_location_sharing_ended" = "ライブ現在地共有が終了";
"live_location_sharing_banner_title" = "ライブ現在地共有が有効";
"live_location_sharing_ended" = "位置情報(ライブ)が終了しました";
"live_location_sharing_banner_title" = "位置情報(ライブ)が有効です";
"location_sharing_invalid_authorization_settings" = "設定";
// MARK: Live location sharing
"location_sharing_live_share_title" = "ライブ現在地共有";
"service_terms_modal_decline_button" = "拒否する";
"service_terms_modal_accept_button" = "同意する";
"location_sharing_live_share_title" = "位置情報(ライブ)を共有";
"service_terms_modal_decline_button" = "拒否";
"service_terms_modal_accept_button" = "同意";
"service_terms_modal_description_identity_server" = "この操作により、端末の連絡先にあなたの電話番号や電子メールを保存している人があなたを検索できるようになります。";
// Service terms
"service_terms_modal_title_message" = "続行するには、以下の利用規約に同意してください";
"service_terms_modal_information_title_integration_manager" = "インテグレーションマネージャー";
// Alert explaining what an identity server / integration manager is.
"service_terms_modal_information_title_identity_server" = "IDサーバー";
"location_sharing_invalid_power_level_message" = "位置情報(ライブ)の共有には適切な権限が必要です。";
"location_sharing_live_error" = "位置情報(ライブ)のエラー";
+13
View File
@@ -26,6 +26,19 @@
</style>
</head>
<body>
<div>
<p>
<b>Version 2.2.0</b>
</p>
<p>
<b>Bugfixes</b>
<ul>
<li/>Umfragen funktionierten nach einem erneuten Anmelden nicht mehr.
</ul>
</p>
</div>
<br>
<div>
<p>
<b>Version 2.1.0</b>
+7 -7
View File
@@ -16,10 +16,10 @@
// Permissions usage explanations
"NSCameraUsageDescription" = "De camera wordt gebruikt om te videobellen, of om foto's en video's te maken en te uploaden.";
"NSPhotoLibraryUsageDescription" = "Geef toegang tot foto's om foto's en video's uit uw bibliotheek te uploaden.";
"NSMicrophoneUsageDescription" = "Element heeft toegang nodig tot uw microfoon nodig voor oproepen, maken van video's en spraakberichten opnemen.";
"NSContactsUsageDescription" = "Ze worden gedeeld met uw identiteitsserver om uw contacten op Matrix te vinden.";
"NSCalendarsUsageDescription" = "Bekijk uw geplande afspraken in de app.";
"NSFaceIDUsageDescription" = "Face ID wordt gebruikt om toegang te krijgen tot uw app.";
"NSLocationWhenInUseUsageDescription" = "Wanneer u uw locatie deelt met mensen heeft Element toegang nodig om dit op een kaart te tonen.";
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Wanneer u locatie met mensen deelt, heeft Element toegang nodig om ze een kaart te laten zien.";
"NSPhotoLibraryUsageDescription" = "Geef toegang tot foto's om foto's en video's uit je bibliotheek te uploaden.";
"NSMicrophoneUsageDescription" = "Element heeft toegang nodig tot je microfoon nodig voor oproepen, maken van video's en spraakberichten opnemen.";
"NSContactsUsageDescription" = "Ze worden gedeeld met je identiteitsserver om je contacten op Matrix te vinden.";
"NSCalendarsUsageDescription" = "Bekijk jouw geplande afspraken in de app.";
"NSFaceIDUsageDescription" = "Face ID wordt gebruikt om toegang te krijgen tot je app.";
"NSLocationWhenInUseUsageDescription" = "Wanneer je jouw locatie deelt met mensen heeft Element toegang nodig om dit op een kaart te tonen.";
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Wanneer je jouw locatie met mensen deelt, heeft Element toegang nodig om ze een kaart te laten zien.";
+5 -5
View File
@@ -54,11 +54,11 @@
/** Invites **/
/* A user has invited you to a chat */
"USER_INVITE_TO_CHAT" = "%@ heeft u uitgenodigd om te chatten";
"USER_INVITE_TO_CHAT" = "%@ heeft je uitgenodigd om te chatten";
/* A user has invited you to an (unamed) group chat */
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ heeft u uitgenodigd in een groepschat";
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ heeft je uitgenodigd in een groepschat";
/* A user has invited you to a named room */
"USER_INVITE_TO_NAMED_ROOM" = "%@ heeft u in %@-kamer uitgenodigd";
"USER_INVITE_TO_NAMED_ROOM" = "%@ heeft je in %@-kamer uitgenodigd";
/** Calls **/
/* Incoming one-to-one voice call */
@@ -74,9 +74,9 @@
/* Incoming named video conference invite from a specific person */
"VIDEO_CONF_NAMED_FROM_USER" = "Video-groepsoproep van %@: %@";
/* A single unread message in a room */
"SINGLE_UNREAD_IN_ROOM" = "U heeft een bericht ontvangen in %@";
"SINGLE_UNREAD_IN_ROOM" = "Je hebt een bericht ontvangen in %@";
/* A single unread message */
"SINGLE_UNREAD" = "U heeft een bericht ontvangen";
"SINGLE_UNREAD" = "Je hebt een bericht ontvangen";
/* Message title for a specific person in a named room */
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ in %@";
/* Sticker from a specific person, not referencing a room. */
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -2605,7 +2605,7 @@
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Por favor esteja ciente que nomes de sessões também são visíveis a pessoas com quem você se comunica. %@";
"manage_session_name_hint" = "Nomes de sessões personalizados podem ajudar você a reconhecer seus dispositivos mais facilmente.";
"settings_labs_enable_wysiwyg_composer" = "Experimente o editor de texto rico (modo de texto puro vindo em breve)";
"settings_labs_enable_wysiwyg_composer" = "Experimente o editor de texto rico";
"wysiwyg_composer_start_action_voice_broadcast" = "Broadcast de voz";
"voice_broadcast_playback_loading_error" = "Incapaz de tocar este broadcast de voz.";
"voice_broadcast_already_in_progress_message" = "Você já está gravando um broadcast de voz. Por favor termine seu broadcast de voz atual para começar um novo.";
@@ -2618,3 +2618,9 @@
"deselect_all" = "Desselecionar Todas(os)";
"user_other_session_menu_select_sessions" = "Selecionar sessões";
"user_other_session_selected_count" = "%@ selecionadas";
"user_other_session_menu_sign_out_sessions" = "Fazer signout de %@ sessões";
"user_sessions_hide_location_info" = "Esconder endereço de IP";
"user_sessions_show_location_info" = "Mostrar endereço de IP";
"manage_session_sign_out_other_sessions" = "Fazer signout de todas as outras sessões";
"voice_broadcast_tile" = "Broadcast de voz";
"voice_broadcast_live" = "Ao vivo";
+3 -3
View File
@@ -1,8 +1,8 @@
// Permissions usage explanations
"NSCameraUsageDescription" = "Камера используется для съемки фото и видео, совершения видеозвонков.";
"NSPhotoLibraryUsageDescription" = "Галерея используется для отправки фото и видео.";
"NSCameraUsageDescription" = "Камера используется для совершения видеозвонков, съёмки и загрузки фотографий и видео.";
"NSPhotoLibraryUsageDescription" = "Разрешите доступ к фото для отправки фото и видео из вашей библиотеки.";
"NSMicrophoneUsageDescription" = "Element необходим доступ к вашему микрофону, чтобы совершать и принимать звонки, снимать видео и записывать голосовые сообщения.";
"NSContactsUsageDescription" = "Element покажет ваши контакты, чтобы вы могли пригласить их в чат.";
"NSContactsUsageDescription" = "Они будут переданы вашему серверу идентификации, чтобы помочь найти ваши контакты в Matrix.";
"NSCalendarsUsageDescription" = "Просматривайте запланированные встречи в приложении.";
"NSFaceIDUsageDescription" = "Face ID используется для доступа к вашему приложению.";
"NSLocationWhenInUseUsageDescription" = "Когда вы делитесь с людьми своим местоположением, Element необходим доступ, чтобы показать им карту.";
+11 -1
View File
@@ -2131,7 +2131,7 @@
"authentication_recaptcha_title" = "Вы человек?";
/* The placeholder will show the homeserver's domain */
"authentication_terms_message" = "Пожалуйста прочитайте условия и политику %@";
"authentication_terms_title" = "Политика сервера";
"authentication_terms_title" = "Политика приватности";
"authentication_verify_msisdn_invalid_phone_number" = "Недействительный номер телефона";
"authentication_verify_msisdn_waiting_button" = "Отправить код повторно";
/* The placeholder will show the phone number that was entered. */
@@ -2158,3 +2158,13 @@
"user_other_session_current_session_details" = "Текущая сессия";
"user_other_session_filter_menu_all" = "Все сессии";
"wysiwyg_composer_start_action_stickers" = "Наклейки";
"authentication_login_with_qr" = "Войти при помощи QR-кода";
"onboarding_avatar_message" = "Время добавить лицо к имени";
"onboarding_congratulations_home_button" = "На главную";
"invite_to" = "Пригласить в %@";
"authentication_qr_login_start_step3" = "Выберите «Соеденить устройство»";
"authentication_qr_login_start_step2" = "Зайдите в Настройки -> Безопасность и Приватность";
"authentication_qr_login_start_step1" = "Откройте Element на вашем другом устройстве";
"authentication_qr_login_start_subtitle" = "Используйте камеру на этом устройстве, чтобы сканировать QR-код, отображённый на вашем другом устройстве:";
"authentication_qr_login_start_title" = "Сканировать QR-код";
"authentication_terms_policy_url_error" = "Не получилось найти выбранные правила. Пожалуйста, попробуйте снова позже.";
+20 -1
View File
@@ -2827,7 +2827,7 @@
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Uvedomte si, že názvy relácií sú viditeľné aj pre ľudí, s ktorými komunikujete. %@";
"manage_session_name_hint" = "Vlastné názvy relácií vám pomôžu ľahšie rozpoznať vaše zariadenia.";
"settings_labs_enable_wysiwyg_composer" = "Vyskúšajte rozšírený textový editor (čistý textový režim sa objaví čoskoro)";
"settings_labs_enable_wysiwyg_composer" = "Vyskúšajte rozšírený textový editor";
"wysiwyg_composer_start_action_voice_broadcast" = "Hlasové vysielanie";
"voice_broadcast_already_in_progress_message" = "Už nahrávate hlasové vysielanie. Ukončite aktuálne hlasové vysielanie a spustite nové.";
"voice_broadcast_blocked_by_someone_else_message" = "Niekto iný už nahráva hlasové vysielanie. Počkajte, kým sa skončí jeho hlasové vysielanie, a potom spustite nové.";
@@ -2840,3 +2840,22 @@
"deselect_all" = "Zrušiť výber všetkých";
"user_other_session_selected_count" = "%@ vybratých";
"user_other_session_menu_select_sessions" = "Vyberte relácie";
"user_other_session_menu_sign_out_sessions" = "Odhlásiť sa z %@ relácií";
"user_sessions_hide_location_info" = "Skryť IP adresu";
"user_sessions_show_location_info" = "Zobraziť IP adresu";
"manage_session_sign_out_other_sessions" = "Odhlásiť zo všetkých ostatných relácií";
"voice_broadcast_tile" = "Hlasové vysielanie";
"voice_broadcast_live" = "Naživo";
"user_session_rename_session_description" = "Ostatní používatelia v priamych správach a miestnostiach, do ktorých sa pripojíte, si môžu pozrieť úplný zoznam vašich relácií.\n\nTo im poskytuje istotu, že komunikujú naozaj s vami, ale zároveň to znamená, že vidia názov relácie, ktorý sem zadáte.";
"user_session_rename_session_title" = "Premenovanie relácií";
"user_session_inactive_session_description" = "Neaktívne relácie sú relácie, ktoré ste určitý čas nepoužívali, ale naďalej dostávajú šifrovacie kľúče.\n\nOdstránenie neaktívnych relácií zvyšuje bezpečnosť a výkon a uľahčuje identifikáciu podozrivých nových relácií.";
"user_session_inactive_session_title" = "Neaktívne relácie";
"user_session_unverified_session_description" = "Neoverené relácie sú relácie, do ktorých ste sa prihlásili pomocou svojich prístupových údajov, ale ktoré neboli krížovo overené.\n\nMali by ste si byť obzvlášť istí, že tieto relácie poznáte, pretože by mohli predstavovať neoprávnené použitie vášho konta.";
"user_session_unverified_session_title" = "Neoverená relácia";
"user_session_verified_session_description" = "Overené relácie sú všade tam, kde používate Element po zadaní svojho prístupového hesla alebo po potvrdení svojej totožnosti inou overenou reláciou.\n\nTo znamená, že máte všetky kľúče potrebné na odomknutie zašifrovaných správ a potvrdenie pre ostatných používateľov, že tejto relácii dôverujete.";
"user_session_verified_session_title" = "Overené relácie";
"user_session_got_it" = "Rozumiem";
"key_verification_alert_body" = "Skontrolujte, či je vaše konto bezpečné.";
// Unverified sessions
"key_verification_alert_title" = "Máte neoverené relácie";
+3 -3
View File
@@ -1,8 +1,8 @@
// Permissions usage explanations
"NSCameraUsageDescription" = "Kamera përdoret për të bërë foto dhe regjistruar video, dhe për të bërë thirrje video.";
"NSPhotoLibraryUsageDescription" = "Fototeka përdoret për të dërguar foto dhe video.";
"NSCameraUsageDescription" = "Kamera përdoret për të bërë thirrje video, ose për të bërë dhe ngarkuar diku foto dhe video.";
"NSPhotoLibraryUsageDescription" = "Që të ngarkohen foto dhe video që nga mediateka juaj, lejoni hyrje te fotot.";
"NSMicrophoneUsageDescription" = "Element-it i duhet të përdorë mikrofonin tuaj për të bërë dhe marrë thirrje, për të regjistruar video, dhe për të regjistruar mesazhe zanorë.";
"NSContactsUsageDescription" = "Element-i do të shfaqë kontaktet tuaja, që kështu të mund ti ftoni për të biseduar.";
"NSContactsUsageDescription" = "Do ti jepen shërbyesit tuaj të identiteteve, për ta ndihmuar të gjejë kontakte tuajt në Matrix.";
"NSCalendarsUsageDescription" = "Shihini te aplikacioni takimet tuaja të planifikuara.";
"NSFaceIDUsageDescription" = "Face ID përdoret që të hyni në aplikacionin tuaj.";
"NSLocationWhenInUseUsageDescription" = "Kur ndani vendndodhjen tuaj me persona, Element-i ka nevojë për hyrje në të, që tu trgojë atyre një hartë.";
+214 -1
View File
@@ -2362,7 +2362,7 @@
"authentication_terms_policy_url_error" = "Sarrihet të gjendet rregulli i përzgjedhur. Ju lutemi, riprovoni.";
/* The placeholder will show the homeserver's domain */
"authentication_terms_message" = "Ju lutemi, lexoni kushte dhe rregulla të %@";
"authentication_terms_title" = "Rregulla shërbyesi";
"authentication_terms_title" = "Rregulla privatësie";
"authentication_verify_msisdn_invalid_phone_number" = "Numër telefoni i pavlefshëm";
"authentication_verify_msisdn_waiting_button" = "Ridërgomëni kodin";
/* The placeholder will show the phone number that was entered. */
@@ -2417,3 +2417,216 @@
// MARK: Authentication
"authentication_registration_title" = "Krijoni llogarinë tuaj";
"all_chats_onboarding_page_message3" = "Prekni profilin tuaj që të na bëni të ditur se ç’mendoni.";
"all_chats_edit_layout_add_section_message" = "Fiksoni ndarje te kreu, për hyrje të lehtë në ta";
"room_event_encryption_info_key_authenticity_not_guaranteed" = "Smund të garantohet mirëfilltësia e këtij mesazhi të fshehtëzuar në këtë pajisje.";
"deselect_all" = "Shpërzgjidhi Krejt";
"wysiwyg_composer_format_action_strikethrough" = "Apliko format me të nënvizuara";
"wysiwyg_composer_format_action_underline" = "Apliko format me të hequravije";
"wysiwyg_composer_format_action_italic" = "Apliko format me të pjerrta";
// Formatting Actions
"wysiwyg_composer_format_action_bold" = "Apliko format me të trasha";
"wysiwyg_composer_start_action_voice_broadcast" = "Transmetim zanor";
"wysiwyg_composer_start_action_text_formatting" = "Formatim Teksti";
"wysiwyg_composer_start_action_camera" = "Kamerë";
"wysiwyg_composer_start_action_location" = "Vendndodhje";
"wysiwyg_composer_start_action_polls" = "Pyetësorë";
"wysiwyg_composer_start_action_attachments" = "Bashkëngjitje";
"wysiwyg_composer_start_action_stickers" = "Ngjitës";
// Mark: - WYSIWYG Composer
// Send Media Actions
"wysiwyg_composer_start_action_media_picker" = "Fototekë";
"user_session_overview_session_details_button_title" = "Hollësi sesioni";
"user_session_overview_session_title" = "Sesion";
"user_session_overview_current_session_title" = "Sesioni i tanishëm";
"user_session_details_application_url" = "URL";
"user_session_details_application_version" = "Version";
"user_session_details_application_name" = "Emër";
"user_session_details_device_os" = "Sistem Operativ";
"user_session_details_device_browser" = "Shfletues";
"user_session_details_device_model" = "Model";
"user_session_details_device_ip_location" = "Venndodhje IP-je";
"user_session_details_device_ip_address" = "Adresë IP";
"user_session_details_last_activity" = "Veprimtaria e fundit";
"user_session_details_session_section_footer" = "Kopjoni çfarëdo të dhëne duke prekur mbi të dhe duke e mbajtur të shtypur.";
"user_session_details_session_id" = "ID Sesioni";
"user_session_details_session_name" = "Emër sesioni";
"user_session_details_device_section_header" = "Pajisje";
"user_session_details_application_section_header" = "Aplikacion";
"user_session_details_session_section_header" = "Sesion";
"user_session_details_title" = "Hollësi sesioni";
"device_type_name_unknown" = "E panjohur";
"device_type_name_mobile" = "Celular";
"device_type_name_web" = "Web";
"device_type_name_desktop" = "Desktop";
"device_name_unknown" = "Klient i panjohur";
"user_inactive_session_item_with_date" = "Joaktiv për 90 e ca ditë (%@)";
"user_inactive_session_item" = "Joaktiv për 90 e ca ditë";
"user_session_item_details_last_activity" = "Veprimtaria e fundit %@";
/* %1$@ will be the verification state and %2$@ will be user_session_item_details_verification_unknown or user_other_session_current_session_details */
"user_session_item_details" = "%1$@ · %2$@";
// First item is client name and second item is session display name
"user_session_name" = "%@: %@";
"user_other_session_menu_select_sessions" = "Përzgjidhni sesione";
"user_other_session_selected_count" = "%@ të përzgjedhur";
"user_other_session_clear_filter" = "Spastroje filtrin";
"user_other_session_no_unverified_sessions" = "Su gjetën sesione të paverifikuar.";
"user_other_session_no_verified_sessions" = "Su gjetën sesione të verifikuar.";
"user_other_session_no_inactive_sessions" = "Su gjetën sesione joaktive.";
"user_other_session_filter_menu_inactive" = "Joaktiv";
"user_other_session_filter_menu_unverified" = "I paverifikuar";
"user_other_session_filter_menu_verified" = "I verifikuar";
"user_other_session_filter_menu_all" = "Krejt sesionet";
"user_other_session_filter" = "Filtroji";
"user_other_session_verified_sessions_header_subtitle" = "Për sigurinë më të mirë, dilni nga çfarëdo sesioni që nuk e njihni apo përdorni më.";
"user_other_session_current_session_details" = "Sesioni juaj i tanishëm";
"user_other_session_unverified_sessions_header_subtitle" = "Verifikoni sesionet tuaj, për shkëmbim më të sigurt mesazhesh, ose dilni prej atyre që nuk i njihni, apo përdorni më.";
"user_other_session_security_recommendation_title" = "Rekomandim sigurie";
"user_session_push_notifications_message" = "Kur aktivizohet, ky sesion do të marrë njoftime push.";
"user_session_push_notifications" = "Njoftime Push";
"user_other_session_verified_additional_info" = "Ky sesion është gati për shkëmbim të sigurt mesazhesh.";
"user_other_session_unverified_additional_info" = "Për sigurinë dhe besueshmërinë më të mirë, verifikojeni, ose dilni nga ky sesion.";
"user_session_verification_unknown_additional_info" = "Verifikoni sesionin tuaj të tanishëm, që të shfaqni gjendjen e verifikimit të këtij sesioni.";
"user_session_unverified_additional_info" = "Verifikoni sesionin tuaj të tanishëm, për shkëmbim më të sigurt të mesazheve.";
"user_session_verified_additional_info" = "Sesioni juaj i tanishëm është gati për shkëmbim të sigurt mesazhesh.";
"user_session_learn_more" = "Mësoni më tepër";
"user_session_view_details" = "Shihni hollësitë";
"user_session_verify_action" = "Verifiko sesion";
"user_session_verification_unknown_short" = "I panjohur";
"user_session_unverified_short" = "I paverifikuar";
"user_session_verified_short" = "I verifikuar";
"user_session_verification_unknown" = "Gjendje e panjohur verifikimi";
"user_session_unverified" = "Sesion i paverifikuar";
"user_session_verified" = "Sesion i verifikuar";
"user_sessions_view_all_action" = "Shihini krejt (%d)";
"user_sessions_overview_link_device" = "Lidhni një pajisje";
"user_sessions_overview_current_session_section_title" = "Sesioni i tanishëm";
"user_sessions_overview_other_sessions_section_info" = "Për sigurinë më të mirë, verifikoni sesionet tuaja dhe dilni nga çfarëdo sesioni që se njihni, ose se përdorni më.";
"user_sessions_overview_other_sessions_section_title" = "Sesione të tjerë";
"user_sessions_overview_security_recommendations_inactive_info" = "Shihni mundësinë e daljes nga sesione të vjetër (90 ditë ose më tepër) të cilët si përdorni më.";
"user_sessions_overview_security_recommendations_inactive_title" = "Sesione joaktivë";
"user_sessions_overview_security_recommendations_unverified_info" = "Verifikojini, ose dilni nga sesione të paverifikuar.";
"user_sessions_overview_security_recommendations_unverified_title" = "Sesione të paverifikuar";
"user_sessions_overview_security_recommendations_section_info" = "Përmirësoni sigurinë e llogarisë tuaj duke ndjekur këto rekomandime.";
"user_sessions_overview_security_recommendations_section_title" = "Rekomandime sigurie";
"user_sessions_overview_title" = "Sesione";
// MARK: User sessions management
// Parameter is the application display name (e.g. "Element")
"user_sessions_default_session_display_name" = "%@ iOS";
"location_sharing_map_loading_error" = "Sarrihet të ngarkohet hartë\nKy shërbyes Home s’është formësuar të shfaqë harta";
"space_invite_nav_title" = "Ftesë për në hapësirë";
"space_detail_nav_title" = "Hollësi hapësire";
"space_selector_create_space" = "Krijo Hapësirë";
"space_selector_empty_view_information" = "Hapësirat janë një mënyrë e re për të grupuar dhoma dhe njerëz. Që tia filloni, krijoni një hapësirë.";
"space_selector_empty_view_title" = "Ende pa hapësira.";
// Mark: - Space Selector
"space_selector_title" = "Hapësirat e mia";
"room_invites_empty_view_information" = "Ky është vendi ku shfaqen ftesat tuaja.";
// Mark: - Room invites
"room_invites_empty_view_title" = "Ska gjë të re.";
"all_chats_onboarding_try_it" = "Provojeni";
"all_chats_onboarding_title" = "Ç’ka të re";
"all_chats_onboarding_page_title3" = "Jepni Përshtypje";
"all_chats_onboarding_page_message2" = "Hyni në Hapësirat tuaja (poshtë djathtas) më shpejt dhe më kollaj se kurrë më parë.";
"all_chats_onboarding_page_title2" = "Hyni Në Hapësira";
"all_chats_onboarding_page_message1" = "Që të thjeshtohet Element-i juaj, skedat tanimë janë opsionale. Administrojini duke përdorur menunë djathtas në krye.";
"all_chats_onboarding_page_title1" = "Mirë se vini te një pamje e re!";
"all_chats_edit_menu_space_settings" = "Rregullime hapësire";
"all_chats_edit_menu_leave_space" = "Braktise %@";
"all_chats_user_menu_settings" = "Rregullime përdoruesi";
"all_chats_user_menu_accessibility_label" = "Menu përdoruesi";
"room_recents_recently_viewed_section" = "Parë së fundi";
"all_chats_nothing_found_placeholder_message" = "Provoni të përimtoni kërkimin tuaj.";
"all_chats_nothing_found_placeholder_title" = "Su gjet gjë.";
"all_chats_empty_unreads_placeholder_message" = "Ky është vendi ku do të shfaqen mesazhet tuaj të palexuar, kur të ketë të tillë.";
"all_chats_empty_view_information" = "Aplikacioni “all-in-one” i fjalosjeve të siguruara, për ekipe, shokë dhe ente. Që tia filloni, krijoni një fjalosje, ose hyni në një dhomë ekzistuese.";
"all_chats_empty_space_information" = "Hapësirat janë një mënyrë e re për të grupuar dhoma dhe persona. Shtoni një dhomë ekzistuese, ose krijoni një të re, duke përdorur butonin poshtë djathtas.";
"all_chats_empty_view_title" = "%@\nduket paksa si i zbrazët.";
"all_chats_all_filter" = "Krejt";
"all_chats_edit_layout_alphabetical_order" = "Renditi si A-Z";
"all_chats_edit_layout_activity_order" = "Renditi sipas veprimtarish";
"all_chats_edit_layout_show_filters" = "Shfaq filtra";
"all_chats_edit_layout_show_recents" = "Shfaq të freskëta";
"all_chats_edit_layout_sorting_options_title" = "Renditi mesazhet sipas";
"all_chats_edit_layout_pin_spaces_title" = "Fiksoni hapësirat tuaja";
"all_chats_edit_layout_add_filters_title" = "Filtroni mesazhet tuaja";
"all_chats_edit_layout_add_section_title" = "Shtoni ndarje te kreu";
"all_chats_edit_layout_unreads" = "Të palexuara";
"all_chats_edit_layout_recents" = "Së fundi";
"all_chats_edit_layout" = "Parapëlqime skeme grafike";
"all_chats_section_title" = "Fjalosje";
// Mark: - All Chats
"all_chats_title" = "Krejt fjalosjet";
"voice_broadcast_playback_loading_error" = "Sarrihet të luhet ky transmetim zanor.";
"voice_broadcast_already_in_progress_message" = "Po incizoni tashmë një transmetim zanor. Ju lutemi, që të nisni një të ri, përfundoni transmetimin tuaj zanor të tanishëm.";
"voice_broadcast_blocked_by_someone_else_message" = "Dikush tjetër është duke incizuar një transmetim zanor. Që të nisni një të ri, prisni të përfundojë incizimi zanor i tij.";
"voice_broadcast_permission_denied_message" = "Skeni lejet e domosdoshme që të nisni një transmetim zanor në këtë dhomë. Lidhuni me një përgjegjës dhome që të përmirësoni lejet tuaja.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Sniset dot një transmetim zanor i ri";
"spaces_subspace_creation_visibility_message" = "Hapësira e krijuar do të shtohet te %@.";
"spaces_subspace_creation_visibility_title" = "Ç’lloj nënhapësire doni të krijoni?";
"spaces_explore_rooms_format" = "Eksploroni %@";
"spaces_create_subspace_title" = "Krijoni një nënhapësirë";
"spaces_add_subspace_title" = "Krijoni hapësirë brenda %@";
"sign_out_confirmation_message" = "Jeni i sigurt se doni të dilni?";
// MARK: Sign out warning
"sign_out" = "Dilni";
// User sessions management
"user_sessions_settings" = "Administroni sesione";
"manage_session_rename" = "Riemërtoni sesionin";
"manage_session_name_info_link" = "Mësoni më tepër";
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Ju lutemi, kini parasysh se emrat e sesioneve janë të dukshëm edhe për personat me të cilët komunikoni.%@";
"manage_session_name_hint" = "Emra vetjakë sesionesh mund tju ndihmojnë të njihni më kollaj pajisjet tuaja.";
"settings_labs_enable_voice_broadcast" = "Aktivizoni transmetim zanor (nën zhvillim aktiv)";
"settings_labs_enable_wysiwyg_composer" = "Provoni përpunuesin e teksteve të pasur (për tekst të thjeshtë vjen së shpejti)";
"settings_labs_enable_new_app_layout" = "Skemë e Re Aplikacioni";
"settings_labs_enable_new_client_info_feature" = "Regjistro emrin, versionin dhe URL-në e klientit, për të dalluar më kollaj sesionit te përgjegjës sesionesh";
"settings_labs_enable_new_session_manager" = "Përgjegjës i ri sesionesh";
"room_first_message_placeholder" = "Dërgoni mesazhin tuaj të parë…";
"authentication_qr_login_failure_retry" = "Riprovoni";
"authentication_qr_login_failure_request_timed_out" = "Lidhja su plotësua brenda kohës së domosdoshme.";
"authentication_qr_login_failure_request_denied" = "Kërkesa u hodh poshtë në pajisjen tjetër.";
"authentication_qr_login_failure_invalid_qr" = "Kodi QR është i pavlefshëm.";
"authentication_qr_login_failure_title" = "Lidhja dështoi";
"authentication_qr_login_loading_signed_in" = "Tani jeni i futur te pajisja juaj tjetër.";
"authentication_qr_login_loading_waiting_signin" = "Po pritet që të bëhet hyrja te pajisja.";
"authentication_qr_login_loading_connecting_device" = "Po lidhet me pajisjen";
"authentication_qr_login_confirm_alert" = "Ju lutemi, sigurohuni se e dini origjinën e këtij kodi. Duke lidhur pajisje, do ti jepni dikujt hyrje të plotë në llogarinë tuaj.";
"authentication_qr_login_confirm_subtitle" = "Ripohoni se kodi më poshtë përkon me atë në pajisjen tuaj tjetër:";
"authentication_qr_login_confirm_title" = "U vendos lidhje e siguruar";
"authentication_qr_login_scan_subtitle" = "Vendoseni kodin QR te kuadrati më poshtë";
"authentication_qr_login_scan_title" = "Skanoni kodin QR";
"authentication_qr_login_display_step2" = "Përzgjidhni “Hyni me kod QR”";
"authentication_qr_login_display_step1" = "Hapeni Element-in në pajisjen tuaj tjetër";
"authentication_qr_login_display_subtitle" = "Skanoni kodin QR më poshtë me pajisjen ku është bërë dalja.";
"authentication_qr_login_display_title" = "Lidhni një pajisje";
"authentication_qr_login_start_display_qr" = "Shfaq kod QR te kjo pajisje";
"authentication_qr_login_start_need_alternative" = "Ju duhet një metodë alternative?";
"authentication_qr_login_start_step4" = "Përzgjidhni “Shfaq kod QR në këtë pajisje”";
"authentication_qr_login_start_step3" = "Përzgjidhni “Lidhni një pajisje”";
"authentication_qr_login_start_step2" = "Kaloni te Rregullime -> Siguri & Privatësi";
"authentication_qr_login_start_step1" = "Hapeni Element-in në pajisjen tuaj tjetër";
"authentication_qr_login_start_subtitle" = "Përdorni kamerën në këtë pajisje që të skanoni kodin QR të shfaqur në pajisjen tuaj tjetër:";
"authentication_qr_login_start_title" = "Skanoni kodin QR";
"authentication_login_with_qr" = "Hyni me kod QR";
"invite_to" = "Ftojeni te %@";
"all_chats_empty_list_placeholder_title" = "Ska gjë tjetër për të parë.";
"all_chats_edit_layout_add_filters_message" = "Filtroni automatikisht mesazhet tuaj në kategori që caktoni vetë";
+27 -8
View File
@@ -2829,16 +2829,35 @@
/* The placeholder will be replaces with manage_session_name_info_link */
"manage_session_name_info" = "Зауважте, що назви сеансів також видно людям, з якими ви спілкуєтесь. %@";
"manage_session_name_hint" = "Власні назви сеансів допоможуть вам легше розпізнавати ваші пристрої.";
"settings_labs_enable_wysiwyg_composer" = "Спробуйте розширений текстовий редактор (незабаром з'явиться режим звичайного тексту)";
"wysiwyg_composer_start_action_voice_broadcast" = "Голосові повідомлення";
"voice_broadcast_playback_loading_error" = "Неможливо відтворити це голосове повідомлення.";
"voice_broadcast_already_in_progress_message" = "Ви вже записуєте голосове повідомлення. Завершіть поточну трансляцію, щоб розпочати нову.";
"voice_broadcast_blocked_by_someone_else_message" = "Хтось інший вже записує голосове повідомлення. Зачекайте, поки закінчиться трансляція, щоб розпочати нову.";
"voice_broadcast_permission_denied_message" = "Ви не маєте необхідних дозволів для початку трансляції голосового повідомлення в цій кімнаті. Зверніться до адміністратора кімнати, щоб оновити ваші дозволи.";
"settings_labs_enable_wysiwyg_composer" = "Спробуйте розширений текстовий редактор";
"wysiwyg_composer_start_action_voice_broadcast" = "Голосові трансляції";
"voice_broadcast_playback_loading_error" = "Неможливо відтворити цю голосову трансляцію.";
"voice_broadcast_already_in_progress_message" = "Ви вже записуєте голосову трансляцію. Завершіть поточну трансляцію, щоб розпочати нову.";
"voice_broadcast_blocked_by_someone_else_message" = "Хтось інший вже записує голосову трансляцію. Зачекайте, поки вона завершиться, щоб розпочати нову.";
"voice_broadcast_permission_denied_message" = "Ви не маєте необхідних дозволів для початку голосової трансляції в цій кімнаті. Зверніться до адміністратора кімнати, щоб оновити ваші дозволи.";
// Mark: - Voice broadcast
"voice_broadcast_unauthorized_title" = "Не вдалося розпочати трансляцію нового голосового повідомлення";
"settings_labs_enable_voice_broadcast" = "Голосові повідомлення (в активній розробці)";
"voice_broadcast_unauthorized_title" = "Не вдалося розпочати нову голосову трансляцію";
"settings_labs_enable_voice_broadcast" = "Голосові трансляції (в активній розробці)";
"deselect_all" = "Скасувати вибір усіх";
"user_other_session_menu_select_sessions" = "Вибрати сеанси";
"user_other_session_selected_count" = "Вибрано %@";
"user_other_session_menu_sign_out_sessions" = "Вийти з %@ сеансів";
"manage_session_sign_out_other_sessions" = "Вийти з усіх інших сеансів";
"user_sessions_hide_location_info" = "Сховати IP-адресу";
"user_sessions_show_location_info" = "Показати IP-адресу";
"voice_broadcast_tile" = "Голосові трансляції";
"voice_broadcast_live" = "Наживо";
"user_session_rename_session_description" = "Інші користувачі в особистих повідомленнях і кімнатах, до яких ви приєдналися, можуть переглядати повний список ваших сеансів.\n\nЦе дає їм впевненість у тому, що вони дійсно розмовляють з вами, а також означає, що вони можуть бачити назву сеансу, яку ви вводите сюди.";
"user_session_rename_session_title" = "Перейменовані сеанси";
"user_session_inactive_session_description" = "Неактивні сеанси — це сеанси, які ви не використовували протягом певного часу, але вони продовжують отримувати ключі шифрування.\n\nВилучення неактивних сеансів покращує безпеку та швидкодію, а також полегшує визначення підозрілих нових сеансів.";
"user_session_inactive_session_title" = "Неактивні сеанси";
"user_session_unverified_session_description" = "Не звірені сеанси — це сеанси, до яких ви ввійшли за допомогою ваших облікових даних, але не пройшли перехресну перевірку.\n\nВи повинні бути особливо впевнені, що розпізнаєте ці сеанси, оскільки вони можуть означати несанкціоноване використовування вашого облікового запису.";
"user_session_unverified_session_title" = "Не звірений сеанс";
"user_session_verified_session_description" = "Звірені сеанси — це будь-який пристрій, на якому ви використовуєте Element після введення парольної фрази або підтвердження вашої особи за допомогою іншого звіреного сеансу.\n\nЦе означає, що ви маєте всі ключі, необхідні для розблокування ваших зашифрованих повідомлень і підтвердження іншим користувачам, що ви довіряєте цьому сеансу.";
"user_session_verified_session_title" = "Звірені сеанси";
"user_session_got_it" = "Зрозуміло";
"key_verification_alert_body" = "Перегляньте їх, щоб переконатися, що ваш обліковий запис у безпеці.";
// Unverified sessions
"key_verification_alert_title" = "У вас є не звірені сеанси";
+25
View File
@@ -0,0 +1,25 @@
//
// Copyright 2022 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.
//
import Foundation
extension Date {
func daysBetween(date: Date) -> Int {
let components = Calendar.current.dateComponents([.day], from: self, to: date)
return components.day ?? 0
}
}
+60
View File
@@ -0,0 +1,60 @@
//
// Copyright 2022 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.
//
import MatrixSDK
extension MXError {
/// Returns custom localized message from errcode parameter of MXError.
func authenticationErrorMessage() -> String {
let message: String
switch self.errcode {
case kMXErrCodeStringForbidden:
message = VectorL10n.loginErrorForbidden
case kMXErrCodeStringUnknownToken:
message = VectorL10n.loginErrorUnknownToken
case kMXErrCodeStringBadJSON:
message = VectorL10n.loginErrorBadJson
case kMXErrCodeStringNotJSON:
message = VectorL10n.loginErrorBadJson
case kMXErrCodeStringLimitExceeded:
message = VectorL10n.loginErrorLimitExceeded
case kMXErrCodeStringUserInUse:
message = VectorL10n.loginErrorUserInUse
case kMXErrCodeStringLoginEmailURLNotYet:
message = VectorL10n.loginErrorLoginEmailNotYet
case kMXErrCodeStringThreePIDInUse:
message = VectorL10n.authEmailInUse
case kMXErrCodeStringPasswordTooShort:
message = VectorL10n.passwordPolicyTooShortPwdError
case kMXErrCodeStringPasswordNoDigit:
message = VectorL10n.passwordPolicyWeakPwdError
case kMXErrCodeStringPasswordNoLowercase:
message = VectorL10n.passwordPolicyWeakPwdError
case kMXErrCodeStringPasswordNoUppercase:
message = VectorL10n.passwordPolicyWeakPwdError
case kMXErrCodeStringPasswordNoSymbol:
message = VectorL10n.passwordPolicyWeakPwdError
case kMXErrCodeStringWeakPassword:
message = VectorL10n.passwordPolicyWeakPwdError
case kMXErrCodeStringPasswordInDictionary:
message = VectorL10n.passwordPolicyPwdInDictError
default:
message = self.error
}
return message
}
}
+34 -10
View File
@@ -583,27 +583,35 @@ public class BWIL10n: NSObject {
public static var createRoomPlaceholderTopic: String {
return BWIL10n.tr("Bwi", "create_room_placeholder_topic")
}
/// Verfiziere dieses Gerät von einer Deiner anderen Sitzungen, um Zugriff auf die verschlüsselten Nachrichten zu erhalten.
/// Verifizierung abgebrochen. Du kannst sie erneut starten.
public static var deviceVerificationCancelled: String {
return BWIL10n.tr("Bwi", "device_verification_cancelled")
}
/// Bestätige die neue Anmeldung auf Deinem Gerät: %@
public static func deviceVerificationSelfVerifyAlertMessage(_ p1: String) -> String {
return BWIL10n.tr("Bwi", "device_verification_self_verify_alert_message", p1)
}
/// Verifiziere diese Anmeldung mit einem Gerät, auf dem du bereits angemeldet bist, um Zugriff auf die verschlüsselten Nachrichten zu erhalten.
public static var deviceVerificationSelfVerifyWaitInformation: String {
return BWIL10n.tr("Bwi", "device_verification_self_verify_wait_information")
}
/// Benutze die neuste Messenger-Sitzung auf deinem anderen Gerät:
///
public static var deviceVerificationSelfVerifyWaitInformationMore: String {
return BWIL10n.tr("Bwi", "device_verification_self_verify_wait_information_more")
}
/// Nutze Dein Wiederherstellungsschlüssel um alle Deine Nachrichten zu entschlüsseln
/// Nutze Deinen Wiederherstellungsschlüssel, um alle Deine Nachrichten zu entschlüsseln.
public static var deviceVerificationSelfVerifyWaitRecoverSecretsAdditionalInformation: String {
return BWIL10n.tr("Bwi", "device_verification_self_verify_wait_recover_secrets_additional_information")
}
/// Verschlüsselungskennwort verwenden
/// Alternative Wiederherstellung
public static var deviceVerificationSelfVerifyWaitRecoverSecretsWithPassphrase: String {
return BWIL10n.tr("Bwi", "device_verification_self_verify_wait_recover_secrets_with_passphrase")
}
/// Verschlüsselungskennwort verwenden
/// Alternative Wiederherstellung
public static var deviceVerificationSelfVerifyWaitRecoverSecretsWithoutPassphrase: String {
return BWIL10n.tr("Bwi", "device_verification_self_verify_wait_recover_secrets_without_passphrase")
}
/// Verifiziere dieses Gerät
/// Diese Anmeldung verifizieren
public static var deviceVerificationSelfVerifyWaitTitle: String {
return BWIL10n.tr("Bwi", "device_verification_self_verify_wait_title")
}
@@ -787,10 +795,14 @@ public class BWIL10n: NSObject {
public static var keyBackupSetupSuccessFromRecoveryKeyRecoveryKeyTitle: String {
return BWIL10n.tr("Bwi", "key_backup_setup_success_from_recovery_key_recovery_key_title")
}
/// Wiederherstellungsschlüssel
/// Diese Anmeldung verifizieren
public static var keyVerificationThisSessionTitle: String {
return BWIL10n.tr("Bwi", "key_verification_this_session_title")
}
/// Verifizierung angefragt
public static var keyVerificationTileRequestAlertTitle: String {
return BWIL10n.tr("Bwi", "key_verification_tile_request_alert_title")
}
/// Du kannst nun sichere Nachrichten auf deinem neuen Gerät lesen. Andere Benutzer wissen, dass sie es vertrauen können.
public static var keyVerificationVerifiedNewSessionInformation: String {
return BWIL10n.tr("Bwi", "key_verification_verified_new_session_information")
@@ -799,6 +811,18 @@ public class BWIL10n: NSObject {
public static var keyVerificationVerifiedThisSessionInformation: String {
return BWIL10n.tr("Bwi", "key_verification_verified_this_session_information")
}
/// Stattdessen mit Emojis vergleichen
public static var keyVerificationVerifyQrCodeCannotScanAction: String {
return BWIL10n.tr("Bwi", "key_verification_verify_qr_code_cannot_scan_action")
}
/// Scanne den Code mit einem anderen Gerät oder umgekehrt.
public static var keyVerificationVerifyQrCodeInformationOtherDevice: String {
return BWIL10n.tr("Bwi", "key_verification_verify_qr_code_information_other_device")
}
/// Diese Anmeldung verifizieren
public static var keyVerificationVerifyQrCodeTitle: String {
return BWIL10n.tr("Bwi", "key_verification_verify_qr_code_title")
}
///
public static var locationSharingCopyrightLabel: String {
return BWIL10n.tr("Bwi", "location_sharing_copyright_label")
@@ -947,7 +971,7 @@ public class BWIL10n: NSObject {
public static var roomDetailsNoLocalAddressesForDm: String {
return BWIL10n.tr("Bwi", "room_details_no_local_addresses_for_dm")
}
/// Raum teilen
/// Link zum Raum kopieren
public static var roomDetailsPermalink: String {
return BWIL10n.tr("Bwi", "room_details_permalink")
}
@@ -967,7 +991,7 @@ public class BWIL10n: NSObject {
public static var roomEventActionEndPoll: String {
return BWIL10n.tr("Bwi", "room_event_action_end_poll")
}
/// Nachricht teilen
/// Link zur Nachricht kopieren
public static var roomEventActionPermalink: String {
return BWIL10n.tr("Bwi", "room_event_action_permalink")
}
@@ -999,7 +1023,7 @@ public class BWIL10n: NSObject {
public static var roomParticipantsActionIgnore: String {
return BWIL10n.tr("Bwi", "room_participants_action_ignore")
}
/// Nutzer teilen
/// Link zum Nutzer kopieren
public static var roomParticipantsActionPermalink: String {
return BWIL10n.tr("Bwi", "room_participants_action_permalink")
}
+7
View File
@@ -99,6 +99,7 @@ internal class Asset: NSObject {
internal static let lock = ImageAsset(name: "lock")
internal static let messageCircle = ImageAsset(name: "message_circle")
internal static let monitor = ImageAsset(name: "monitor")
internal static let permalink = ImageAsset(name: "permalink")
internal static let placeholder = ImageAsset(name: "placeholder")
internal static let plusIcon = ImageAsset(name: "plus_icon")
internal static let poweredByBWIBlk = ImageAsset(name: "powered_by_BWI_blk")
@@ -214,6 +215,8 @@ internal class Asset: NSObject {
internal static let personalNotesAvatar = ImageAsset(name: "personal_notes_avatar")
internal static let actionCamera = ImageAsset(name: "action_camera")
internal static let actionFile = ImageAsset(name: "action_file")
internal static let actionFormattingDisabled = ImageAsset(name: "action_formatting_disabled")
internal static let actionFormattingEnabled = ImageAsset(name: "action_formatting_enabled")
internal static let actionLive = ImageAsset(name: "action_live")
internal static let actionLocation = ImageAsset(name: "action_location")
internal static let actionMediaLibrary = ImageAsset(name: "action_media_library")
@@ -360,7 +363,11 @@ internal class Asset: NSObject {
internal static let voiceBroadcastPlay = ImageAsset(name: "voice_broadcast_play")
internal static let voiceBroadcastRecord = ImageAsset(name: "voice_broadcast_record")
internal static let voiceBroadcastRecordPause = ImageAsset(name: "voice_broadcast_record_pause")
internal static let voiceBroadcastSpinner = ImageAsset(name: "voice_broadcast_spinner")
internal static let voiceBroadcastStop = ImageAsset(name: "voice_broadcast_stop")
internal static let voiceBroadcastTileLive = ImageAsset(name: "voice_broadcast_tile_live")
internal static let voiceBroadcastTileMic = ImageAsset(name: "voice_broadcast_tile_mic")
internal static let voiceBroadcastTimeLeft = ImageAsset(name: "voice_broadcast_time_left")
internal static let launchScreenLogo = ImageAsset(name: "launch_screen_logo")
}
@objcMembers
+122 -10
View File
@@ -2923,6 +2923,14 @@ public class VectorL10n: NSObject {
public static var keyBackupSetupTitle: String {
return VectorL10n.tr("Vector", "key_backup_setup_title")
}
/// Review to ensure your account is safe.
public static var keyVerificationAlertBody: String {
return VectorL10n.tr("Vector", "key_verification_alert_body")
}
/// You have unverified sessions
public static var keyVerificationAlertTitle: String {
return VectorL10n.tr("Vector", "key_verification_alert_title")
}
/// You need to bootstrap cross-signing first.
public static var keyVerificationBootstrapNotSetupMessage: String {
return VectorL10n.tr("Vector", "key_verification_bootstrap_not_setup_message")
@@ -3007,14 +3015,6 @@ public class VectorL10n: NSObject {
public static var keyVerificationSelfVerifyCurrentSessionAlertValidateAction: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_current_session_alert_validate_action")
}
/// Verify all your sessions to ensure your account & messages are safe.
public static var keyVerificationSelfVerifyUnverifiedSessionsAlertMessage: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_message")
}
/// Review where you're logged in
public static var keyVerificationSelfVerifyUnverifiedSessionsAlertTitle: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_title")
}
/// Review
public static var keyVerificationSelfVerifyUnverifiedSessionsAlertValidateAction: String {
return VectorL10n.tr("Vector", "key_verification_self_verify_unverified_sessions_alert_validate_action")
@@ -3179,6 +3179,18 @@ public class VectorL10n: NSObject {
public static var later: String {
return VectorL10n.tr("Vector", "later")
}
/// Processing data\n%@ %%
public static func launchLoadingProcessingResponse(_ p1: String) -> String {
return VectorL10n.tr("Vector", "launch_loading_processing_response", p1)
}
/// Syncing with the server
public static var launchLoadingServerSyncing: String {
return VectorL10n.tr("Vector", "launch_loading_server_syncing")
}
/// Syncing with the server\n(%@ attempt)
public static func launchLoadingServerSyncingNthAttempt(_ p1: String) -> String {
return VectorL10n.tr("Vector", "launch_loading_server_syncing_nth_attempt", p1)
}
/// Leave
public static var leave: String {
return VectorL10n.tr("Vector", "leave")
@@ -3647,6 +3659,10 @@ public class VectorL10n: NSObject {
public static var manageSessionSignOut: String {
return VectorL10n.tr("Vector", "manage_session_sign_out")
}
/// Sign out of all other sessions
public static var manageSessionSignOutOtherSessions: String {
return VectorL10n.tr("Vector", "manage_session_sign_out_other_sessions")
}
/// Manage session
public static var manageSessionTitle: String {
return VectorL10n.tr("Vector", "manage_session_title")
@@ -4587,6 +4603,18 @@ public class VectorL10n: NSObject {
public static var or: String {
return VectorL10n.tr("Vector", "or")
}
/// This password has been found in a dictionary, and is not allowed.
public static var passwordPolicyPwdInDictError: String {
return VectorL10n.tr("Vector", "password_policy_pwd_in_dict_error")
}
/// Too short password
public static var passwordPolicyTooShortPwdError: String {
return VectorL10n.tr("Vector", "password_policy_too_short_pwd_error")
}
/// This password is too weak. It must contain at least 8 characters, with at least one character of each type: uppercase, lowercase, digit and special character.
public static var passwordPolicyWeakPwdError: String {
return VectorL10n.tr("Vector", "password_policy_weak_pwd_error")
}
/// Contain a lower-case letter.
public static var passwordValidationErrorContainLowercaseLetter: String {
return VectorL10n.tr("Vector", "password_validation_error_contain_lowercase_letter")
@@ -7535,7 +7563,7 @@ public class VectorL10n: NSObject {
public static var settingsLabsEnableRingingForGroupCalls: String {
return VectorL10n.tr("Vector", "settings_labs_enable_ringing_for_group_calls")
}
/// Threaded messaging
/// Threaded messages
public static var settingsLabsEnableThreads: String {
return VectorL10n.tr("Vector", "settings_labs_enable_threads")
}
@@ -7543,7 +7571,7 @@ public class VectorL10n: NSObject {
public static var settingsLabsEnableVoiceBroadcast: String {
return VectorL10n.tr("Vector", "settings_labs_enable_voice_broadcast")
}
/// Try out the rich text editor (plain text mode coming soon)
/// Try out the rich text editor
public static var settingsLabsEnableWysiwygComposer: String {
return VectorL10n.tr("Vector", "settings_labs_enable_wysiwyg_composer")
}
@@ -8679,6 +8707,10 @@ public class VectorL10n: NSObject {
public static var userOtherSessionMenuSelectSessions: String {
return VectorL10n.tr("Vector", "user_other_session_menu_select_sessions")
}
/// Sign out of %@ sessions
public static func userOtherSessionMenuSignOutSessions(_ p1: String) -> String {
return VectorL10n.tr("Vector", "user_other_session_menu_sign_out_sessions", p1)
}
/// No inactive sessions found.
public static var userOtherSessionNoInactiveSessions: String {
return VectorL10n.tr("Vector", "user_other_session_no_inactive_sessions")
@@ -8691,6 +8723,10 @@ public class VectorL10n: NSObject {
public static var userOtherSessionNoVerifiedSessions: String {
return VectorL10n.tr("Vector", "user_other_session_no_verified_sessions")
}
/// This session doesnt support encryption and thus can't be verified.
public static var userOtherSessionPermanentlyUnverifiedAdditionalInfo: String {
return VectorL10n.tr("Vector", "user_other_session_permanently_unverified_additional_info")
}
/// Security recommendation
public static var userOtherSessionSecurityRecommendationTitle: String {
return VectorL10n.tr("Vector", "user_other_session_security_recommendation_title")
@@ -8779,6 +8815,18 @@ public class VectorL10n: NSObject {
public static var userSessionDetailsTitle: String {
return VectorL10n.tr("Vector", "user_session_details_title")
}
/// Got it
public static var userSessionGotIt: String {
return VectorL10n.tr("Vector", "user_session_got_it")
}
/// Inactive sessions are sessions you have not used in some time, but they continue to receive encryption keys.\n\nRemoving inactive sessions improves security and performance, and makes it easier for you to identify if a new session is suspicious.
public static var userSessionInactiveSessionDescription: String {
return VectorL10n.tr("Vector", "user_session_inactive_session_description")
}
/// Inactive sessions
public static var userSessionInactiveSessionTitle: String {
return VectorL10n.tr("Vector", "user_session_inactive_session_title")
}
/// %1$@ · %2$@
public static func userSessionItemDetails(_ p1: String, _ p2: String) -> String {
return VectorL10n.tr("Vector", "user_session_item_details", p1, p2)
@@ -8807,6 +8855,10 @@ public class VectorL10n: NSObject {
public static var userSessionOverviewSessionTitle: String {
return VectorL10n.tr("Vector", "user_session_overview_session_title")
}
/// This session doesn't support encryption, so it can't be verified.\n\nYou won't be able to participate in rooms where encryption is enabled when using this session.\n\nFor best security and privacy, it is recommended to use Matrix clients that support encryption.
public static var userSessionPermanentlyUnverifiedSessionDescription: String {
return VectorL10n.tr("Vector", "user_session_permanently_unverified_session_description")
}
/// Push notifications
public static var userSessionPushNotifications: String {
return VectorL10n.tr("Vector", "user_session_push_notifications")
@@ -8815,6 +8867,14 @@ public class VectorL10n: NSObject {
public static var userSessionPushNotificationsMessage: String {
return VectorL10n.tr("Vector", "user_session_push_notifications_message")
}
/// Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.
public static var userSessionRenameSessionDescription: String {
return VectorL10n.tr("Vector", "user_session_rename_session_description")
}
/// Renaming sessions
public static var userSessionRenameSessionTitle: String {
return VectorL10n.tr("Vector", "user_session_rename_session_title")
}
/// Unverified session
public static var userSessionUnverified: String {
return VectorL10n.tr("Vector", "user_session_unverified")
@@ -8823,6 +8883,14 @@ public class VectorL10n: NSObject {
public static var userSessionUnverifiedAdditionalInfo: String {
return VectorL10n.tr("Vector", "user_session_unverified_additional_info")
}
/// Unverified sessions are sessions that have logged in with your credentials but not been cross-verified.\n\nYou should make especially certain that you recognise these sessions as they could represent an unauthorised use of your account.
public static var userSessionUnverifiedSessionDescription: String {
return VectorL10n.tr("Vector", "user_session_unverified_session_description")
}
/// Unverified session
public static var userSessionUnverifiedSessionTitle: String {
return VectorL10n.tr("Vector", "user_session_unverified_session_title")
}
/// Unverified
public static var userSessionUnverifiedShort: String {
return VectorL10n.tr("Vector", "user_session_unverified_short")
@@ -8847,6 +8915,14 @@ public class VectorL10n: NSObject {
public static var userSessionVerifiedAdditionalInfo: String {
return VectorL10n.tr("Vector", "user_session_verified_additional_info")
}
/// Verified sessions are anywhere you are using Element after entering your passphrase or confirming your identity with another verified session.\n\nThis means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session.
public static var userSessionVerifiedSessionDescription: String {
return VectorL10n.tr("Vector", "user_session_verified_session_description")
}
/// Verified sessions
public static var userSessionVerifiedSessionTitle: String {
return VectorL10n.tr("Vector", "user_session_verified_session_title")
}
/// Verified
public static var userSessionVerifiedShort: String {
return VectorL10n.tr("Vector", "user_session_verified_short")
@@ -8863,6 +8939,10 @@ public class VectorL10n: NSObject {
public static func userSessionsDefaultSessionDisplayName(_ p1: String) -> String {
return VectorL10n.tr("Vector", "user_sessions_default_session_display_name", p1)
}
/// Hide IP address
public static var userSessionsHideLocationInfo: String {
return VectorL10n.tr("Vector", "user_sessions_hide_location_info")
}
/// Current session
public static var userSessionsOverviewCurrentSessionSectionTitle: String {
return VectorL10n.tr("Vector", "user_sessions_overview_current_session_section_title")
@@ -8911,6 +8991,10 @@ public class VectorL10n: NSObject {
public static var userSessionsSettings: String {
return VectorL10n.tr("Vector", "user_sessions_settings")
}
/// Show IP address
public static var userSessionsShowLocationInfo: String {
return VectorL10n.tr("Vector", "user_sessions_show_location_info")
}
/// View all (%d)
public static func userSessionsViewAllAction(_ p1: Int) -> String {
return VectorL10n.tr("Vector", "user_sessions_view_all_action", p1)
@@ -9071,6 +9155,14 @@ public class VectorL10n: NSObject {
public static var voiceBroadcastBlockedBySomeoneElseMessage: String {
return VectorL10n.tr("Vector", "voice_broadcast_blocked_by_someone_else_message")
}
/// Buffering...
public static var voiceBroadcastBuffering: String {
return VectorL10n.tr("Vector", "voice_broadcast_buffering")
}
/// Live
public static var voiceBroadcastLive: String {
return VectorL10n.tr("Vector", "voice_broadcast_live")
}
/// You don't have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions.
public static var voiceBroadcastPermissionDeniedMessage: String {
return VectorL10n.tr("Vector", "voice_broadcast_permission_denied_message")
@@ -9079,6 +9171,26 @@ public class VectorL10n: NSObject {
public static var voiceBroadcastPlaybackLoadingError: String {
return VectorL10n.tr("Vector", "voice_broadcast_playback_loading_error")
}
/// Yes, stop
public static var voiceBroadcastStopAlertAgreeButton: String {
return VectorL10n.tr("Vector", "voice_broadcast_stop_alert_agree_button")
}
/// Are you sure you want to stop your live broadcast? This will end the broadcast, and the full recording will be available in the room.
public static var voiceBroadcastStopAlertDescription: String {
return VectorL10n.tr("Vector", "voice_broadcast_stop_alert_description")
}
/// Stop live broadcasting?
public static var voiceBroadcastStopAlertTitle: String {
return VectorL10n.tr("Vector", "voice_broadcast_stop_alert_title")
}
/// Voice broadcast
public static var voiceBroadcastTile: String {
return VectorL10n.tr("Vector", "voice_broadcast_tile")
}
/// %@ left
public static func voiceBroadcastTimeLeft(_ p1: String) -> String {
return VectorL10n.tr("Vector", "voice_broadcast_time_left", p1)
}
/// Can't start a new voice broadcast
public static var voiceBroadcastUnauthorizedTitle: String {
return VectorL10n.tr("Vector", "voice_broadcast_unauthorized_title")
-4
View File
@@ -14,10 +14,6 @@ public extension VectorL10n {
static var imagePickerActionFiles: String {
return VectorL10n.tr("Untranslated", "image_picker_action_files")
}
/// Voice broadcast detected (under active development)
static var voiceBroadcastInTimelineTitle: String {
return VectorL10n.tr("Untranslated", "voice_broadcast_in_timeline_title")
}
}
// swiftlint:enable function_parameter_count identifier_name line_length type_body_length
@@ -18,12 +18,9 @@ import Foundation
import Combine
extension RiotSettings {
@available(iOS 13.0, *)
func publisher(for key: String) -> AnyPublisher<Notification, Never> {
return NotificationCenter.default.publisher(for: .userDefaultValueUpdated)
NotificationCenter.default.publisher(for: .userDefaultValueUpdated)
.filter({ $0.object as? String == key })
.eraseToAnyPublisher()
}
}
+12 -3
View File
@@ -35,6 +35,7 @@ final class RiotSettings: NSObject {
static let showAllRoomsInHomeSpace = "showAllRoomsInHomeSpace"
static let enableUISIAutoReporting = "enableUISIAutoReporting"
static let enableLiveLocationSharing = "enableLiveLocationSharing"
static let showIPAddressesInSessionsManager = "showIPAddressesInSessionsManager"
}
static let shared = RiotSettings()
@@ -166,6 +167,10 @@ final class RiotSettings: NSObject {
@UserDefault(key: "enableThreads", defaultValue: false, storage: defaults)
var enableThreads
/// Indicates if threads should be forced enabled in the timeline.
@UserDefault(key: "forceThreadsEnabled", defaultValue: true, storage: defaults)
var forceThreadsEnabled
/// Indicates if auto reporting of decryption errors is enabled
@UserDefault(key: UserDefaultsKeys.enableUISIAutoReporting, defaultValue: BuildSettings.cryptoUISIAutoReportingEnabled, storage: defaults)
var enableUISIAutoReporting
@@ -189,6 +194,13 @@ final class RiotSettings: NSObject {
/// Flag indicating if the wysiwyg composer feature is enabled
@UserDefault(key: "enableWysiwygComposer", defaultValue: false, storage: defaults)
var enableWysiwygComposer
@UserDefault(key: "enableWysiwygTextFormatting", defaultValue: true, storage: defaults)
var enableWysiwygTextFormatting
/// Flag indicating if the IP addresses should be shown in the new device manager
@UserDefault(key: UserDefaultsKeys.showIPAddressesInSessionsManager, defaultValue: false, storage: defaults)
var showIPAddressesInSessionsManager
/// Flag indicating if the voice broadcast feature is enabled
@UserDefault(key: "enableVoiceBroadcast", defaultValue: false, storage: defaults)
@@ -209,9 +221,6 @@ final class RiotSettings: NSObject {
@UserDefault(key: "hideVerifyThisSessionAlert", defaultValue: false, storage: defaults)
var hideVerifyThisSessionAlert
@UserDefault(key: "hideReviewSessionsAlert", defaultValue: false, storage: defaults)
var hideReviewSessionsAlert
@UserDefault(key: "matrixApps", defaultValue: false, storage: defaults)
var matrixApps
@@ -175,9 +175,10 @@ extension UISIAutoReportData: Codable {
]
contentMap.setObject(content as NSDictionary, forUser: source.senderUserId, andDevice: source.senderDeviceId)
session.matrixRestClient.sendDirectToDevice(
eventType: Self.autoRsRequest,
contentMap: contentMap,
txnId: nil
payload: .init(
eventType: Self.autoRsRequest,
contentMap: contentMap
)
) { response in
if response.isFailure {
MXLog.warning("failed to send auto-uisi to device")
@@ -42,6 +42,10 @@ struct SentryMonitoringClient {
options.enableNetworkTracking = false
options.beforeSend = { event in
// Use the actual error message as issue fingerprint
if let message = event.message?.formatted {
event.fingerprint = [message]
}
MXLog.debug("[SentryMonitoringClient] Issue detected: \(event)")
return event
}
+32 -8
View File
@@ -656,7 +656,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[self.pushNotificationService applicationDidBecomeActive];
[self configurePinCodeScreenFor:application createIfRequired:NO];
self.isApplicationActiveFromSystemAlert = NO;
[self checkCrossSigningForSession:self.mxSessions.firstObject];
}
- (void)configurePinCodeScreenFor:(UIApplication *)application
@@ -2353,6 +2356,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Reset analytics
[Analytics.shared reset];
[[[ReviewSessionAlertSnoozeController alloc] init] clearSnooze];
[TimelinePollProvider.shared reset];
#ifdef MX_CALL_STACK_ENDPOINT
// Erase all created certificates and private keys by MXEndpointCallStack
for (MXKAccount *account in MXKAccountManager.sharedManager.accounts)
@@ -2551,11 +2558,22 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
MXLogDebug(@"[AppDelegate] showLaunchAnimation");
UIView* launchLoadingView = [BUMLaunchLoadingViewController makeView];
launchLoadingView.frame = window.bounds;
launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[window addSubview:launchLoadingView];
UIView *launchLoadingView;
if (MXSDKOptions.sharedInstance.enableSyncProgress)
{
if (BWIBuildSettings.shared.showBUMLottieAnimation)
{
launchLoadingView = [BUMLaunchLoadingViewController makeView];
} else {
MXSession *mainSession = self.mxSessions.firstObject;
launchLoadingView = [LaunchLoadingView instantiateWithSyncProgress:mainSession.syncProgress];
}
launchLoadingView.frame = window.bounds;
launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[window addSubview:launchLoadingView];
}
launchAnimationContainerView = launchLoadingView;
[MXSDKOptions.sharedInstance.profiler startMeasuringTaskWithName:MXTaskProfileNameStartupLaunchScreen];
@@ -4106,7 +4124,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if (senderName)
{
senderInfo = [NSString stringWithFormat:@"%@ (%@)", senderName, senderId];
senderInfo = [NSString stringWithFormat:@"%@", senderName]; // bwi: show only the name
}
else
{
@@ -4123,7 +4141,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
};
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[VectorL10n keyVerificationTileRequestIncomingTitle]
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[BWIL10n keyVerificationTileRequestAlertTitle]
message:senderInfo
preferredStyle:UIAlertControllerStyleAlert];
@@ -4235,7 +4253,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
deviceInfo = device.deviceId;
}
NSString *alertMessage = [VectorL10n deviceVerificationSelfVerifyAlertMessage:deviceInfo];
NSString *alertMessage = [BWIL10n deviceVerificationSelfVerifyAlertMessage:deviceInfo];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:[VectorL10n deviceVerificationSelfVerifyAlertTitle]
message:alertMessage
@@ -4474,6 +4492,12 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
RiotSettings.shared.showAllRoomsInHomeSpace = YES;
}
if (RiotSettings.shared.forceThreadsEnabled)
{
RiotSettings.shared.enableThreads = YES;
RiotSettings.shared.forceThreadsEnabled = NO;
}
}
#pragma mark - App version management
@@ -613,12 +613,14 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
/// Replace the contents of the navigation router with a loading animation.
private func showLoadingAnimation() {
// FROTMERGE
if BWIBuildSettings.shared.showBUMLottieAnimation {
let loadingViewController = BUMLaunchLoadingViewController(toFrame: 60)
loadingViewController.modalPresentationStyle = .fullScreen
navigationRouter.setRootModule(loadingViewController)
} else {
let loadingViewController = LaunchLoadingViewController()
let syncProgress: MXSessionSyncProgress? = MXSDKOptions.sharedInstance().enableSyncProgress ? session?.syncProgress : nil
let loadingViewController = LaunchLoadingViewController(syncProgress: syncProgress)
loadingViewController.modalPresentationStyle = .fullScreen
// Replace the navigation stack with the loading animation
@@ -106,12 +106,14 @@ final class LegacyAuthenticationCoordinator: NSObject, AuthenticationCoordinator
// MARK: - Private
private func showLoadingAnimation() {
// FROTMERGE
if BWIBuildSettings.shared.showBUMLottieAnimation {
let loadingViewController = BUMLaunchLoadingViewController(toFrame: 60)
loadingViewController.modalPresentationStyle = .fullScreen
navigationRouter.setRootModule(loadingViewController)
} else {
let loadingViewController = LaunchLoadingViewController()
let syncProgress: MXSessionSyncProgress? = MXSDKOptions.sharedInstance().enableSyncProgress ? session?.syncProgress : nil
let loadingViewController = LaunchLoadingViewController(syncProgress: syncProgress)
loadingViewController.modalPresentationStyle = .fullScreen
// Replace the navigation stack with the loading animation
@@ -25,11 +25,26 @@ class VectorHostingBottomSheetPreferences {
case medium
case large
/// only available on iOS16, medium behaviour will be used instead
/// - Parameters:
/// - height: The height of the custom detent, if the height is bigger than the maximum possible height for a detent the latter will be returned
/// - identifier: The identifier used to identify the custom detent during detent transitions, by default the value is set to "custom", however if you are supporting multiple custom detents in a bottom sheet, you should specify a different identifier for each
case custom(height: CGFloat, identifier: String = "custom")
@available(iOS 15, *)
fileprivate func uiSheetDetent() -> UISheetPresentationController.Detent {
switch self {
case .medium: return .medium()
case .large: return .large()
case let .custom(height, identifier):
if #available(iOS 16, *) {
let identifier = UISheetPresentationController.Detent.Identifier(identifier)
return .custom(identifier: identifier) { context in
return min(height, context.maximumDetentValue)
}
} else {
return .medium()
}
}
}
@@ -38,6 +53,12 @@ class VectorHostingBottomSheetPreferences {
switch self {
case .medium: return .medium
case .large: return .large
case let .custom(_, identifier):
if #available(iOS 16, *) {
return UISheetPresentationController.Detent.Identifier(identifier)
} else {
return .medium
}
}
}
}
@@ -22,10 +22,6 @@ import MatrixSDK
/// A presenter responsible for showing / hiding a toast view for loading spinners or success messages.
/// It is managed by an `UserIndicator`, meaning the `present` and `dismiss` methods will be called when the parent `UserIndicator` starts or completes.
class ToastViewPresenter: UserIndicatorViewPresentable {
struct Constants {
static let navigationBarPatting = CGFloat(12)
}
private let viewState: ToastViewState
private let presentationContext: UserIndicatorPresentationContext
private weak var view: UIView?
@@ -46,19 +42,11 @@ class ToastViewPresenter: UserIndicatorViewPresentable {
self.view = view
view.translatesAutoresizingMaskIntoConstraints = false
if let navigation = viewController.topNavigationController {
navigation.view.addSubview(view)
NSLayoutConstraint.activate([
view.centerXAnchor.constraint(equalTo: navigation.view.centerXAnchor),
view.topAnchor.constraint(equalTo: navigation.navigationBar.safeAreaLayoutGuide.bottomAnchor, constant: Constants.navigationBarPatting)
])
} else {
viewController.view.addSubview(view)
NSLayoutConstraint.activate([
view.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor),
view.topAnchor.constraint(equalTo: viewController.view.topAnchor)
])
}
viewController.view.addSubview(view)
NSLayoutConstraint.activate([
view.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor),
view.topAnchor.constraint(equalTo: viewController.view.safeAreaLayoutGuide.topAnchor)
])
view.alpha = 0
view.transform = .init(translationX: 0, y: 5)
@@ -85,13 +73,3 @@ class ToastViewPresenter: UserIndicatorViewPresentable {
animator?.startAnimation()
}
}
private extension UIViewController {
var topNavigationController: UINavigationController? {
var controller: UINavigationController? = self as? UINavigationController ?? navigationController
while controller?.navigationController != nil {
controller = controller?.navigationController
}
return controller
}
}
@@ -609,9 +609,10 @@
}
actionsIndex = sectionCount++;
// bwi: show direct message section
directChatsIndex = sectionCount++;
}
directChatsIndex = sectionCount++;
}
// Else check whether the contact has been instantiated with an email or a matrix id
else if ((!_contact.isMatrixContact && _contact.emailAddresses.count) || [MXTools isEmailAddress:_contact.displayName])
@@ -650,7 +651,13 @@
}
else if (section == directChatsIndex)
{
return (directChatsArray.count + 1);
// bwi: add option "start chat" to the direct message section when there is no chat
if (directChatsArray.count == 0) {
return (directChatsArray.count + 1);
} else {
return directChatsArray.count;
}
}
return 0;
@@ -78,7 +78,7 @@ final class CrossSigningService: NSObject {
func setupCrossSigningRequest() -> AuthenticatedEndpointRequest {
let path = "\(kMXAPIPrefixPathUnstable)/keys/device_signing/upload"
return AuthenticatedEndpointRequest(path: path, httpMethod: "POST")
return AuthenticatedEndpointRequest(path: path, httpMethod: "POST", params: [:])
}
/// Setup cross-signing without authentication. Useful when a grace period is enabled.
@@ -152,7 +152,7 @@
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
// Finalize cell view customization here
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class])
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class] && ![cell isKindOfClass:MXKRoomEmptyBubbleTableViewCell.class])
{
MXKRoomBubbleTableViewCell *bubbleCell = (MXKRoomBubbleTableViewCell*)cell;
@@ -27,7 +27,6 @@ protocol AllChatsViewControllerDelegate: AnyObject {
}
class AllChatsViewController: HomeViewController {
// MARK: - Class methods
static override func nib() -> UINib! {
@@ -60,7 +59,7 @@ class AllChatsViewController: HomeViewController {
private let tableViewPaginationThrottler = MXThrottler(minimumDelay: 0.1)
private var reviewSessionAlertHasBeenDisplayed: Bool = false
private let reviewSessionAlertSnoozeController = ReviewSessionAlertSnoozeController()
private var bannerView: UIView? {
didSet {
@@ -73,8 +72,10 @@ class AllChatsViewController: HomeViewController {
private var allChatsOnboardingCoordinatorBridgePresenter: AllChatsOnboardingCoordinatorBridgePresenter?
private var currentAlert: UIAlertController?
private var theme: Theme {
ThemeService.shared().theme
}
@IBOutlet private var toolbar: UIToolbar!
private var isToolbarHidden: Bool = false {
didSet {
@@ -139,12 +140,13 @@ class AllChatsViewController: HomeViewController {
searchController.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(self.setupEditOptions), name: AllChatsLayoutSettingsManager.didUpdateSettings, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.updateBadgeButton), name: MXSpaceNotificationCounter.didUpdateNotificationCount, object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.toolbar.tintColor = ThemeService.shared().theme.colors.accent
self.toolbar.tintColor = theme.colors.accent
if self.navigationItem.searchController == nil {
self.navigationItem.searchController = searchController
}
@@ -462,7 +464,7 @@ class AllChatsViewController: HomeViewController {
return
}
self.update(with: ThemeService.shared().theme)
self.update(with: theme)
}
private func update(with theme: Theme) {
@@ -502,22 +504,51 @@ class AllChatsViewController: HomeViewController {
self?.updateToolbar(with: menu)
}))
updateEmptyView()
updateBadgeButton()
}
private func updateRightNavigationItem(with menu: UIMenu) {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), menu: menu)
}
private lazy var spacesButton: BadgedBarButtonItem = {
let innerButton = UIButton(type: .system)
innerButton.accessibilityLabel = VectorL10n.spaceSelectorTitle
innerButton.addTarget(self, action: #selector(self.showSpaceSelectorAction(sender:)), for: .touchUpInside)
innerButton.setImage(Asset.Images.allChatsSpacesIcon.image, for: .normal)
return BadgedBarButtonItem(withBaseButton: innerButton, theme: theme)
}()
@objc private func updateBadgeButton() {
guard isViewLoaded, let session = mainSession else {
return
}
let notificationCount = session.spaceService.missedNotificationsCount
let hasSpaceInvite = session.spaceService.hasSpaceInvite
let isBadgeHighlighed = session.spaceService.hasHighlightNotification || hasSpaceInvite
let badgeValue: String
switch notificationCount {
case 0:
badgeValue = hasSpaceInvite ? "!" : "0"
case (1 ... Constants.spacesButtonMaxCount):
badgeValue = "\(notificationCount)"
default:
badgeValue = "\(Constants.spacesButtonMaxCount)+"
}
spacesButton.badgeText = badgeValue
spacesButton.badgeBackgroundColor = isBadgeHighlighed ? theme.noticeColor : theme.noticeSecondaryColor
}
private func updateToolbar(with menu: UIMenu) {
guard isViewLoaded else {
return
}
self.isToolbarHidden = false
self.update(with: ThemeService.shared().theme)
let spacesButton = UIBarButtonItem(image: Asset.Images.allChatsSpacesIcon.image, style: .done, target: self, action: #selector(self.showSpaceSelectorAction(sender: )))
spacesButton.accessibilityLabel = VectorL10n.spaceSelectorTitle
self.update(with: theme)
self.toolbar.items = [
spacesButton,
@@ -659,6 +690,12 @@ class AllChatsViewController: HomeViewController {
}
}
private extension AllChatsViewController {
enum Constants {
static let spacesButtonMaxCount: UInt = 999
}
}
// MARK: - SpaceSelectorBottomSheetCoordinatorBridgePresenterDelegate
extension AllChatsViewController: SpaceSelectorBottomSheetCoordinatorBridgePresenterDelegate {
@@ -695,7 +732,6 @@ extension AllChatsViewController: SpaceSelectorBottomSheetCoordinatorBridgePrese
// MARK: - UISearchResultsUpdating
extension AllChatsViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
guard let searchText = searchController.searchBar.text, !searchText.isEmpty else {
self.dataSource.search(withPatterns: nil)
@@ -704,7 +740,6 @@ extension AllChatsViewController: UISearchResultsUpdating {
self.dataSource.search(withPatterns: [searchText])
}
}
// MARK: - UISearchControllerDelegate
@@ -821,12 +856,13 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
/// - Parameters:
/// - session: the matrix session.
func presentVerifyCurrentSessionAlertIfNeeded(with session: MXSession) {
guard !RiotSettings.shared.hideVerifyThisSessionAlert, !reviewSessionAlertHasBeenDisplayed, !isOnboardingInProgress else {
guard !RiotSettings.shared.hideVerifyThisSessionAlert,
!isOnboardingInProgress,
presentedViewController == nil,
viewIfLoaded?.window != nil else {
return
}
reviewSessionAlertHasBeenDisplayed = true
// Force verification if required by the HS configuration
guard !session.vc_homeserverConfiguration().encryption.isSecureBackupRequired else {
MXLog.debug("[AllChatsViewController] presentVerifyCurrentSessionAlertIfNeededWithSession: Force verification of the device")
@@ -842,21 +878,16 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
/// - Parameters:
/// - session: the matrix session.
func presentReviewUnverifiedSessionsAlertIfNeeded(with session: MXSession) {
guard !RiotSettings.shared.hideReviewSessionsAlert, !reviewSessionAlertHasBeenDisplayed else {
guard BuildSettings.showUnverifiedSessionsAlert,
!reviewSessionAlertSnoozeController.isSnoozed(),
presentedViewController == nil,
viewIfLoaded?.window != nil else {
return
}
let devices = mainSession.crypto.devices(forUser: mainSession.myUserId).values
var userHasOneUnverifiedDevice = false
for device in devices {
if !device.trustLevel.isCrossSigningVerified {
userHasOneUnverifiedDevice = true
break
}
}
let userHasOneUnverifiedDevice = devices.contains(where: {!$0.trustLevel.isCrossSigningVerified})
if userHasOneUnverifiedDevice {
reviewSessionAlertHasBeenDisplayed = true
presentReviewUnverifiedSessionsAlert(with: session)
}
}
@@ -972,8 +1003,6 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
private func presentVerifyCurrentSessionAlert(with session: MXSession) {
MXLog.debug("[AllChatsViewController] presentVerifyCurrentSessionAlertWithSession")
currentAlert?.dismiss(animated: true, completion: nil)
let alert = UIAlertController(title: VectorL10n.keyVerificationSelfVerifyCurrentSessionAlertTitle,
message: VectorL10n.keyVerificationSelfVerifyCurrentSessionAlertMessage,
preferredStyle: .alert)
@@ -993,16 +1022,13 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
}))
self.present(alert, animated: true)
currentAlert = alert
}
private func presentReviewUnverifiedSessionsAlert(with session: MXSession) {
MXLog.debug("[AllChatsViewController] presentReviewUnverifiedSessionsAlert")
currentAlert?.dismiss(animated: true, completion: nil)
let alert = UIAlertController(title: VectorL10n.keyVerificationSelfVerifyUnverifiedSessionsAlertTitle,
message: VectorL10n.keyVerificationSelfVerifyUnverifiedSessionsAlertMessage,
let alert = UIAlertController(title: VectorL10n.keyVerificationAlertTitle,
message: VectorL10n.keyVerificationAlertBody,
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: VectorL10n.keyVerificationSelfVerifyUnverifiedSessionsAlertValidateAction,
@@ -1011,14 +1037,11 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
self.showSettingsSecurityScreen(with: session)
}))
alert.addAction(UIAlertAction(title: VectorL10n.later, style: .cancel))
alert.addAction(UIAlertAction(title: VectorL10n.doNotAskAgain, style: .destructive, handler: { action in
RiotSettings.shared.hideReviewSessionsAlert = true
alert.addAction(UIAlertAction(title: VectorL10n.later, style: .cancel, handler: { [weak self] _ in
self?.reviewSessionAlertSnoozeController.snooze()
}))
present(alert, animated: true)
currentAlert = alert
}
private func showSettingsSecurityScreen(with session: MXSession) {
@@ -1034,7 +1057,12 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
settingsViewController.loadViewIfNeeded()
AppDelegate.theDelegate().restoreInitialDisplay {
self.navigationController?.viewControllers = [self, settingsViewController, securityViewController]
if RiotSettings.shared.enableNewSessionManager {
self.navigationController?.viewControllers = [self, settingsViewController]
settingsViewController.showUserSessionsFlow()
} else {
self.navigationController?.viewControllers = [self, settingsViewController, securityViewController]
}
}
}
@@ -1057,9 +1085,7 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
}
private func resetReviewSessionsFlags() {
reviewSessionAlertHasBeenDisplayed = false
RiotSettings.shared.hideVerifyThisSessionAlert = false
RiotSettings.shared.hideReviewSessionsAlert = false
}
private func presentOnboardingFlow() {
@@ -1091,3 +1117,22 @@ extension AllChatsViewController: SplitViewMasterViewControllerProtocol {
self.refreshCurrentSelectedCell(false)
}
}
private extension MXSpaceService {
var hasSpaceInvite: Bool {
spaceSummaries.contains(where: { $0.isJoined == false })
}
var missedNotificationsCount: UInt {
let notificationState = notificationCounter.homeNotificationState
let groupNotifications = notificationState.groupMissedDiscussionsCount
let directNotifications = notificationState.directMissedDiscussionsCount
// `notificationState.allCount` returns twice the messages for favourite rooms. Fixing it here.
return groupNotifications + directNotifications
}
var hasHighlightNotification: Bool {
notificationCounter.homeNotificationState.allHighlightCount > 0
}
}
@@ -0,0 +1,49 @@
//
// Copyright 2022 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.
//
import Foundation
@objcMembers
class ReviewSessionAlertSnoozeController: NSObject {
private let userDefaults: UserDefaults
private let snoozeDateKey = "ReviewSessionAlertSnoozeController_snoozeDateKey"
private let minDaysBetweenAlerts = 7
// for Objective-C
convenience override init() {
self.init(userDefaults: UserDefaults.standard)
}
init(userDefaults: UserDefaults = UserDefaults.standard) {
self.userDefaults = userDefaults
}
func isSnoozed() -> Bool {
guard let lastDisplayedDate = userDefaults.object(forKey: snoozeDateKey) as? Date else {
return false
}
return lastDisplayedDate.daysBetween(date: Date()) <= minDaysBetweenAlerts
}
func snooze() {
userDefaults.set(Date(), forKey: snoozeDateKey)
}
func clearSnooze() {
userDefaults.removeObject(forKey: snoozeDateKey)
}
}
@@ -133,7 +133,7 @@ final class KeyVerificationDataLoadingViewController: UIViewController {
switch error {
case KeyVerificationDataLoadingViewModelError.transactionCancelled:
message = VectorL10n.deviceVerificationCancelled
message = BWIL10n.deviceVerificationCancelled
case KeyVerificationDataLoadingViewModelError.transactionCancelledByMe(reason: let reason):
if reason.value != MXTransactionCancelCode.user().value {
message = VectorL10n.deviceVerificationCancelledByMe(reason.humanReadable)
@@ -182,7 +182,7 @@ final class KeyVerificationScanConfirmationViewController: UIViewController {
private func renderCancelled(reason: MXTransactionCancelCode) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.viewModel.process(viewAction: .cancel)
}
}
@@ -156,7 +156,7 @@ final class KeyVerificationVerifyBySASViewController: UIViewController {
self.cancelButton.actionStyle = .cancel
self.validateButton.setTitle(VectorL10n.keyVerificationVerifySasValidateAction, for: .normal)
self.additionalInformationLabel.text = VectorL10n.keyVerificationVerifySasAdditionalInformation
self.additionalInformationLabel.text = nil // bwi: text hidden
}
private func render(viewState: KeyVerificationVerifyViewState) {
@@ -188,7 +188,7 @@ final class KeyVerificationVerifyBySASViewController: UIViewController {
private func renderCancelled(reason: MXTransactionCancelCode) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.viewModel.process(viewAction: .cancel)
}
}
@@ -140,14 +140,14 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController {
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
self.title = VectorL10n.keyVerificationVerifyQrCodeTitle
self.titleLabel.text = VectorL10n.keyVerificationVerifyQrCodeTitle
self.title = BWIL10n.keyVerificationVerifyQrCodeTitle
self.titleLabel.text = BWIL10n.keyVerificationVerifyQrCodeTitle
self.informationLabel.text = VectorL10n.keyVerificationVerifyQrCodeInformation
// Hide until we have the type of the verification request
self.scanCodeButton.isHidden = true
self.cannotScanButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeCannotScanAction, for: .normal)
self.cannotScanButton.setTitle(BWIL10n.keyVerificationVerifyQrCodeCannotScanAction, for: .normal)
}
private func render(viewState: KeyVerificationVerifyByScanningViewState) {
@@ -200,7 +200,7 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController {
informationText = VectorL10n.keyVerificationVerifyQrCodeInformation
self.scanCodeButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeScanCodeAction, for: .normal)
default:
informationText = VectorL10n.keyVerificationVerifyQrCodeInformationOtherDevice
informationText = BWIL10n.keyVerificationVerifyQrCodeInformationOtherDevice
self.scanCodeButton.setTitle(VectorL10n.keyVerificationVerifyQrCodeScanCodeOtherDeviceAction, for: .normal)
}
@@ -252,7 +252,7 @@ final class KeyVerificationVerifyByScanningViewController: UIViewController {
// if we're verifying our own device, assume the user probably knows since it was them who
// cancelled on their other device
if verificationKind == .user {
self.errorPresenter.presentError(from: self.alertPresentingViewController, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self.alertPresentingViewController, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.dismissQRCodeScanningIfPresented(animated: false)
self.viewModel.process(viewAction: .cancel)
}
@@ -169,7 +169,7 @@ final class DeviceVerificationIncomingViewController: UIViewController {
private func renderCancelled(reason: MXTransactionCancelCode) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.viewModel.process(viewAction: .cancel)
}
}
@@ -177,7 +177,7 @@ final class KeyVerificationSelfVerifyStartViewController: UIViewController {
private func renderCancelled(reason: MXTransactionCancelCode) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.viewModel.process(viewAction: .cancel)
}
}
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="79A-qb-tmk">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="79A-qb-tmk">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -11,7 +11,7 @@
<!--Key Verification Self Verify Wait View Controller-->
<scene sceneID="a9K-1U-7Nm">
<objects>
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="79A-qb-tmk" customClass="KeyVerificationSelfVerifyWaitViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="79A-qb-tmk" customClass="KeyVerificationSelfVerifyWaitViewController" customModule="Element" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="tAM-kt-f0s">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -20,10 +20,10 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tIM-sl-gwE">
<rect key="frame" x="0.0" y="0.0" width="375" height="518.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="543.5"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IlB-Ch-LEo">
<rect key="frame" x="0.0" y="0.0" width="375" height="518.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="543.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d5Y-pj-XsI">
<rect key="frame" x="20" y="20" width="335" height="84"/>
@@ -35,10 +35,10 @@ Use the latest Riot on your other devices:</string>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="ANK-XS-dY7">
<rect key="frame" x="27.5" y="144" width="320" height="48"/>
<rect key="frame" x="27.5" y="144" width="320" height="73"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="3at-ql-vhb">
<rect key="frame" x="0.0" y="0.0" width="160" height="48"/>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3at-ql-vhb">
<rect key="frame" x="0.0" y="0.0" width="160" height="73"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="monitor" translatesAutoresizingMaskIntoConstraints="NO" id="nrB-Kj-4zE">
<rect key="frame" x="56" y="0.0" width="48" height="48"/>
@@ -47,10 +47,16 @@ Use the latest Riot on your other devices:</string>
<constraint firstAttribute="width" secondItem="nrB-Kj-4zE" secondAttribute="height" multiplier="1:1" id="TOT-bj-1W4"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Web" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lvz-0w-9TT">
<rect key="frame" x="65.5" y="56" width="29.5" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="coY-7W-lY7">
<rect key="frame" x="160" y="0.0" width="160" height="48"/>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="coY-7W-lY7">
<rect key="frame" x="160" y="0.0" width="160" height="73"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="smartphone" translatesAutoresizingMaskIntoConstraints="NO" id="P0P-X4-uSQ">
<rect key="frame" x="56" y="0.0" width="48" height="48"/>
@@ -59,6 +65,12 @@ Use the latest Riot on your other devices:</string>
<constraint firstAttribute="width" secondItem="P0P-X4-uSQ" secondAttribute="height" multiplier="1:1" id="AZP-GN-y8E"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Mobile App" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="x7a-wS-PpB">
<rect key="frame" x="43.5" y="56" width="73.5" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
@@ -67,13 +79,13 @@ Use the latest Riot on your other devices:</string>
</constraints>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This works with Element and other cross-signing capable Matrix clients." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LnW-1H-Ltq">
<rect key="frame" x="20" y="232" width="335" height="33.5"/>
<rect key="frame" x="20" y="257" width="335" height="33.5"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="8oJ-o6-DLK">
<rect key="frame" x="20" y="285.5" width="335" height="233"/>
<rect key="frame" x="20" y="310.5" width="335" height="233"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dXT-cL-ukJ">
<rect key="frame" x="0.0" y="0.0" width="335" height="114.5"/>
@@ -102,7 +114,7 @@ Use the latest Riot on your other devices:</string>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nf8-Ye-b9r">
<rect key="frame" x="0.0" y="114.5" width="335" height="118.5"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OEt-k0-vgM" customClass="RoundedButton" customModule="Riot" customModuleProvider="target">
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OEt-k0-vgM" customClass="RoundedButton" customModule="Element" customModuleProvider="target">
<rect key="frame" x="0.0" y="10" width="335" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="7ws-Nc-I7y"/>
@@ -178,6 +190,7 @@ Use the latest Riot on your other devices:</string>
</constraints>
</scrollView>
</subviews>
<viewLayoutGuide key="safeArea" id="GnW-bb-rsL"/>
<color key="backgroundColor" red="0.94509803920000002" green="0.96078431369999995" blue="0.97254901959999995" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="asO-rj-82y" firstAttribute="trailing" secondItem="GnW-bb-rsL" secondAttribute="trailing" id="Isw-tg-7go"/>
@@ -185,7 +198,6 @@ Use the latest Riot on your other devices:</string>
<constraint firstItem="GnW-bb-rsL" firstAttribute="top" secondItem="asO-rj-82y" secondAttribute="top" id="b3e-2d-oiV"/>
<constraint firstAttribute="bottomMargin" secondItem="asO-rj-82y" secondAttribute="bottom" id="wMk-Oq-DwP"/>
</constraints>
<viewLayoutGuide key="safeArea" id="GnW-bb-rsL"/>
</view>
<connections>
<outlet property="additionalInformationLabel" destination="LnW-1H-Ltq" id="TJS-GC-ABf"/>
@@ -132,9 +132,9 @@ final class KeyVerificationSelfVerifyWaitViewController: UIViewController {
self.desktopClientImageView.image = Asset.Images.monitor.image.withRenderingMode(.alwaysTemplate)
self.mobileClientImageView.image = Asset.Images.smartphone.image.withRenderingMode(.alwaysTemplate)
self.additionalInformationLabel.text = VectorL10n.deviceVerificationSelfVerifyWaitAdditionalInformation(AppInfo.current.displayName)
self.additionalInformationLabel.text = nil // bwi: hidden text
self.recoverSecretsAdditionalInformationLabel.text = VectorL10n.deviceVerificationSelfVerifyWaitRecoverSecretsAdditionalInformation
self.recoverSecretsAdditionalInformationLabel.text = BWIL10n.deviceVerificationSelfVerifyWaitRecoverSecretsAdditionalInformation
}
private func render(viewState: KeyVerificationSelfVerifyWaitViewState) {
@@ -198,7 +198,7 @@ final class KeyVerificationSelfVerifyWaitViewController: UIViewController {
private func renderCancelled(reason: MXTransactionCancelCode) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.viewModel.process(viewAction: .cancel)
}
}
@@ -177,7 +177,7 @@ final class DeviceVerificationStartViewController: UIViewController {
private func renderCancelled(reason: MXTransactionCancelCode) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.viewModel.process(viewAction: .cancel)
}
}
@@ -166,7 +166,7 @@ final class UserVerificationStartViewController: UIViewController {
private func renderCancelled(reason: MXTransactionCancelCode) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, title: "", message: VectorL10n.deviceVerificationCancelled, animated: true) {
self.errorPresenter.presentError(from: self, title: "", message: BWIL10n.deviceVerificationCancelled, animated: true) {
self.viewModel.process(viewAction: .cancel)
}
}
@@ -29,40 +29,32 @@ final class LaunchLoadingView: UIView, NibLoadable, Themable {
// MARK: - Properties
// bwi: for bum just rotate the bum image for now
@IBOutlet private weak var animationView: UIImageView!
@IBOutlet private weak var animationView: ElementView!
@IBOutlet private weak var statusLabel: UILabel!
private var animationTimeline: Timeline_1!
private let numberFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .ordinal
return formatter
}()
// MARK: - Setup
static func instantiate() -> LaunchLoadingView {
static func instantiate(syncProgress: MXSessionSyncProgress?) -> LaunchLoadingView {
let view = LaunchLoadingView.loadFromNib()
syncProgress?.delegate = view
return view
}
override func awakeFromNib() {
super.awakeFromNib()
self.animationView.image = Asset.Images.launchScreenLogo.image
self.animationView.layer.cornerRadius = 50
self.animationView.layer.masksToBounds = true
/*
let animationTimeline = Timeline_1(view: self.animationView, duration: LaunchAnimation.duration, repeatCount: LaunchAnimation.repeatCount)
animationTimeline.play()
self.animationTimeline = animationTimeline
*/
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
let rotation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.toValue = NSNumber(value: Double.pi * 2)
rotation.duration = 1
rotation.isCumulative = true
rotation.repeatCount = Float.greatestFiniteMagnitude
self.animationView.layer.add(rotation, forKey: "rotationAnimation")
self.statusLabel.isHidden = !MXSDKOptions.sharedInstance().enableSyncProgress
}
// MARK: - Public
@@ -72,3 +64,31 @@ final class LaunchLoadingView: UIView, NibLoadable, Themable {
self.animationView.backgroundColor = theme.backgroundColor
}
}
extension LaunchLoadingView: MXSessionSyncProgressDelegate {
func sessionDidUpdateSyncState(_ state: MXSessionSyncState) {
guard MXSDKOptions.sharedInstance().enableSyncProgress else {
return
}
// Sync may be doing a lot of heavy work on the main thread and the status text
// does not update reliably enough without explicitly refreshing
CATransaction.begin()
statusLabel.text = statusText(for: state)
CATransaction.commit()
}
private func statusText(for state: MXSessionSyncState) -> String {
switch state {
case .serverSyncing(let attempts):
if attempts > 1, let nth = numberFormatter.string(from: NSNumber(value: attempts)) {
return VectorL10n.launchLoadingServerSyncingNthAttempt(nth)
} else {
return VectorL10n.launchLoadingServerSyncing
}
case .processingResponse(let progress):
let percent = Int(floor(progress * 100))
return VectorL10n.launchLoadingProcessingResponse("\(percent)")
}
}
}
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_0" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20037"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -14,21 +14,28 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleAspectFit" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3KG-IR-FPV" customClass="UIImageView">
<rect key="frame" x="95" y="220" width="130" height="128"/>
<view contentMode="scaleAspectFit" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3KG-IR-FPV" customClass="ElementView" customModule="Element" customModuleProvider="target">
<rect key="frame" x="95" y="219" width="130" height="130"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
</accessibility>
</view>
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wzS-bN-Pht">
<rect key="frame" x="20" y="528" width="280" height="0.0"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" systemColor="systemGrayColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="wzS-bN-Pht" secondAttribute="trailing" constant="20" id="Naf-Cc-qLq"/>
<constraint firstAttribute="bottom" secondItem="wzS-bN-Pht" secondAttribute="bottom" constant="40" id="cnE-Pn-Wb2"/>
<constraint firstItem="3KG-IR-FPV" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="ig4-YX-FoT"/>
<constraint firstItem="3KG-IR-FPV" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="r9K-7c-fjh"/>
<constraint firstItem="wzS-bN-Pht" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" id="uZP-JW-dVR"/>
</constraints>
<connections>
<outlet property="animationView" destination="3KG-IR-FPV" id="Are-fn-laY"/>
<outlet property="statusLabel" destination="wzS-bN-Pht" id="Mj2-rn-i5x"/>
</connections>
<point key="canvasLocation" x="136.875" y="132.5"/>
</view>
@@ -37,5 +44,8 @@
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemGrayColor">
<color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
@@ -21,10 +21,10 @@ class LaunchLoadingViewController: UIViewController, Reusable {
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
init() {
init(syncProgress: MXSessionSyncProgress?) {
super.init(nibName: "LaunchLoadingViewController", bundle: nil)
let launchLoadingView = LaunchLoadingView.instantiate()
let launchLoadingView = LaunchLoadingView.instantiate(syncProgress: syncProgress)
launchLoadingView.update(theme: ThemeService.shared().theme)
view.vc_addSubViewMatchingParent(launchLoadingView)
@@ -374,11 +374,6 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer
- (void)resetDeviceId;
#pragma mark - Sync filter
/**
Check if the homeserver supports room members lazy loading.
@param completion the check result.
*/
- (void)supportLazyLoadOfRoomMembers:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion;
/**
Call this method at an appropriate time to attempt dehydrating to a new backup device
@@ -897,6 +897,9 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
MXStrongifyAndReturnIfNil(self);
self->mxSession = nil;
NSString *myUserId = self.mxSession.myUser.userId;
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
[[NSNotificationCenter defaultCenter] removeObserver:self->sessionStateObserver];
self->sessionStateObserver = nil;
@@ -1684,6 +1687,14 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
NSString *myUserId = self.mxSession.myUser.userId;
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
}
// If we cannot resolve this error by retrying, exit early
BOOL isRetryableError = [error.domain isEqualToString:NSURLErrorDomain] || [MXHTTPOperation urlResponseFromError:error] != nil;
if (!isRetryableError)
{
MXLogDebug(@"[MXKAccount] Initial sync will not be retried");
return;
}
// Check if it is a network connectivity issue
AFNetworkReachabilityManager *networkReachabilityManager = [AFNetworkReachabilityManager sharedManager];
@@ -1691,7 +1702,6 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
if (networkReachabilityManager.isReachable)
{
// The problem is not the network
// If we have network, we retry immediately, otherwise the server may clear any cache it has computed thus far
[self launchInitialServerSync];
}
@@ -2085,14 +2095,15 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
#pragma mark - Sync filter
- (void)supportLazyLoadOfRoomMembers:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion
- (void)supportLazyLoadOfRoomMembersWithMatrixVersion:(MXMatrixVersions *)matrixVersions
completion:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion
{
void(^onUnsupportedLazyLoadOfRoomMembers)(NSError *) = ^(NSError *error) {
completion(NO);
};
// Check if the server supports LL sync filter
MXFilterJSONModel *filter = [self syncFilterWithLazyLoadOfRoomMembers:YES];
MXFilterJSONModel *filter = [self syncFilterWithLazyLoadOfRoomMembers:YES supportsNotificationsForThreads:NO];
[mxSession.store filterIdForFilter:filter success:^(NSString * _Nullable filterId) {
if (filterId)
@@ -2103,8 +2114,8 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
else
{
// Check the Matrix versions supported by the HS
[self.mxSession supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) {
if (matrixVersions)
{
if (matrixVersions.supportLazyLoadMembers)
{
// The HS supports LL
@@ -2114,8 +2125,11 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
{
onUnsupportedLazyLoadOfRoomMembers(nil);
}
} failure:onUnsupportedLazyLoadOfRoomMembers];
}
else
{
completion(NO);
}
}
} failure:onUnsupportedLazyLoadOfRoomMembers];
}
@@ -2130,28 +2144,42 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
// Check settings
BOOL syncWithLazyLoadOfRoomMembersSetting = [MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers;
if (syncWithLazyLoadOfRoomMembersSetting)
{
// Check if the server supports LL sync filter before enabling it
[self supportLazyLoadOfRoomMembers:^(BOOL supportLazyLoadOfRoomMembers) {
void(^buildSyncFilter)(MXMatrixVersions *) = ^(MXMatrixVersions *matrixVersions) {
BOOL supportsNotificationsForThreads = matrixVersions ? matrixVersions.supportsNotificationsForThreads : NO;
if (syncWithLazyLoadOfRoomMembersSetting)
{
// Check if the server supports LL sync filter before enabling it
[self supportLazyLoadOfRoomMembersWithMatrixVersion:matrixVersions completion:^(BOOL supportLazyLoadOfRoomMembers) {
if (supportLazyLoadOfRoomMembers)
{
completion([self syncFilterWithLazyLoadOfRoomMembers:YES]);
}
else
{
// No support from the HS
// Disable the setting. That will avoid to make a request at every startup
[MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers = NO;
completion([self syncFilterWithLazyLoadOfRoomMembers:NO]);
}
}];
}
else
{
completion([self syncFilterWithLazyLoadOfRoomMembers:NO]);
}
if (supportLazyLoadOfRoomMembers)
{
completion([self syncFilterWithLazyLoadOfRoomMembers:YES
supportsNotificationsForThreads:supportsNotificationsForThreads]);
}
else
{
// No support from the HS
// Disable the setting. That will avoid to make a request at every startup
[MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers = NO;
completion([self syncFilterWithLazyLoadOfRoomMembers:NO
supportsNotificationsForThreads:supportsNotificationsForThreads]);
}
}];
}
else
{
completion([self syncFilterWithLazyLoadOfRoomMembers:NO supportsNotificationsForThreads:supportsNotificationsForThreads]);
}
};
[mxSession supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) {
buildSyncFilter(matrixVersions);
} failure:^(NSError *error) {
MXLogWarning(@"[MXAccount] buildSyncFilter: failed to get supported versions: %@", error);
buildSyncFilter(nil);
}];
}
/**
@@ -2160,7 +2188,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
@param syncWithLazyLoadOfRoomMembers enable LL support.
@return the sync filter to use.
*/
- (MXFilterJSONModel *)syncFilterWithLazyLoadOfRoomMembers:(BOOL)syncWithLazyLoadOfRoomMembers
- (MXFilterJSONModel *)syncFilterWithLazyLoadOfRoomMembers:(BOOL)syncWithLazyLoadOfRoomMembers supportsNotificationsForThreads:(BOOL)supportsNotificationsForThreads
{
MXFilterJSONModel *syncFilter;
NSUInteger limit = 10;
@@ -2195,11 +2223,11 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
// Set that limit in the filter
if (syncWithLazyLoadOfRoomMembers)
{
syncFilter = [MXFilterJSONModel syncFilterForLazyLoadingWithMessageLimit:limit];
syncFilter = [MXFilterJSONModel syncFilterForLazyLoadingWithMessageLimit:limit unreadThreadNotifications:supportsNotificationsForThreads];
}
else
{
syncFilter = [MXFilterJSONModel syncFilterWithMessageLimit:limit];
syncFilter = [MXFilterJSONModel syncFilterWithMessageLimit:limit unreadThreadNotifications:supportsNotificationsForThreads];
}
// TODO: We could extend the filter to match other settings (self.showAllEventsInRoomHistory,
@@ -518,7 +518,6 @@
- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset
{
static UITextView* measurementTextView = nil;
static UITextView* measurementTextViewWithoutInset = nil;
@@ -527,24 +526,23 @@
if (!measurementTextView)
{
measurementTextView = [[UITextView alloc] init];
measurementTextViewWithoutInset = [[UITextView alloc] init];
// Remove the container inset: this operation impacts only the vertical margin.
// Note: consider textContainer.lineFragmentPadding to remove horizontal margin
measurementTextViewWithoutInset.textContainerInset = UIEdgeInsetsZero;
}
// Select the right text view for measurement
UITextView *selectedTextView = (removeVerticalInset ? measurementTextViewWithoutInset : measurementTextView);
selectedTextView.frame = CGRectMake(0, 0, _maxTextViewWidth, 0);
selectedTextView.attributedText = attributedText;
// Force the layout manager to layout the text, fixes problems starting iOS 16
[selectedTextView.layoutManager ensureLayoutForTextContainer:selectedTextView.textContainer];
CGSize size = [selectedTextView sizeThatFits:selectedTextView.frame.size];
// Manage the case where a string attribute has a single paragraph with a left indent
// In this case, [UITextView sizeThatFits] ignores the indent and return the width
// of the text only.
@@ -557,8 +555,10 @@
{
size.width = size.width + paragraphStyle.headIndent;
}
return size;
}
return CGSizeZero;
}
@@ -985,8 +985,19 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
else if (nil == localEcho)
{
// Process here incoming events, and outgoing events sent from another device.
[self queueEventForProcessing:event withRoomState:roomState direction:MXTimelineDirectionForwards];
[self processQueuedEvents:nil];
if (self.threadId == nil && event.isInThread)
{
NSInteger index = [self indexOfCellDataWithEventId:event.relatesTo.eventId];
if (index != NSNotFound)
{
[self reloadNotifying:NO];
}
}
else
{
[self queueEventForProcessing:event withRoomState:roomState direction:MXTimelineDirectionForwards];
[self processQueuedEvents:nil];
}
}
}
}];
@@ -1373,6 +1384,11 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
// ignore the event
return NO;
}
// Ignore voice message related to an actual voice broadcast.
if (event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] != nil) {
return NO;
}
}
// Check for undecryptable messages that were sent while the user was not in the room and hide them
@@ -2358,15 +2374,61 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
// Update cell data we have received a read receipt for
NSArray *readEventIds = receiptEvent.readReceiptEventIds;
for (NSString* eventId in readEventIds)
if (RiotSettings.shared.enableThreads)
{
MXKRoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId];
if (cellData)
NSArray *readThreadIds = receiptEvent.readReceiptThreadIds;
for (int i = 0 ; i < readEventIds.count ; i++)
{
NSString *eventId = readEventIds[i];
MXKRoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId];
if (cellData)
{
if ([readThreadIds[i] isEqualToString:kMXEventUnthreaded])
{
// Unthreaded RR must be propagated through all threads.
[self.mxSession.threadingService allThreadsInRoomWithId:self.roomId onlyParticipated:NO completion:^(NSArray<id<MXThreadProtocol>> *threads) {
NSMutableArray *threadIds = [NSMutableArray arrayWithObject:kMXEventTimelineMain];
for (id<MXThreadProtocol> thread in threads)
{
[threadIds addObject:thread.id];
}
for (NSString *threadId in threadIds)
{
@synchronized(self->bubbles)
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:eventId threadId:threadId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
}
}];
}
else
{
NSString *threadId = readThreadIds[i];
@synchronized(self->bubbles)
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:eventId threadId:threadId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
}
}
}
}
else
{
// If
for (NSString *eventId in readEventIds)
{
MXKRoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId];
@synchronized(self->bubbles)
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:eventId inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
[self addReadReceiptsForEvent:eventId threadId:kMXEventTimelineMain inCellDatas:self->bubbles startingAtCellData:cellData completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
@@ -3512,7 +3574,10 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
@autoreleasepool
{
dispatch_group_enter(dispatchGroup);
[self addReadReceiptsForEvent:queuedEvent.event.eventId inCellDatas:self->bubblesSnapshot startingAtCellData:self->eventIdToBubbleMap[queuedEvent.event.eventId] completion:^{
[self addReadReceiptsForEvent:queuedEvent.event.eventId
threadId:queuedEvent.event.threadId
inCellDatas:self->bubblesSnapshot
startingAtCellData:self->eventIdToBubbleMap[queuedEvent.event.eventId] completion:^{
dispatch_group_leave(dispatchGroup);
}];
}
@@ -3667,16 +3732,22 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
If the event is not displayed, read receipts will be added to a previous displayed message.
@param eventId the id of the event.
@param threadId the Id of the thread related of the event.
@param cellDatas the working array of cell datas.
@param cellData the original cell data the event belongs to.
@param completion completion block
*/
- (void)addReadReceiptsForEvent:(NSString*)eventId inCellDatas:(NSArray<id<MXKRoomBubbleCellDataStoring>>*)cellDatas startingAtCellData:(id<MXKRoomBubbleCellDataStoring>)cellData completion:(void (^)(void))completion
- (void)addReadReceiptsForEvent:(NSString*)eventId
threadId:(NSString *)threadId
inCellDatas:(NSArray<id<MXKRoomBubbleCellDataStoring>>*)cellDatas
startingAtCellData:(id<MXKRoomBubbleCellDataStoring>)cellData
completion:(void (^)(void))completion
{
if (self.showBubbleReceipts)
{
if (self.room)
{
[self.room getEventReceipts:eventId sorted:YES completion:^(NSArray<MXReceiptData *> * _Nonnull readReceipts) {
[self.room getEventReceipts:eventId threadId:threadId sorted:YES completion:^(NSArray<MXReceiptData *> * _Nonnull readReceipts) {
if (readReceipts.count)
{
NSInteger cellDataIndex = [cellDatas indexOfObject:cellData];
@@ -3686,6 +3757,14 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
}
}
if (!RiotSettings.shared.enableThreads)
{
// If threads are disabled, we may have several threaded RR with same userId
// but different threadId within the same timeline.
// We just need to keep the latest one.
[self clearDuplicatedReadReceiptsInCellDatas:cellDatas];
}
if (completion)
{
completion();
@@ -3771,6 +3850,45 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
}
}
/**
Clear all potential duplicated RR with same user ID within a given list of cell data.
This is needed for client with threads disabled in order to clean threaded RRs.
@param cellDatas the working array of cell datas.
*/
- (void)clearDuplicatedReadReceiptsInCellDatas:(NSArray<id<MXKRoomBubbleCellDataStoring>>*)cellDatas
{
NSMutableSet<NSString *> *seenUserIds = [NSMutableSet set];
for (id<MXKRoomBubbleCellDataStoring> cellData in cellDatas.reverseObjectEnumerator)
{
if ([cellData isKindOfClass:MXKRoomBubbleCellData.class])
{
MXKRoomBubbleCellData *roomBubbleCellData = (MXKRoomBubbleCellData*)cellData;
for (MXKRoomBubbleComponent *component in roomBubbleCellData.bubbleComponents)
{
if (component.attributedTextMessage)
{
if (roomBubbleCellData.readReceipts[component.event.eventId])
{
NSArray<MXReceiptData*> *currentReadReceipts = roomBubbleCellData.readReceipts[component.event.eventId];
NSMutableArray<MXReceiptData*> *newReadReceipts = [NSMutableArray array];
for (MXReceiptData *readReceipt in currentReadReceipts)
{
if (![seenUserIds containsObject:readReceipt.userId])
{
[newReadReceipts addObject:readReceipt];
[seenUserIds addObject:readReceipt.userId];
}
}
[self updateCellData:roomBubbleCellData withReadReceipts:newReadReceipts forEventId:component.event.eventId];
}
}
}
}
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
@@ -47,6 +47,7 @@ typedef enum : NSUInteger
@class MXKRoomInputToolbarView;
@class MXKImageView;
@protocol MXKRoomInputToolbarViewDelegate <NSObject>
/**
@@ -381,4 +382,6 @@ typedef enum : NSUInteger
*/
@property (nonatomic) NSAttributedString *attributedTextMessage;
- (void)dismissValidationView:(MXKImageView*)validationView;
@end
@@ -105,6 +105,8 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag)
*/
@property(nonatomic) NSInteger componentIndexOfSentMessageTick;
@property(nonatomic, strong) NSString *voiceBroadcastState;
/**
Indicate that both the text message layout and any additional content height are no longer
valid and should be recomputed before presentation in a bubble cell. This could be due
+34 -11
View File
@@ -186,23 +186,45 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
else if ([event.type isEqualToString:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType])
{
VoiceBroadcastInfo *voiceBroadcastInfo = [VoiceBroadcastInfo modelFromJSON: event.content];
// Check if the state event corresponds to the beginning of a voice broadcast
if ([VoiceBroadcastInfo isStartedFor:voiceBroadcastInfo.state])
{
// This state event corresponds to the beginning of a voice broadcast
// Check whether this is a local live broadcast to display it with the recorder view or not
// Note: Because of race condition, the voiceBroadcastService may be running without id here (the sync response may be received before
// the success of the event sending), in that case, we will display a recorder view by default to let the user be able to stop a potential record.
if ([event.sender isEqualToString: self.mxSession.myUserId] &&
[voiceBroadcastInfo.deviceId isEqualToString:self.mxSession.myDeviceId] &&
self.mxSession.voiceBroadcastService != nil &&
([event.eventId isEqualToString: self.mxSession.voiceBroadcastService.voiceBroadcastInfoEventId] ||
self.mxSession.voiceBroadcastService.voiceBroadcastInfoEventId == nil))
// Retrieve the most recent voice broadcast info.
MXEvent *lastVoiceBroadcastInfoEvent = [roomDataSource.roomState stateEventsWithType:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType].lastObject;
if (event.originServerTs > lastVoiceBroadcastInfoEvent.originServerTs)
{
self.tag = RoomBubbleCellDataTagVoiceBroadcastRecord;
lastVoiceBroadcastInfoEvent = event;
}
VoiceBroadcastInfo *lastVoiceBroadcastInfo = [VoiceBroadcastInfo modelFromJSON: lastVoiceBroadcastInfoEvent.content];
// Handle the specific case where the state event is a started voice broadcast (the voiceBroadcastId is the event id itself).
if (!lastVoiceBroadcastInfo.voiceBroadcastId)
{
lastVoiceBroadcastInfo.voiceBroadcastId = lastVoiceBroadcastInfoEvent.eventId;
}
// Check if the voice broadcast is still alive.
if ([lastVoiceBroadcastInfo.voiceBroadcastId isEqualToString:event.eventId] && ![VoiceBroadcastInfo isStoppedFor:lastVoiceBroadcastInfo.state])
{
// Check whether this broadcast is sent from the currrent session to display it with the recorder view or not.
if ([event.stateKey isEqualToString:self.mxSession.myUserId] &&
[voiceBroadcastInfo.deviceId isEqualToString:self.mxSession.myDeviceId])
{
self.tag = RoomBubbleCellDataTagVoiceBroadcastRecord;
}
else
{
self.tag = RoomBubbleCellDataTagVoiceBroadcastPlayback;
}
self.voiceBroadcastState = lastVoiceBroadcastInfo.state;
}
else
{
self.tag = RoomBubbleCellDataTagVoiceBroadcastPlayback;
self.voiceBroadcastState = VoiceBroadcastInfo.stoppedValue;
}
}
else
@@ -213,8 +235,9 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
{
// This state event corresponds to the end of a voice broadcast
// Force the tag of the potential cellData which corresponds to the started event to switch the display from recorder to listener
id<MXKRoomBubbleCellDataStoring> bubbleData = [roomDataSource cellDataOfEventWithEventId:voiceBroadcastInfo.eventId];
RoomBubbleCellData *bubbleData = [roomDataSource cellDataOfEventWithEventId:voiceBroadcastInfo.voiceBroadcastId];
bubbleData.tag = RoomBubbleCellDataTagVoiceBroadcastPlayback;
bubbleData.voiceBroadcastState = VoiceBroadcastInfo.stoppedValue;
}
}
self.collapsable = NO;
@@ -120,7 +120,7 @@ const CGFloat kTypingCellHeight = 24;
// Sadly, we need to make sure we have fetched all room members from the HS
// to be able to display read receipts
if (![self.mxSession.store hasLoadedAllRoomMembersForRoom:self.roomId])
if (!self.isPeeking && ![self.mxSession.store hasLoadedAllRoomMembersForRoom:self.roomId])
{
[self.room members:^(MXRoomMembers *roomMembers) {
MXLogDebug(@"[MXKRoomDataSource] finalizeRoomDataSource: All room members have been retrieved");
@@ -437,7 +437,7 @@ const CGFloat kTypingCellHeight = 24;
id<RoomTimelineCellDecorator> cellDecorator = [RoomTimelineConfiguration shared].currentStyle.cellDecorator;
// Finalize cell view customization here
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class])
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class] && ![cell isKindOfClass:MXKRoomEmptyBubbleTableViewCell.class])
{
MXKRoomBubbleTableViewCell *bubbleCell = (MXKRoomBubbleTableViewCell*)cell;
[self resetAccessibilityForCell:bubbleCell];
@@ -27,8 +27,8 @@ public class ThreadDataSource: RoomDataSource {
public override func finalizeInitialization() {
super.finalizeInitialization()
showReadMarker = false
showBubbleReceipts = false
showReadMarker = true
showBubbleReceipts = true
showTypingRow = false
NotificationCenter.default.addObserver(self,
@@ -42,22 +42,6 @@ public class ThreadDataSource: RoomDataSource {
object: nil)
}
public override var showReadMarker: Bool {
get {
return false
} set {
_ = newValue
}
}
public override var showBubbleReceipts: Bool {
get {
return false
} set {
_ = newValue
}
}
public override class func load(withRoomId roomId: String!,
initialEventId: String!,
threadId: String!,
+2 -2
View File
@@ -214,14 +214,14 @@ typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) {
@property (weak, nonatomic) IBOutlet UITableView *bubblesTableView;
@property (weak, nonatomic) IBOutlet UIView *roomTitleViewContainer;
@property (weak, nonatomic) IBOutlet UIView *roomInputToolbarContainer;
@property (strong, nonatomic) IBOutlet UIView *roomInputToolbarContainer;
@property (weak, nonatomic) IBOutlet UIView *roomActivitiesContainer;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bubblesTableViewTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bubblesTableViewBottomConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *roomActivitiesContainerHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *roomInputToolbarContainerHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *roomInputToolbarContainerBottomConstraint;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *roomInputToolbarContainerBottomConstraint;
#pragma mark - Class methods

Some files were not shown because too many files have changed in this diff Show More