mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-19 06:02:12 +02:00
Merge branch 'release/v2.7.0'
This commit is contained in:
@@ -53,23 +53,10 @@ jobs:
|
||||
contains(github.event.issue.labels.*.name, 'O-Frequent')) ||
|
||||
contains(github.event.issue.labels.*.name, 'A11y'))
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc0sUA"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
project-url: https://github.com/orgs/vector-im/projects/18
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
add_product_issues_to_project:
|
||||
name: X-Needs-Product to Design project board
|
||||
@@ -77,138 +64,10 @@ jobs:
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'X-Needs-Product')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4AAg6N"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
Delight_issues_to_board:
|
||||
name: Spaces issues to Delight project board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Team: Delight') ||
|
||||
contains(github.event.issue.labels.*.name, 'Z-AppLayout')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc1HvQ"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
move_voice-message_issues:
|
||||
name: A-Voice Messages to voice message board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'A-Voice Messages')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc2KCw"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
move_message_bubble_issues:
|
||||
name: A-Message-Bubbles to Message bubble board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'A-Message-Bubbles')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc3m-g"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
move_FTUE_issues:
|
||||
name: Z-FTUE to FTUE board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Z-FTUE')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4AAqVx"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
move_WTF_issues:
|
||||
name: Z-WTF to WTF board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Z-WTF')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4AArk0"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
project-url: https://github.com/orgs/vector-im/projects/28
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
ex_plorers:
|
||||
name: Add labelled issues to X-Plorer project
|
||||
@@ -216,23 +75,10 @@ jobs:
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Team: Element X Feature')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4ALoFY"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
project-url: https://github.com/orgs/vector-im/projects/73
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
ps_features1:
|
||||
name: Add labelled issues to PS features team 1
|
||||
@@ -245,23 +91,10 @@ jobs:
|
||||
(contains(github.event.issue.labels.*.name, 'A-Session-Mgmt') &&
|
||||
contains(github.event.issue.labels.*.name, 'A-User-Settings'))
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4AHJKF"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
project-url: https://github.com/orgs/vector-im/projects/56
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
ps_features2:
|
||||
name: Add labelled issues to PS features team 2
|
||||
@@ -270,23 +103,10 @@ jobs:
|
||||
contains(github.event.issue.labels.*.name, 'A-DM-Start') ||
|
||||
contains(github.event.issue.labels.*.name, 'A-Broadcast')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4AHJKd"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
project-url: https://github.com/orgs/vector-im/projects/58
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
ps_features3:
|
||||
name: Add labelled issues to PS features team 3
|
||||
@@ -294,23 +114,10 @@ jobs:
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4AHJKW"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
project-url: https://github.com/orgs/vector-im/projects/57
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
voip:
|
||||
name: Add labelled issues to VoIP project board
|
||||
@@ -318,20 +125,7 @@ jobs:
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Team: VoIP')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
id: add_to_project
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PVT_kwDOAM0swc4ABMIk"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
project-url: https://github.com/orgs/vector-im/projects/41
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
+58
@@ -1,3 +1,61 @@
|
||||
## Changes in 1.10.12 (2023-05-16)
|
||||
|
||||
✨ Features
|
||||
|
||||
- Add composer suggestions for slash commands ([#7493](https://github.com/vector-im/element-ios/issues/7493))
|
||||
|
||||
🙌 Improvements
|
||||
|
||||
- Crypto: Deprecate MXLegacyCrypto ([#7508](https://github.com/vector-im/element-ios/pull/7508))
|
||||
- Add a flag in the build settings to force the user to define a homeserver instead of using the default one. ([#7541](https://github.com/vector-im/element-ios/pull/7541))
|
||||
- Upgrade MatrixSDK version ([v0.26.10](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.26.10)).
|
||||
- Add an audio alert when the voice broadcast recording is automatically paused ([#7504](https://github.com/vector-im/element-ios/issues/7504))
|
||||
- Timeline: Remove the matrix ID displayed when someone has changed its display name. ([#7517](https://github.com/vector-im/element-ios/issues/7517))
|
||||
|
||||
🐛 Bugfixes
|
||||
|
||||
- Fix an issue where the Secrets Reset screen would open twice. ([#7404](https://github.com/vector-im/element-ios/pull/7404))
|
||||
- Make sure to use the chosen language for the VoiceOver voice too. ([#7493](https://github.com/vector-im/element-ios/pull/7493))
|
||||
- Fix the position of the send confirmation icon. ([#7512](https://github.com/vector-im/element-ios/pull/7512))
|
||||
- Disable accessibility for emojis during session verification. ([#7521](https://github.com/vector-im/element-ios/pull/7521))
|
||||
- Fix accessibility when entering the PIN to unlock the app. ([#7522](https://github.com/vector-im/element-ios/pull/7522))
|
||||
- Fix voiceover order of room creation header and message composer. ([#7543](https://github.com/vector-im/element-ios/pull/7543))
|
||||
- Fix: The last event description text color now matches the active theme. ([#7545](https://github.com/vector-im/element-ios/pull/7545))
|
||||
- Fix mention pills display in thread list ([#7322](https://github.com/vector-im/element-ios/issues/7322))
|
||||
- Poll: The timeline sometimes displayed closed polls in the wrong order. ([#7497](https://github.com/vector-im/element-ios/issues/7497))
|
||||
- Fix a flickering issue when the timeline datasource is reloaded. ([#7523](https://github.com/vector-im/element-ios/issues/7523))
|
||||
- Fix the position of the marker highlighting an event. ([#7526](https://github.com/vector-im/element-ios/issues/7526))
|
||||
- Fix application crashing when opening a thread with RTE enabled ([#7530](https://github.com/vector-im/element-ios/issues/7530))
|
||||
- Labs: Rich Text Editor: Fix partial text messages not being saved for each room ([#7535](https://github.com/vector-im/element-ios/issues/7535))
|
||||
|
||||
|
||||
## Changes in 1.10.11 (2023-04-18)
|
||||
|
||||
🙌 Improvements
|
||||
|
||||
- Upgrade MatrixSDK version ([v0.26.9](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.26.9)).
|
||||
- Labs: Rich Text Editor: Integrate version 2.0.0 with mention Pills support. ([#7442](https://github.com/vector-im/element-ios/issues/7442))
|
||||
|
||||
🐛 Bugfixes
|
||||
|
||||
- Continue to display pills for matrix.to permalinks if a custom permalinkBaseUrl is set. ([#7482](https://github.com/vector-im/element-ios/pull/7482))
|
||||
- Add a foreground color attribute for the unformattable event error message. ([#7501](https://github.com/vector-im/element-ios/pull/7501))
|
||||
- Fixed a bug that prevented audio messages that were not .mp4 to be played in the timeline ([#7451](https://github.com/vector-im/element-ios/issues/7451))
|
||||
- Fix user suggestion list item height on iOS 16+ ([#7492](https://github.com/vector-im/element-ios/issues/7492))
|
||||
|
||||
🧱 Build
|
||||
|
||||
- Pinned used Xcode version to 14.2 as newer version fail ASC validation ([#7476](https://github.com/vector-im/element-ios/issues/7476))
|
||||
|
||||
|
||||
## Changes in 1.10.10 (2023-04-12)
|
||||
|
||||
🙌 Improvements
|
||||
|
||||
- Crypto: Enable Rust Crypto for all users ([#7485](https://github.com/vector-im/element-ios/pull/7485))
|
||||
- Upgrade MatrixSDK version ([v0.26.7](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.26.7)).
|
||||
|
||||
|
||||
## Changes in 1.10.9 (2023-04-04)
|
||||
|
||||
🙌 Improvements
|
||||
|
||||
+38
-1
@@ -1,4 +1,41 @@
|
||||
Changes in BWI project 2.5.0 (2023-05-09)
|
||||
Changes in BWI project 2.7.0 (2023-07-04)
|
||||
===================================================
|
||||
|
||||
Upstream merge ✨:
|
||||
|
||||
- v1.10.12
|
||||
|
||||
Features ✨:
|
||||
- New show participants toggle for polls (#4393)
|
||||
|
||||
Improvements 🙌:
|
||||
- Roomavatar can now be deleted (#4743)
|
||||
- Remove "black" theme (#4744)
|
||||
- Open links in system browser (#1678)
|
||||
- Add imprint (#4682)
|
||||
- Text changes for DM creation (#4736)
|
||||
- Add accessibility statement (#4772)
|
||||
- Matomo tracking of poll creation (#4795)
|
||||
- Matomo tracking of voice messages (#4795)
|
||||
- Matomo tracking of forwarding messages (#4795)
|
||||
|
||||
Bugfix 🐛:
|
||||
- Disable logout when there is no internet connection (#3539)
|
||||
- Disable permalink sharing for private rooms (#4390)
|
||||
- Fix manual verification (#4710)
|
||||
- Fix QR code scanning (#4748)
|
||||
- Show app logo in pin code screen (#4828)
|
||||
- Update "all chats" filter on logout/login (#4573)
|
||||
|
||||
Translations 🗣 :
|
||||
- English translations passphrase (#4706)
|
||||
|
||||
SDK API changes ⚠️:
|
||||
|
||||
Build 🧱:
|
||||
|
||||
|
||||
Changes in BWI project 2.6.0 (2023-05-09)
|
||||
===================================================
|
||||
|
||||
Upstream merge ✨:
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
//
|
||||
|
||||
// Version
|
||||
MARKETING_VERSION = 2.6.0
|
||||
MARKETING_VERSION = 2.7.0
|
||||
CURRENT_PROJECT_VERSION = 20220714163152
|
||||
|
||||
@@ -124,6 +124,8 @@ class BWIBuildSettings: NSObject {
|
||||
var bwiUserLabelParticipantSorting = true
|
||||
|
||||
var bwiShowClosedPolls = true
|
||||
var bwiPollShowParticipantsToggle = true
|
||||
var bwiPollVisibleVotes = 5
|
||||
var bwiShowThreads = false
|
||||
|
||||
var bwiShowRoomCreationSectionFooter = false
|
||||
@@ -185,7 +187,16 @@ class BWIBuildSettings: NSObject {
|
||||
"4d5b6dcf02396274be58a69c4bbeba975b529f6b19c504fc99a37892ee1cf0b5",
|
||||
"0d157119821bd9d76ac4f24c7f44f56e6bb5b766a6d5ee7dad6634420e79271a",
|
||||
"e3573fe09d518cce80cececedf80f8e0020cbc150f22db8b64827bff2e27abd9",
|
||||
"b76a62ccd8ea70d01c3a35ec3839e49ed2c83c8e3276f40a1b2c2cdf7cd77d01"
|
||||
"b76a62ccd8ea70d01c3a35ec3839e49ed2c83c8e3276f40a1b2c2cdf7cd77d01",
|
||||
"4a610a4d5fd3d8a1e1fd5669abdf8e0c5f7f5ff0c6b559e0f360cfa092ecb115",
|
||||
"32752f6d21f3005587941415cd64892ee28c19e6e01ed307edf9ddf4f6a91583",
|
||||
"704c6eaa107b13ef0694eb7ddd043bb6f595b53670a2e0c3c16e199947a9e013",
|
||||
"6921f031357cf63fb8538d9a1d1973efae95899907fdbf05a05082b6d1a6d0fb",
|
||||
"9f960fc663f5eaae67eecff75b137dea130b3ab1cf889c45fc74c688a48aea30",
|
||||
"160c35279484a027031b131583f3f203b1166306bab214355b00cf28502bce11",
|
||||
"d5a7298dde23aa0269c4cbd3b1a543e6ede94ce78fc20e4bfb888eb6057b5c52",
|
||||
"00136d830dd2acd5047efcf8429e939ef7ef97a84bef1930df86aace3f855265",
|
||||
"64cbbeea37237814445b65c941d010b9d5d024e4c584a476864b00c7c9909bce"
|
||||
]
|
||||
|
||||
// use a different badge color if the user was mentioned in a room
|
||||
@@ -436,8 +447,9 @@ class BWIBuildSettings: NSObject {
|
||||
var authScreenShowTestServerOptions = true
|
||||
var authScreenShowSocialLoginSection = false
|
||||
|
||||
// MARK: - Cross-signing (bwi=true)
|
||||
var disableSelfUserVerification = false
|
||||
// MARK: - Self Verification not crosssigning (bwi=true)
|
||||
var disableSelfUserVerification = true
|
||||
var disableCrosssigning = false
|
||||
var additionalSelfVerfificationAlert = false
|
||||
var showNoOtherDeviceError = false
|
||||
|
||||
@@ -489,7 +501,7 @@ class BWIBuildSettings: NSObject {
|
||||
var passwordIndicatorOnLogin = true
|
||||
|
||||
// MARK: Displays the element base version on the settings screen
|
||||
var elementBaseVersion = "1.10.9"
|
||||
var elementBaseVersion = "1.10.12"
|
||||
|
||||
var showElementBaseVersion = true
|
||||
|
||||
@@ -617,6 +629,22 @@ class BWIBuildSettings: NSObject {
|
||||
// MARK: Rust Encryption
|
||||
var useRustEncryption = false
|
||||
|
||||
// MARK: Color Theme
|
||||
var useNewBumColors = false
|
||||
|
||||
// MARK: Sessions Manager
|
||||
var enableNewSessionManagerByDefault = false
|
||||
|
||||
// MARK: Accessibility declaration
|
||||
// bwi flag for showing accessibility declaration on login screen and in settings
|
||||
var bwiShowAccessibilityDeclaration = false
|
||||
// internal markdown file for accessibility declaration in en and de.
|
||||
var accessibilityDeclarationFileDe = ""
|
||||
var accessibilityDeclarationFileEn = ""
|
||||
|
||||
// MARK: Voice Broadcast
|
||||
var enableLabFeatureVoiceBroadcasts = false
|
||||
|
||||
// MARK: WYSIWYG
|
||||
var enableLabFeatureWYSIWYG = false
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import Foundation
|
||||
extension BWIBuildSettings {
|
||||
|
||||
func overrideTargetSpecificSettings() {
|
||||
useNewBumColors = true
|
||||
secondaryAppName = "BundesMessenger"
|
||||
settingsScreenShowLabSettings = true
|
||||
authScreenShowRegister = true
|
||||
@@ -32,6 +33,10 @@ extension BWIBuildSettings {
|
||||
bwiLocationShareButtonVisible = false
|
||||
bwiLoginFlowLayout = false
|
||||
useRustEncryption = true
|
||||
|
||||
enableLabFeatureVoiceBroadcasts = true
|
||||
enableNewSessionManagerByDefault = true
|
||||
enableLabFeatureWYSIWYG = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2021 Vector Creations 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.
|
||||
//
|
||||
|
||||
|
||||
// App identity
|
||||
BUNDLE_DISPLAY_NAME = BuM-Open
|
||||
BASE_BUNDLE_IDENTIFIER = de.bwi.messenger-open
|
||||
APPLICATION_GROUP_IDENTIFIER = group.de.messenger-open
|
||||
APPLICATION_SCHEME = element
|
||||
|
||||
// Team
|
||||
DEVELOPMENT_TEAM = Q111Q11QQ1
|
||||
|
||||
|
||||
// Provisioning profiles
|
||||
RIOT_PROVISIONING_PROFILE_SPECIFIER = Vector App Store
|
||||
RIOT_PROVISIONING_PROFILE = 7579fa6f-9887-415e-90fc-2c7acd8812e6
|
||||
|
||||
NSE_PROVISIONING_PROFILE_SPECIFIER = "Vector NSE: App Store"
|
||||
NSE_PROVISIONING_PROFILE = e73107b2-1bfe-4615-be3e-39fd4dcb2af0
|
||||
|
||||
SHARE_EXTENSION_PROVISIONING_PROFILE_SPECIFIER = "Vector Share Extension: App Store"
|
||||
SHARE_EXTENSION_PROVISIONING_PROFILE = 8c797ca0-0440-49bd-be8d-11d761152995
|
||||
|
||||
SIRI_INTENTS_PROVISIONING_PROFILE_SPECIFIER = "Vector Siri Intents: App Store"
|
||||
SIRI_INTENTS_PROVISIONING_PROFILE = 1690e81a-5ad3-4d99-b578-02693579be71
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
/*
|
||||
* Copyright (c) 2023 BWI GmbH
|
||||
*
|
||||
* 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 BWIBuildSettings {
|
||||
|
||||
func overrideTargetSpecificSettings() {
|
||||
secondaryAppName = "BundesMessenger"
|
||||
locationSharingEnabled = false
|
||||
bwiLocationShareButtonVisible = false
|
||||
bwiLoginFlowLayout = false
|
||||
authScreenShowTestServerOptions = false
|
||||
|
||||
enableNewSessionManagerByDefault = true
|
||||
|
||||
bwiEnableLoginProtection = false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -98,10 +98,15 @@ final class BuildSettings: NSObject {
|
||||
|
||||
// MARK: - Server configuration
|
||||
|
||||
// Default servers proposed on the authentication screen
|
||||
/// Force the user to set a homeserver instead of using the default one
|
||||
static let forceHomeserverSelection = false
|
||||
|
||||
/// Default server proposed on the authentication screen
|
||||
static let serverConfigDefaultHomeserverUrlString = "https://matrix.org"
|
||||
static let serverConfigDefaultIdentityServerUrlString = "https://vector.im"
|
||||
|
||||
/// Default identity server
|
||||
static let serverConfigDefaultIdentityServerUrlString = "https://vector.im"
|
||||
|
||||
static let serverConfigSygnalAPIUrlString = "https://matrix.org/_matrix/push/v1/notify"
|
||||
|
||||
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
# setConfig.sh
|
||||
#
|
||||
# Copyright (c) 2023 BWI GmbH
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
cp -vf ../Config/BuM-Open/AppIdentifiers-bum-open.xcconfig ../Config/AppIdentifiers.xcconfig
|
||||
@@ -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.26.6'
|
||||
$matrixSDKVersion = '= 0.26.10'
|
||||
# $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://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk', :tag => 'v0.26.6.1_bwi' }
|
||||
$matrixSDKVersionSpec = { :git => 'https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk', :tag => 'v0.26.10_bwi' }
|
||||
|
||||
# Method to import the MatrixSDK
|
||||
def import_MatrixSDK
|
||||
@@ -155,6 +155,26 @@ abstract_target 'RiotPods' do
|
||||
|
||||
pod 'FLEX', '~> 4.5.0', :configurations => ['Debug']
|
||||
end
|
||||
|
||||
target "BuM-Open" do
|
||||
import_MatrixSDK
|
||||
import_MatrixKit_pods
|
||||
|
||||
import_SwiftUI_pods
|
||||
|
||||
pod 'UICollectionViewLeftAlignedLayout', '~> 1.0.2'
|
||||
pod 'UICollectionViewRightAlignedLayout', '~> 0.0.3'
|
||||
pod 'KTCenterFlowLayout', '~> 1.3.1'
|
||||
pod 'FlowCommoniOS', '~> 1.12.0'
|
||||
pod 'DTTJailbreakDetection', '~> 0.4.0'
|
||||
pod 'ReadMoreTextView', '~> 3.0.1'
|
||||
pod 'SwiftBase32', '~> 0.9.0'
|
||||
pod 'SwiftJWT', '~> 3.6.200'
|
||||
pod 'SideMenu', '~> 6.5'
|
||||
pod 'DSWaveformImage', '~> 6.1.1'
|
||||
|
||||
pod 'FLEX', '~> 4.5.0', :configurations => ['Debug']
|
||||
end
|
||||
|
||||
target "RiotSwiftUI" do
|
||||
import_SwiftUI_pods
|
||||
|
||||
+62
-20
@@ -20,6 +20,24 @@ PODS:
|
||||
- Down (0.11.0)
|
||||
- DSBottomSheet (0.3.0)
|
||||
- DSWaveformImage (6.1.1)
|
||||
- DTCoreText (1.6.26):
|
||||
- DTCoreText/Core (= 1.6.26)
|
||||
- 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):
|
||||
- DTFoundation/Core (~> 1.7.5)
|
||||
- DTFoundation/DTAnimatedGIF (~> 1.7.5)
|
||||
- DTFoundation/DTHTMLParser (~> 1.7.5)
|
||||
- DTFoundation/UIKit (~> 1.7.5)
|
||||
- DTFoundation/Core (1.7.18)
|
||||
- DTFoundation/DTAnimatedGIF (1.7.18)
|
||||
- DTFoundation/DTHTMLParser (1.7.18):
|
||||
- DTFoundation/Core
|
||||
- DTFoundation/UIKit (1.7.18):
|
||||
- DTFoundation/Core
|
||||
- DTTJailbreakDetection (0.4.0)
|
||||
- FLEX (4.5.0)
|
||||
- FlowCommoniOS (1.12.2)
|
||||
- GBDeviceInfo (7.1.0):
|
||||
@@ -39,20 +57,23 @@ PODS:
|
||||
- LoggerAPI (1.9.200):
|
||||
- Logging (~> 1.1)
|
||||
- Logging (1.4.0)
|
||||
- MatrixSDK (0.26.6):
|
||||
- MatrixSDK/Core (= 0.26.6)
|
||||
- MatrixSDK/Core (0.26.6):
|
||||
- MatomoTracker (7.5.2):
|
||||
- MatomoTracker/Core (= 7.5.2)
|
||||
- MatomoTracker/Core (7.5.2)
|
||||
- MatrixSDK (0.26.10):
|
||||
- MatrixSDK/Core (= 0.26.10)
|
||||
- MatrixSDK/Core (0.26.10):
|
||||
- AFNetworking (~> 4.0.0)
|
||||
- GZIP (~> 1.3.0)
|
||||
- libbase58 (~> 0.1.4)
|
||||
- MatrixSDKCrypto (= 0.3.2)
|
||||
- MatrixSDKCrypto (= 0.3.4)
|
||||
- OLMKit (~> 3.2.5)
|
||||
- Realm (= 10.27.0)
|
||||
- SwiftyBeaver (= 1.9.5)
|
||||
- MatrixSDK/JingleCallStack (0.26.6):
|
||||
- MatrixSDK/JingleCallStack (0.26.10):
|
||||
- JitsiMeetSDKLite (= 7.0.1-lite)
|
||||
- MatrixSDK/Core
|
||||
- MatrixSDKCrypto (0.3.2)
|
||||
- MatrixSDKCrypto (0.3.4)
|
||||
- OLMKit (3.2.12):
|
||||
- OLMKit/olmc (= 3.2.12)
|
||||
- OLMKit/olmcpp (= 3.2.12)
|
||||
@@ -95,6 +116,8 @@ DEPENDENCIES:
|
||||
- Down (~> 0.11.0)
|
||||
- DSBottomSheet (~> 0.3)
|
||||
- DSWaveformImage (~> 6.1.1)
|
||||
- DTCoreText (= 1.6.26)
|
||||
- DTTJailbreakDetection (~> 0.4.0)
|
||||
- FLEX (~> 4.5.0)
|
||||
- FlowCommoniOS (~> 1.12.0)
|
||||
- GBDeviceInfo (~> 7.1.0)
|
||||
@@ -102,8 +125,9 @@ DEPENDENCIES:
|
||||
- KeychainAccess (~> 4.2.2)
|
||||
- KTCenterFlowLayout (~> 1.3.1)
|
||||
- libPhoneNumber-iOS (~> 0.9.13)
|
||||
- MatrixSDK (= 0.26.6)
|
||||
- MatrixSDK/JingleCallStack (= 0.26.6)
|
||||
- MatomoTracker (~> 7.5.2)
|
||||
- MatrixSDK (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v0.26.10_bwi_beta`)
|
||||
- MatrixSDK/JingleCallStack (from `https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk`, tag `v0.26.10_bwi_beta`)
|
||||
- OLMKit
|
||||
- PostHog (~> 2.0.0)
|
||||
- ReadMoreTextView (~> 3.0.1)
|
||||
@@ -122,8 +146,20 @@ DEPENDENCIES:
|
||||
- ZXingObjC (~> 3.6.5)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
- AFNetworking
|
||||
- DTCoreText
|
||||
- DTFoundation
|
||||
- DTTJailbreakDetection
|
||||
- GZIP
|
||||
- JitsiMeetSDKLite
|
||||
- JitsiWebRTC
|
||||
- libbase58
|
||||
- MatomoTracker
|
||||
- MatrixSDKCrypto
|
||||
- Realm
|
||||
- SwiftyBeaver
|
||||
trunk:
|
||||
- BlueCryptor
|
||||
- BlueECC
|
||||
- BlueRSA
|
||||
@@ -133,23 +169,16 @@ SPEC REPOS:
|
||||
- FLEX
|
||||
- FlowCommoniOS
|
||||
- GBDeviceInfo
|
||||
- GZIP
|
||||
- Introspect
|
||||
- JitsiMeetSDKLite
|
||||
- JitsiWebRTC
|
||||
- KeychainAccess
|
||||
- KituraContracts
|
||||
- KTCenterFlowLayout
|
||||
- libbase58
|
||||
- libPhoneNumber-iOS
|
||||
- LoggerAPI
|
||||
- Logging
|
||||
- MatrixSDK
|
||||
- MatrixSDKCrypto
|
||||
- OLMKit
|
||||
- PostHog
|
||||
- ReadMoreTextView
|
||||
- Realm
|
||||
- Reusable
|
||||
- Sentry
|
||||
- SideMenu
|
||||
@@ -158,13 +187,22 @@ SPEC REPOS:
|
||||
- SwiftGen
|
||||
- SwiftJWT
|
||||
- SwiftLint
|
||||
- SwiftyBeaver
|
||||
- UICollectionViewLeftAlignedLayout
|
||||
- UICollectionViewRightAlignedLayout
|
||||
- WeakDictionary
|
||||
- zxcvbn-ios
|
||||
- ZXingObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
MatrixSDK:
|
||||
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
|
||||
:tag: v0.26.10_bwi_beta
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
MatrixSDK:
|
||||
:git: https://dl-gitlab.example.com/bwmessenger/bundesmessenger/bundesmessenger-ios-sdk
|
||||
:tag: v0.26.10_bwi_beta
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
|
||||
BlueCryptor: b0aee3d9b8f367b49b30de11cda90e1735571c24
|
||||
@@ -173,6 +211,9 @@ SPEC CHECKSUMS:
|
||||
Down: b6ba1bc985c9d2f4e15e3b293d2207766fa12612
|
||||
DSBottomSheet: ca0ac37eb5af2dd54663f86b84382ed90a59be2a
|
||||
DSWaveformImage: 3c718a0cf99291887ee70d1d0c18d80101d3d9ce
|
||||
DTCoreText: ec749e013f2e1f76de5e7c7634642e600a7467ce
|
||||
DTFoundation: a53f8cda2489208cbc71c648be177f902ee17536
|
||||
DTTJailbreakDetection: 5e356c5badc17995f65a83ed9483f787a0057b71
|
||||
FLEX: e51461dd6f0bfb00643c262acdfea5d5d12c596b
|
||||
FlowCommoniOS: ca92071ab526dc89905495a37844fd7e78d1a7f2
|
||||
GBDeviceInfo: 5d62fa85bdcce3ed288d83c28789adf1173e4376
|
||||
@@ -187,8 +228,9 @@ SPEC CHECKSUMS:
|
||||
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
|
||||
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
|
||||
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
||||
MatrixSDK: 8179c184d819782282f47dab16ce6c2b68ef8a74
|
||||
MatrixSDKCrypto: 7073c382c484cb8ba7dba0a83e112ead96d3bbfd
|
||||
MatomoTracker: 1d98ddc58322fd9d65e1a6886b8e41363047bd13
|
||||
MatrixSDK: 68e39c246ff8d80c5788d5fc46e93fcbb24703fa
|
||||
MatrixSDKCrypto: ac805c22c24f79f349cdbfa065855c73a4c81b51
|
||||
OLMKit: da115f16582e47626616874e20f7bb92222c7a51
|
||||
PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d
|
||||
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
|
||||
@@ -208,6 +250,6 @@ SPEC CHECKSUMS:
|
||||
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
|
||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||
|
||||
PODFILE CHECKSUM: 54848168ab5303c9126626395886cd85f27a44b3
|
||||
PODFILE CHECKSUM: 6bd4e9aff1b435c22f06ad6a4497af49acca8a27
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift",
|
||||
"state" : {
|
||||
"revision" : "addf90f3e2a6ab46bd2b2febe117d9cddb646e7d",
|
||||
"version" : "1.1.1"
|
||||
"revision" : "ff5e8054da60212051cb0dec244500ca0f441bac",
|
||||
"version" : "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "launch_bwi.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "launch_bwi@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "launch_bwi@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
"filename" : "bundesmessenger-logo.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
@@ -21,6 +10,7 @@
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true,
|
||||
"template-rendering-intent" : "original"
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1024" height="1024" rx="248" fill="white"/>
|
||||
<rect x="2" y="2" width="1020" height="1020" rx="246" stroke="black" stroke-opacity="0.25" stroke-width="4"/>
|
||||
<rect x="243" y="366" width="545" height="47" rx="23.5" fill="black"/>
|
||||
<rect x="207" y="529.648" width="544" height="47.6335" rx="23.8167" fill="#FFCC00"/>
|
||||
<rect x="243" y="612" width="419" height="47" rx="23.5" fill="black"/>
|
||||
<rect x="340" y="694" width="378" height="47" rx="23.5" fill="black"/>
|
||||
<rect x="296" y="775.438" width="488" height="47.6335" rx="23.8167" fill="black"/>
|
||||
<rect x="393" y="857.367" width="325" height="47.6335" rx="23.8167" fill="black"/>
|
||||
<rect x="385" y="202" width="366" height="48" rx="24" fill="black"/>
|
||||
<rect x="286" y="283.859" width="487" height="47.6335" rx="23.8167" fill="black"/>
|
||||
<rect x="385.001" y="120" width="167" height="48" rx="24" fill="black"/>
|
||||
<rect x="207" y="447.719" width="610" height="47.6335" rx="23.8167" fill="#FF0000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 43 KiB |
Binary file not shown.
@@ -205,6 +205,7 @@
|
||||
"settings_password_has_no_lowercase_letter" = "Das Passwort muss mindestens einen Kleinbuchstaben enthalten";
|
||||
"settings_about" = "Erweitert";
|
||||
"bwi_settings_ignored_users_text" = "Ignorierte Nutzer";
|
||||
"settings_imprint" = "Impressum";
|
||||
|
||||
// MARK: - Room Details
|
||||
|
||||
@@ -387,7 +388,7 @@
|
||||
|
||||
// Mark: - Room Creation
|
||||
|
||||
"room_intro_cell_information_dm_sentence1_part1" = "Das ist der Anfang deiner Direktnachricht mit ";
|
||||
"room_intro_cell_information_dm_sentence1_part1" = "Dies ist der Beginn deiner Direktnachrichten mit ";
|
||||
"room_avatar_view_accessibility_hint" = "Raumbild ändern";
|
||||
"room_avatar_view_accessibility_label" = "Profilbild";
|
||||
"room_details_permalink" = "Link zum Raum kopieren";
|
||||
@@ -501,6 +502,7 @@
|
||||
"bwi_error_invite_already_in_room" = "%@ ist bereits im Raum.";
|
||||
"bwi_error_invite_banned_in_room" = "%@ ist vom Raum gebannt.";
|
||||
"bwi_error_invite_general" = "%@ konnte nicht eingeladen werden.";
|
||||
"bwi_error_logout_offline" = "Abmelden ist ohne Internetverbindung nicht möglich.";
|
||||
|
||||
// MARK: - Matomo
|
||||
|
||||
@@ -519,7 +521,7 @@
|
||||
"bwi_settings_new_features_show_features" = "Neue Funktionen anzeigen";
|
||||
"bwi_feature_banner_header" = "Neue Funktionen";
|
||||
"bwi_feature_banner_show_more_button" = "Erfahre mehr";
|
||||
"bwi_feature_banner_advertisement_text" = "Du kannst jetzt aktive und vergangene Umfragen gesammelt in den Raumdetails einsehen (erreichbar unter Raumdetails, im Bereich \"Umfrageverlauf\").";
|
||||
"bwi_feature_banner_advertisement_text" = "Neue Umfragen können vom Ersteller so konfiguriert werden, dass angezeigt wird, wer für welche Option gestimmt hat.";
|
||||
|
||||
// MARK: - Onboarding
|
||||
"onboarding_splash_login_button_title" = "Loslegen";
|
||||
@@ -540,6 +542,10 @@
|
||||
"poll_edit_form_poll_type" = "Umfragetyp";
|
||||
"poll_edit_form_poll_type_closed" = "Versteckte Umfrage";
|
||||
"poll_edit_form_poll_type_open" = "Offene Umfrage";
|
||||
"poll_edit_form_participant_toggle" = "Anzeigen, wer für welche Option gestimmt hat.";
|
||||
"poll_timeline_show_participants_button" = "Stimmen anzeigen";
|
||||
"poll_participant_details_show_more" = "Alle ansehen (%lu weitere)";
|
||||
"poll_participant_details_title" = "Umfragedetails";
|
||||
|
||||
// MARK: - Welcome Experience
|
||||
"welcome_experience_title1" = "Willkommen beim BundesMessenger";
|
||||
@@ -592,6 +598,8 @@
|
||||
|
||||
// MARK: - Permalink
|
||||
"settings_permalink_prefix_picker_title" = "Permalink Prefix";
|
||||
"bwi_error_room_not_available_title" = "Link ungültig";
|
||||
"bwi_error_room_not_available_message" = "Der Raum wurde bereits geschlossen, daher kannst Du nicht mehr beitreten.";
|
||||
|
||||
// MARK: - Notification Settings
|
||||
"settings_notify_me_for" = "Benachrichtige mich für";
|
||||
@@ -612,7 +620,11 @@
|
||||
// MARK: - Device Manager
|
||||
"user_session_verified_session_description" = "Du hast deine Sitzung durch Eingabe des Wiederherstellungsschlüssels oder durch die Verifizierung mit einem anderen Gerät bestätigt. Dies bedeutet, dass du alle Schlüssel zum Entschlüsseln deiner Nachrichten hast und anderen bestätigst, dieser Sitzung zu vertrauen.";
|
||||
"user_session_button_view_all" = "Alle anzeigen (%d)";
|
||||
"user_verification_session_details_verify_action_current_user" = "Sitzung verifizieren";
|
||||
|
||||
// MARK: - Voice Over
|
||||
"textfield_reveal_secret" = "Texteingabe anzeigen";
|
||||
"textfield_hide_secret" = "Texteingabe verbergen";
|
||||
|
||||
// MARK: - Accessibility declaration
|
||||
"bwi_accessibility_declaration_button_title" = "Barrierefreiheitserklärung";
|
||||
|
||||
@@ -2742,3 +2742,15 @@
|
||||
// MARK: - Launch loading
|
||||
|
||||
"launch_loading_generic" = "Synchronisiere deine Unterhaltungen";
|
||||
"pill_message_in" = "Nachricht in %@";
|
||||
"pill_message_from" = "Nachricht von %@";
|
||||
"pill_message" = "Nachricht";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Space/Raum";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "Verschlüsselte Kommunikation wurde mit der neuesten Aktualisierung verbessert. Bitte verifiziere deine Geräte erneut.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "App aktualisiert";
|
||||
"settings_acceptable_use" = "Nutzungsbedingungen";
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
"settings_password_has_no_lowercase_letter" = "The password must include at least one lowercase letter";
|
||||
"settings_deactivate_my_account" = "Deactivate my account";
|
||||
"settings_enable_inapp_notifications" = "Enable In-App notifications";
|
||||
"settings_imprint" = "Imprint";
|
||||
|
||||
// MARK: - Room Details
|
||||
|
||||
@@ -309,7 +310,7 @@
|
||||
|
||||
// Mark: - Room Creation
|
||||
|
||||
"room_intro_cell_information_dm_sentence1_part1" = "This is the beginning of your conversation with ";
|
||||
"room_intro_cell_information_dm_sentence1_part1" = "This is the beginning of your direct message history with ";
|
||||
|
||||
// MARK: - Notification Times
|
||||
|
||||
@@ -410,6 +411,7 @@
|
||||
"bwi_error_invite_already_in_room" = "%@ is already in the room.";
|
||||
"bwi_error_invite_banned_in_room" = "%@ is banned from the room.";
|
||||
"bwi_error_invite_general" = "%@ could not be invited.";
|
||||
"bwi_error_logout_offline" = "Logout not possible without internet connection.";
|
||||
|
||||
// MARK: - Matomo
|
||||
|
||||
@@ -428,7 +430,7 @@
|
||||
"bwi_settings_new_features_show_features" = "Show new features";
|
||||
"bwi_feature_banner_header" = "New Features";
|
||||
"bwi_feature_banner_show_more_button" = "Learn more";
|
||||
"bwi_feature_banner_advertisement_text" = "You can now see a poll history in the room details.";
|
||||
"bwi_feature_banner_advertisement_text" = "New polls can be configured by the creator to show who voted for which option.";
|
||||
|
||||
// MARK: - Onboarding
|
||||
"onboarding_splash_login_button_title" = "Let's go";
|
||||
@@ -445,6 +447,10 @@
|
||||
"poll_edit_form_poll_type" = "Poll type";
|
||||
"poll_edit_form_poll_type_closed" = "Hidden Poll";
|
||||
"poll_edit_form_poll_type_open" = "Open poll";
|
||||
"poll_edit_form_participant_toggle" = "Show who voted for which option";
|
||||
"poll_timeline_show_participants_button" = "Show votes";
|
||||
"poll_participant_details_show_more" = "Show all (%lu more)";
|
||||
"poll_participant_details_title" = "Poll details";
|
||||
|
||||
// MARK: - Welcome Experience
|
||||
"welcome_experience_title1" = "Welcome to BundesMessenger";
|
||||
@@ -502,6 +508,8 @@
|
||||
|
||||
// MARK: - Permalink
|
||||
"settings_permalink_prefix_picker_title" = "Permalink Prefix";
|
||||
"bwi_error_room_not_available_title" = "Link invalid";
|
||||
"bwi_error_room_not_available_message" = "The room has already been closed, you can no longer join.";
|
||||
|
||||
// MARK: - Notification Settings
|
||||
"settings_notify_me_for" = "Notify me for";
|
||||
@@ -522,8 +530,11 @@
|
||||
// MARK: - Device Manager
|
||||
"user_session_verified_session_description" = "You have confirmed your session by entering the recovery key or verifying with another device. This means that you have all the keys to decrypt your messages and are confirming to others to trust this session.";
|
||||
"user_session_button_view_all" = "View all (%d)";
|
||||
"user_verification_session_details_verify_action_current_user" = "Verify session";
|
||||
|
||||
// MARK: - Voice Over
|
||||
"textfield_reveal_secret" = "reveal text input";
|
||||
"textfield_hide_secret" = "hide text input";
|
||||
|
||||
// MARK: - Accessibility declaration
|
||||
"bwi_accessibility_declaration_button_title" = "Accessibility declaration";
|
||||
|
||||
@@ -614,6 +614,21 @@ Tap the + to start adding people.";
|
||||
"room_join_group_call" = "Join";
|
||||
"room_no_privileges_to_create_group_call" = "You need to be an admin or a moderator to start a call.";
|
||||
|
||||
// Room commands descriptions
|
||||
"room_command_change_display_name_description" = "Changes your display nickname";
|
||||
"room_command_emote_description" = "Displays action";
|
||||
"room_command_join_room_description" = "Joins room with given address";
|
||||
"room_command_part_room_description" = "Leave room";
|
||||
"room_command_invite_user_description" = "Invites user with given id to current room";
|
||||
"room_command_kick_user_description" = "Removes user with given id from this room";
|
||||
"room_command_ban_user_description" = "Bans user with given id";
|
||||
"room_command_unban_user_description" = "Unbans user with given id";
|
||||
"room_command_set_user_power_level_description" = "Define the power level of a user";
|
||||
"room_command_reset_user_power_level_description" = "Deops user with given id";
|
||||
"room_command_change_room_topic_description" = "Sets the room topic";
|
||||
"room_command_discard_session_description" = "Forces the current outbound group session in an encrypted room to be discarded";
|
||||
"room_command_error_unknown_command" = "Invalid or unhandled command";
|
||||
|
||||
// MARK: Threads
|
||||
"room_thread_title" = "Thread";
|
||||
"thread_copy_link_to_thread" = "Copy link to thread";
|
||||
@@ -2393,6 +2408,8 @@ Tap the + to start adding people.";
|
||||
|
||||
"poll_timeline_reply_ended_poll" = "Ended poll";
|
||||
|
||||
"poll_timeline_loading" = "Loading...";
|
||||
|
||||
// MARK: - Location sharing
|
||||
|
||||
"location_sharing_title" = "Location";
|
||||
@@ -2972,6 +2989,7 @@ To enable access, tap Settings> Location and select Always";
|
||||
"notice_avatar_url_changed" = "%@ changed their avatar";
|
||||
"notice_display_name_set" = "%@ set their display name to %@";
|
||||
"notice_display_name_changed_from" = "%@ changed their display name from %@ to %@";
|
||||
"notice_display_name_changed_to" = "%@ changed their display name to %@";
|
||||
"notice_display_name_removed" = "%@ removed their display name";
|
||||
"notice_topic_changed" = "%@ changed the topic to \"%@\".";
|
||||
"notice_room_name_changed" = "%@ changed the room name to %@.";
|
||||
|
||||
@@ -2680,3 +2680,15 @@
|
||||
// MARK: - Launch loading
|
||||
|
||||
"launch_loading_generic" = "Sinu vestlused on sünkroniseerimisel";
|
||||
"pill_message_in" = "Sõnum jututoas %@";
|
||||
"pill_message_from" = "Sõnum kasutajalt %@";
|
||||
"pill_message" = "Sõnum";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Kogukond/jututuba";
|
||||
"settings_acceptable_use" = "Vastuvõetava kasutamise põhimõtted";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "Turvalisele sõnumivahetusele on lisandunud palju täiendusi. Palun verifitseeri oma seade uuesti.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "Rakendus on uuendatud";
|
||||
|
||||
@@ -2654,7 +2654,6 @@
|
||||
"voice_broadcast_stop_alert_title" = "Megszakítod az élő közvetítést?";
|
||||
"voice_broadcast_buffering" = "Pufferelés…";
|
||||
"voice_broadcast_time_left" = "%@ van vissza";
|
||||
|
||||
"password_policy_pwd_in_dict_error" = "Ez a jelszó megtalálható a szótárban ezért nem engedélyezett.";
|
||||
"password_policy_weak_pwd_error" = "Ez a jelszó túl gyenge. Legalább 8 karakternek kell lennie és minden típusból legalább egy: nagybetű, kisbetű, szám és speciális karakter.";
|
||||
|
||||
@@ -2701,7 +2700,6 @@
|
||||
"poll_history_no_past_poll_period_text" = "%@ napja nincs aktív szavazás. További szavazások betöltése az előző havi szavazások megjelenítéséhez";
|
||||
"poll_history_no_active_poll_period_text" = "%@ napja nincs aktív szavazás. További szavazások betöltése az előző havi szavazások megjelenítéséhez";
|
||||
"poll_history_loading_text" = "Szavazások megjelenítése";
|
||||
|
||||
"settings_labs_disable_crypto_sdk" = "Rust végpontok közötti titkosítás (kikapcsoláshoz kijelentkezés szükséges)";
|
||||
"settings_labs_confirm_crypto_sdk" = "Ez a funkció még kísérleti fázisban van. Lehet, hogy nem az elvártnak megfelelően fog működni és előre nem látható következménye lehet. A funkció kikapcsolásához egyszerű ki-, és bejelentkezés szükséges. Használata csak saját felelősségre.";
|
||||
"settings_labs_enable_crypto_sdk" = "Rust végpontok közötti titkosítás";
|
||||
@@ -2720,3 +2718,25 @@
|
||||
"device_verification_self_verify_wait_recover_secrets_additional_help" = "Nem férsz hozzá létező munkamenethez, %@?";
|
||||
"device_verification_self_verify_open_on_other_device_title" = "Nyisd meg ezt: %@ a másik eszközön";
|
||||
"room_creation_only_one_email_invite" = "E-mail meghívóból egyszerre csak egy küldhető";
|
||||
"pill_message_in" = "Üzenet itt: %@";
|
||||
"pill_message_from" = "Üzenet tőle: %@";
|
||||
"pill_message" = "Üzenet";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Tér/Szoba";
|
||||
"launch_loading_delay_warning" = "Ez egy kicsit tovább tarthat.\nKöszönjük a türelmet.";
|
||||
|
||||
// MARK: - Launch loading
|
||||
|
||||
"launch_loading_generic" = "Beszélgetések szinkronizálása";
|
||||
"key_verification_scan_qr_code_information_new_session" = "Az új munkameneted ellenőrzéséhez irányítsd a kamerádat a másik eszközödön megjelenő QR kódra";
|
||||
"key_verification_scan_qr_code_information_other_session" = "A munkameneted ellenőrzéséhez irányítsd a kamerádat a másik eszközödön megjelenő QR kódra";
|
||||
"key_verification_scan_qr_code_information_other_device" = "A munkamenet ellenőrzéséhez irányítsd a kamerádat a másik eszközödön megjelenő QR kódra";
|
||||
"key_verification_scan_qr_code_information_other_user" = "A munkamenetük ellenőrzéséhez irányítsd a kamerádat az eszközükön megjelenő QR kódra";
|
||||
"device_verification_self_verify_open_on_other_device_information" = "Ennek a munkamenetnek az ellenőrzésére szükséged van a régi titkosított üzenetek olvasásához.\n\nNyisd meg az Elementet egy másik eszközödön és kövesd az utasításokat.";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "A biztonságos üzenetküldés a legutolsó fejlesztésekkel frissült. Kérjük ellenőrizzed újra az eszközt.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "Alkalmazás frissítve";
|
||||
"settings_acceptable_use" = "Elfogadható felhasználói feltételek";
|
||||
|
||||
@@ -2935,3 +2935,15 @@
|
||||
"device_verification_self_verify_open_on_other_device_information" = "Anda harus memverifikasi sesi ini supaya dapat membaca riwayat pesan aman Anda.\n\nBuka Element di salah satu perangkat Anda yang lain dan ikuti petunjuknya.";
|
||||
"device_verification_self_verify_open_on_other_device_title" = "Buka %@ di perangkat Anda yang lain";
|
||||
"room_creation_only_one_email_invite" = "Amda hanya dapat mengundang satu surel satu-satu";
|
||||
"pill_message_in" = "Pesan di %@";
|
||||
"pill_message_from" = "Pesan dari %@";
|
||||
"pill_message" = "Pesan";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Space/Ruangan";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "Perpesanan aman telah ditingkatkan dengan pembaruan terkini. Silakan verifikasi ulang perangkat Anda.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "Aplikasi diperbarui";
|
||||
"settings_acceptable_use" = "Kebijakan Penggunaan yang Dapat Diterima";
|
||||
|
||||
@@ -2708,3 +2708,15 @@
|
||||
// MARK: - Launch loading
|
||||
|
||||
"launch_loading_generic" = "Sincronizzazione delle tue conversazioni";
|
||||
"pill_message_in" = "Messaggio in %@";
|
||||
"pill_message_from" = "Messaggio da %@";
|
||||
"pill_message" = "Messaggio";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Spazio/Stanza";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "La messaggistica sicura è stata migliorata con l'aggiornamento più recente. Ri-verifica il tuo dispositivo.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "App aggiornata";
|
||||
"settings_acceptable_use" = "Politica di utilizzo accettabile";
|
||||
|
||||
@@ -26,6 +26,35 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p>
|
||||
<b>Version 2.7.0</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Neue Funktionen</b>
|
||||
<ul>
|
||||
<li/>Neue Umfragen können vom Ersteller so konfiguriert werden, dass angezeigt wird, wer für welche Option gestimmt hat.
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Verbesserungen</b>
|
||||
<ul>
|
||||
<li/>Das Löschen des Raumavatars ist nun möglich.
|
||||
<li/>Website Verlinkungen werden nun im System-Browser geöffnet.
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Behobene Bugs</b>
|
||||
<ul>
|
||||
<li/>Das Abmelden ohne Internetverbindung kann zu Fehlern führen, deshalb ist dies nicht mehr möglich.
|
||||
<li/>Die Eingabe des Wiederherstellungsschlüssels war nicht möglich, wenn die Sprache der App auf Englisch eingestellt war.
|
||||
<li/>Man kann eine andere Sitzung nicht mehr von einem Gerät alleine verifizieren.
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<b>Version 2.6.0</b>
|
||||
|
||||
@@ -239,7 +239,7 @@
|
||||
"settings_ignored_users" = "ИГНОРИРУЕМЫЕ ПОЛЬЗОВАТЕЛИ";
|
||||
"settings_contacts" = "КОНТАКТЫ УСТРОЙСТВА";
|
||||
"settings_advanced" = "ДОПОЛНИТЕЛЬНО";
|
||||
"settings_other" = "ДРУГИЕ";
|
||||
"settings_other" = "Другие";
|
||||
"settings_labs" = "ЛАБОРАТОРИЯ";
|
||||
"settings_devices" = "СЕАНСЫ";
|
||||
"settings_cryptography" = "КРИПТОГРАФИЯ";
|
||||
@@ -272,11 +272,11 @@
|
||||
"settings_send_crash_report" = "Отправка данных о сбоях и использовании";
|
||||
"settings_clear_cache" = "Очистить кэш";
|
||||
"settings_change_password" = "Изменить пароль";
|
||||
"settings_old_password" = "старый пароль";
|
||||
"settings_new_password" = "новый пароль";
|
||||
"settings_confirm_password" = "подтвердить пароль";
|
||||
"settings_fail_to_update_password" = "Не удалось обновить пароль";
|
||||
"settings_password_updated" = "Ваш пароль был обновлен";
|
||||
"settings_old_password" = "Старый пароль";
|
||||
"settings_new_password" = "Новый пароль";
|
||||
"settings_confirm_password" = "Подтвердить пароль";
|
||||
"settings_fail_to_update_password" = "Не удалось обновить пароль аккаунта Matrix";
|
||||
"settings_password_updated" = "Ваш пароль аккаунта Matrix был обновлен";
|
||||
"settings_crypto_device_name" = "Имя сеанса: ";
|
||||
"settings_crypto_device_id" = "\nID сеанса: ";
|
||||
"settings_crypto_device_key" = "\nКлюч сеанса:\n";
|
||||
@@ -512,7 +512,7 @@
|
||||
"room_action_send_photo_or_video" = "Отправить фото или видео";
|
||||
"room_action_send_sticker" = "Отправить стикер";
|
||||
"settings_deactivate_account" = "ДЕАКТИВАЦИЯ АККАУНТА";
|
||||
"settings_deactivate_my_account" = "Деактивировать мой аккаунт";
|
||||
"settings_deactivate_my_account" = "Деактивировать аккаунт навсегда";
|
||||
"widget_sticker_picker_no_stickerpacks_alert_add_now" = "Добавить сейчас?";
|
||||
"deactivate_account_title" = "Деактивировать аккаунт";
|
||||
"deactivate_account_informations_part1" = "Это действие сделает вашу учетную запись непригодной для дальнейшего использования. Вы не сможете войти в систему и никто другой не сможет заново зарегистрировать учетную запись с вашим идентификатором. Также, это приведет к тому, что вы покинете все комнаты, в которых участвовали и данные о вашей учетной записи будут удалены с сервера идентификации. ";
|
||||
@@ -525,7 +525,7 @@
|
||||
"deactivate_account_forget_messages_information_part3" = ": будущие участники увидят неполное представление разговоров)";
|
||||
"deactivate_account_validate_action" = "Деактивировать аккаунт";
|
||||
"deactivate_account_password_alert_title" = "Деактивировать аккаунт";
|
||||
"deactivate_account_password_alert_message" = "Чтобы продолжить, введите пароль";
|
||||
"deactivate_account_password_alert_message" = "Чтобы продолжить, введите пароль аккаунта Matrix";
|
||||
"widget_sticker_picker_no_stickerpacks_alert" = "У вас пока нет включенных пакетов стикеров.";
|
||||
"event_formatter_rerequest_keys_part1_link" = "Повторно запросить ключи шифрования";
|
||||
"event_formatter_rerequest_keys_part2" = " из других ваших сеансов.";
|
||||
@@ -583,7 +583,7 @@
|
||||
"key_backup_setup_intro_title" = "Никогда не теряйте зашифрованных сообщений";
|
||||
"key_backup_setup_intro_info" = "Сообщения в зашифрованных комнатах защищены сквозным шифрованием. Только вы и получатель(и) имеют ключи для чтения этих сообщений.\n\nСохраните ключи надежно, чтобы не потерять их.";
|
||||
"key_backup_setup_intro_setup_action" = "Настроить";
|
||||
"key_backup_setup_passphrase_info" = "Мы будем хранить зашифрованную копию ваших ключей на нашем сервере. Для безопасности, защитите резервную копию секретной фразой.\n\nДля обеспечения максимальной безопасности она должна отличаться от пароля учетной записи.";
|
||||
"key_backup_setup_passphrase_info" = "Мы будем хранить зашифрованную копию ваших ключей на нашем сервере. Для безопасности, защитите резервную копию секретной фразой.\n\nДля обеспечения максимальной безопасности она должна отличаться от пароля учётной записи Matrix.";
|
||||
"key_backup_setup_passphrase_passphrase_title" = "Ввод";
|
||||
"key_backup_setup_passphrase_passphrase_placeholder" = "Введите секретную фразу";
|
||||
"key_backup_setup_passphrase_passphrase_valid" = "Отлично!";
|
||||
@@ -864,7 +864,7 @@
|
||||
"identity_server_settings_alert_error_invalid_identity_server" = "%@ не является действительным сервером идентификации.";
|
||||
"settings_add_3pid_password_title_email" = "Добавить адрес электронной почты";
|
||||
"settings_add_3pid_password_title_msidsn" = "Добавить номер телефона";
|
||||
"settings_add_3pid_password_message" = "Для продолжения, задайте пароль";
|
||||
"settings_add_3pid_password_message" = "Для продолжения, введите пароль аккаунта Matrix";
|
||||
"settings_add_3pid_invalid_password_message" = "Недействительные данные";
|
||||
"settings_discovery_three_pid_details_title_phone_number" = "Управление номера телефона";
|
||||
"settings_identity_server_no_is" = "Сервер идентификации не настроен";
|
||||
@@ -915,7 +915,7 @@
|
||||
"security_settings_title" = "Безопасность";
|
||||
"security_settings_crypto_sessions" = "МОИ СЕАНСЫ";
|
||||
"security_settings_crypto_sessions_loading" = "Загрузка сеансов…";
|
||||
"security_settings_crypto_sessions_description_2" = "Если вы не узнали логин, измените пароль и сбросьте Безопасное резервное копирование.";
|
||||
"security_settings_crypto_sessions_description_2" = "Если вы не узнали логин, измените пароль аккаунта Matrix и сбросьте Безопасное резервное копирование.";
|
||||
"security_settings_secure_backup" = "БЕЗОПАСНОЕ РЕЗЕРВНОЕ КОПИРОВАНИЕ";
|
||||
"security_settings_secure_backup_description" = "Сделайте резервную копию ключей шифрования с данными вашей учетной записи на случай, если вы потеряете доступ к своим сеансам. Ваши ключи будут защищены уникальным электронным ключом.";
|
||||
"security_settings_secure_backup_setup" = "Настроить";
|
||||
@@ -938,7 +938,7 @@
|
||||
"security_settings_complete_security_alert_title" = "Завершите настройку безопасности";
|
||||
"security_settings_complete_security_alert_message" = "Сначала вы должны завершить настройку безопасности текущего сеанса.";
|
||||
"security_settings_coming_soon" = "Извините. Это действие пока недоступно в %@ iOS. Пожалуйста, используйте другой клиент Matrix для его настройки. %@ iOS будет его использовать.";
|
||||
"security_settings_user_password_description" = "Подтвердите свою личность, введя пароль учетной записи";
|
||||
"security_settings_user_password_description" = "Подтвердите свою личность, введя пароль учётной записи Matrix";
|
||||
// Manage session
|
||||
"manage_session_title" = "Управление сеансами";
|
||||
"manage_session_info" = "ИНФОРМАЦИЯ О СЕАНСЕ";
|
||||
@@ -1130,7 +1130,7 @@
|
||||
"secrets_setup_recovery_key_storage_alert_message" = "✓ Распечатайте и храните в безопасном месте\n✓ Сохраните его на USB-носителе или резервном носителе\n✓ Скопируйте его в свое личное облачное хранилище";
|
||||
"secrets_setup_recovery_passphrase_title" = "Задайте мнемоническую фразу";
|
||||
"secrets_setup_recovery_passphrase_information" = "Введите секретную фразу, известную только вам, для защиты данных на вашем сервере.";
|
||||
"secrets_setup_recovery_passphrase_additional_information" = "Не используйте пароль своей учетной записи.";
|
||||
"secrets_setup_recovery_passphrase_additional_information" = "Не используйте пароль своей учётной записи Matrix.";
|
||||
"secrets_setup_recovery_passphrase_validate_action" = "Готово";
|
||||
"secrets_setup_recovery_passphrase_confirm_information" = "Введите мнемоническую фразу ещё раз, чтобы подтвердить её.";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Подтвердить";
|
||||
@@ -1183,7 +1183,7 @@
|
||||
"searchable_directory_x_network" = "%@ Сеть";
|
||||
"searchable_directory_search_placeholder" = "Имя или ID";
|
||||
"create_room_title" = "Новая комната";
|
||||
"create_room_section_header_name" = "Имя комнаты";
|
||||
"create_room_section_header_name" = "НАЗВАНИЕ";
|
||||
"create_room_placeholder_name" = "Имя";
|
||||
"create_room_section_header_topic" = "Тема комнаты (опционально)";
|
||||
"create_room_placeholder_topic" = "Тема";
|
||||
@@ -1218,7 +1218,7 @@
|
||||
"room_details_advanced_e2e_encryption_enabled_for_dm" = "Шифрование включено";
|
||||
"room_details_advanced_e2e_encryption_disabled_for_dm" = "Шифрование не включено.";
|
||||
"pin_protection_kick_user_alert_message" = "Слишком много ошибок, вы вышли из системы";
|
||||
"secrets_reset_authentication_message" = "Введите пароль своей учётной записи для подтверждения";
|
||||
"secrets_reset_authentication_message" = "Введите пароль своей учётной записи Matrix для подтверждения";
|
||||
"secrets_reset_reset_action" = "Сброс";
|
||||
"secrets_reset_warning_message" = "Вы перезапустите приложение без истории, сообщений, доверенных устройств или доверенных пользователей.";
|
||||
"secrets_reset_warning_title" = "Если сбросить все";
|
||||
@@ -2224,3 +2224,40 @@
|
||||
"threads_notice_information" = "Все потоки созданные во время экспериментального периода теперь <b>отображаются как обычные ответы</b>.<br/><br/>Это разовый переход, так как потоки теперь часть спецификации Matrix.";
|
||||
"authentication_qr_login_failure_device_not_supported" = "Связь с этим устройством не поддерживается.";
|
||||
"accessibility_selected" = "выбранный";
|
||||
"room_access_settings_screen_message" = "Решите, кто может найти и присоединиться к %@.";
|
||||
"room_access_settings_screen_title" = "Кто может получить доступ к этой комнате?";
|
||||
"room_details_promote_room_suggest_title" = "Предложить участникам пространства";
|
||||
/* The placeholder will be replaces with manage_session_name_info_link */
|
||||
"manage_session_name_info" = "Учитывайте, что имена сессий также видны людям, с которыми вы общаетесь. %@";
|
||||
"settings_labs_enable_new_client_info_feature" = "Запишите имя клиента, версию и URL-адрес, чтобы упростить распознавание сеансов в диспетчере сеансов";
|
||||
"sign_out_confirmation_message" = "Вы уверены, что хотите выйти?";
|
||||
"share_extension_send_now" = "Отправить сейчас";
|
||||
"share_extension_low_quality_video_title" = "Видео будет отправлено в низком качестве";
|
||||
"analytics_prompt_stop" = "Прекратить делиться";
|
||||
"analytics_prompt_not_now" = "Не сейчас";
|
||||
"analytics_prompt_point_3" = "Вы можете отключить это в любое время в настройках";
|
||||
/* Note: The word "don't" is formatted in bold */
|
||||
"analytics_prompt_point_2" = "Мы <b>не</b> передаем информацию третьим лицам";
|
||||
/* Note: The word "don't" is formatted in bold */
|
||||
"analytics_prompt_point_1" = "Мы <b>не</b> записываем и не профилируем никакие данные учётной записи";
|
||||
"analytics_prompt_message_upgrade" = "Ранее вы дали согласие на передачу нам анонимных данных об использовании. Теперь, чтобы помочь понять, как люди используют несколько устройств, мы сгенерируем случайный идентификатор, общий для всех ваших устройств.";
|
||||
"analytics_prompt_message_new_user" = "Помогите нам выявить проблемы и улучшить %@, поделившись анонимными данными об использовании. Чтобы понять, как люди используют несколько устройств, мы сгенерируем случайный идентификатор, общий для всех ваших устройств.";
|
||||
|
||||
// Analytics
|
||||
"analytics_prompt_title" = "Помогите улучшить %@";
|
||||
"call_jitsi_unable_to_start" = "Невозможно начать конференц-звонок";
|
||||
"network_offline_message" = "Вы не в сети, проверьте ваше соединение.";
|
||||
"network_offline_title" = "Вы не в сети";
|
||||
"event_formatter_message_deleted" = "Сообщение удалено";
|
||||
"room_access_space_chooser_other_spaces_section" = "Другие пространства или комнаты";
|
||||
"room_access_settings_screen_setting_room_access" = "Настройка доступа к комнате";
|
||||
"room_access_settings_screen_upgrade_alert_auto_invite_switch" = "Автоматически приглашать участников в новую комнату";
|
||||
"room_access_settings_screen_upgrade_alert_note" = "Обратите внимание, что при обновлении будет создана новая версия комнаты. Все текущие сообщения останутся в этой архивной комнате.";
|
||||
"room_access_settings_screen_upgrade_alert_message_no_param" = "Любой в родительском пространстве сможет найти и присоединиться к этой комнате - нет необходимости вручную приглашать всех вручную. Вы сможете изменить это в настройках комнаты в любое время.";
|
||||
"room_access_settings_screen_upgrade_alert_message" = "Любой человек в %@ сможет найти и присоединиться к этой комнате - нет необходимости вручную приглашать всех. Вы сможете изменить это в настройках комнаты в любое время.";
|
||||
"room_access_settings_screen_public_message" = "Любой желающий может найти и присоединиться.";
|
||||
"room_access_settings_screen_edit_spaces" = "Редактировать пространства";
|
||||
"room_access_settings_screen_restricted_message" = "Позволяет всем, кто находится в пространстве, найти его и присоединиться.\nВам будет предложено подтвердить к каким пространствам.";
|
||||
"room_access_settings_screen_private_message" = "Только приглашенные люди могут найти и присоединиться.";
|
||||
"manage_session_name_hint" = "Индивидуальные имена сеансов помогут Вам легче распознавать свои устройства.";
|
||||
"settings_labs_confirm_crypto_sdk" = "Имейте ввиду, что эта функция все ещё на экспериментальной стадии, поэтому она может работать не так, как ожидается, и потенциально может иметь непредвиденные последствия. Для отмены функции выйдите из системы и войдите снова. Используйте её по своему усмотрению и с осторожностью.";
|
||||
|
||||
@@ -2931,3 +2931,15 @@
|
||||
// MARK: - Launch loading
|
||||
|
||||
"launch_loading_generic" = "Synchronizácia vašich konverzácií";
|
||||
"pill_message_in" = "Správa v %@";
|
||||
"pill_message_from" = "Správa od %@";
|
||||
"pill_message" = "Správa";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Priestor/miestnosť";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "Najnovšou aktualizáciou sa zlepšilo bezpečné zasielanie správ. Overte prosím znova svoje zariadenie.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "Aplikácia bola aktualizovaná";
|
||||
"settings_acceptable_use" = "Zásady prijateľného používania";
|
||||
|
||||
@@ -2718,3 +2718,16 @@
|
||||
"device_verification_self_verify_open_on_other_device_information" = "Lypset të verifikoni këtë sesion, që të mund të lexoni historikun e mesazheve tuaj të siguruar.\n\nHapeni Element-in në një nga pajisjet tuaja të tjera dhe ndiqni udhëzimet.";
|
||||
"device_verification_self_verify_open_on_other_device_title" = "Hapeni %@ në pajisjen tuaj tjetër";
|
||||
"room_creation_only_one_email_invite" = "Mund të ftoni vetëm një email në herë";
|
||||
"pill_message_in" = "Mesazh te %@";
|
||||
"pill_message_from" = "Mesazh nga %@";
|
||||
"pill_message" = "Mesazh";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Hapësirë/Dhomë";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "Me përditësimin e fundit shkëmbimi i siguruar i mesazheve është përmirësuar. Ju lutemi, riverifikoni pajisjen tuaj.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "Aplikacioni u përditësua";
|
||||
"settings_acceptable_use" = "Rregull Përdorimi të Pranueshëm";
|
||||
"accessibility_selected" = "përzgjedhur";
|
||||
|
||||
@@ -2933,3 +2933,15 @@
|
||||
// MARK: - Launch loading
|
||||
|
||||
"launch_loading_generic" = "Синхронізація ваших розмов";
|
||||
"pill_message_in" = "Повідомлення у %@";
|
||||
"pill_message_from" = "Повідомлення від %@";
|
||||
"pill_message" = "Повідомлення";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "Простір/кімната";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "В останньому оновленні було вдосконалено захищений обмін повідомленнями. Перевірте свій пристрій ще раз.";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "Застосунок оновлено";
|
||||
"settings_acceptable_use" = "Політика прийнятного користування";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Permissions usage explanations
|
||||
"NSCameraUsageDescription" = "給予相機權限會用來進行視訊通話或是拍攝並上傳照片與影片。";
|
||||
"NSPhotoLibraryUsageDescription" = "同意使用圖片的權限會用來上傳您圖庫的照片與影片。";
|
||||
"NSMicrophoneUsageDescription" = "Element 需要麥克風的權限來接受通話、拍攝影片以及錄製語音訊息。";
|
||||
"NSContactsUsageDescription" = "他們會與您的身分伺服器共享以找到您在Matrix上的聯絡人。";
|
||||
"NSPhotoLibraryUsageDescription" = "請允許存取「照片」,來上傳圖庫當中的照片或影片。";
|
||||
"NSMicrophoneUsageDescription" = "Element 需要麥克風的權限來通話、拍攝影片以及錄製語音訊息。";
|
||||
"NSContactsUsageDescription" = "會將此資訊分享給您的身分伺服器,以幫助您尋找 Matrix 聯絡人。";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "當您與其他人分享您的位置,Element 需要權限將位置顯示在地圖上。";
|
||||
"NSLocationWhenInUseUsageDescription" = "當您與其他人分享您的位置,Element 需要權限將位置顯示在地圖上。";
|
||||
"NSFaceIDUsageDescription" = "您可以使用 Face ID 來登入您的應用程式。";
|
||||
|
||||
@@ -75,15 +75,15 @@
|
||||
"USER_MEMBERSHIP_UPDATED" = "%@ 更新了個人資料";
|
||||
|
||||
/* A user has change their name to a new name which we don't know */
|
||||
"GENERIC_USER_UPDATED_DISPLAYNAME" = "%@ 變更了名字";
|
||||
"GENERIC_USER_UPDATED_DISPLAYNAME" = "%@ 變更了名稱";
|
||||
|
||||
/** Membership Updates **/
|
||||
|
||||
/* A user has change their name to a new name */
|
||||
"USER_UPDATED_DISPLAYNAME" = "%@ 把名稱變更為 %@";
|
||||
"USER_UPDATED_DISPLAYNAME" = "%@ 將名稱變更為 %@";
|
||||
|
||||
/* A user has change their avatar */
|
||||
"USER_UPDATED_AVATAR" = "%@ 變更了他們的頭像";
|
||||
"USER_UPDATED_AVATAR" = "%@ 變更了大頭照";
|
||||
|
||||
/* A user has reacted to a message, but the reaction content is unknown */
|
||||
"GENERIC_REACTION_FROM_USER" = "%@ 送出了一個反應";
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
"directory_title" = "目錄";
|
||||
"auth_recaptcha_message" = "這個家伺服器想要確認您不是機器人";
|
||||
"auth_reset_password_missing_email" = "必須輸入和您帳號綁定的電子郵件地址。";
|
||||
"auth_reset_password_missing_password" = "必須輸入一個新密碼。";
|
||||
"auth_reset_password_missing_password" = "必須輸入新密碼。";
|
||||
"auth_reset_password_next_step_button" = "我已經驗證了電子郵件地址";
|
||||
"auth_reset_password_error_unauthorized" = "電子郵件地址驗證失敗:請確認您已點擊郵件中的連結";
|
||||
"auth_reset_password_error_not_found" = "您的電子郵件地址似乎並未與這台家伺服器上的任何 Matrix ID 相關聯。";
|
||||
@@ -384,9 +384,9 @@
|
||||
"room_details_photo" = "聊天室圖片";
|
||||
"room_details_room_name" = "聊天室名稱";
|
||||
"room_details_mute_notifs" = "將通知靜音";
|
||||
"room_details_access_section_no_address_warning" = "要連結一個聊天室,該聊天室必須要有位址";
|
||||
"room_details_access_section_no_address_warning" = "要連結聊天室,該聊天室必須要有位址";
|
||||
"room_details_access_section_directory_toggle" = "將此聊天室列入聊天室目錄";
|
||||
"room_details_history_section_prompt_msg" = "對可閱讀歷史訊息的使用者的變更,將僅適用於此聊天室的新訊息。現有訊息的顯示狀態將保持不變。";
|
||||
"room_details_history_section_prompt_msg" = "對可閱讀訊息紀錄的使用者的變更,僅適用於此聊天室的新訊息。現有訊息的顯示狀態將保持不變。";
|
||||
"room_details_new_address" = "新增位址";
|
||||
"room_details_new_address_placeholder" = "新增位址(例如 #foo%@)";
|
||||
"room_details_addresses_invalid_address_prompt_msg" = "%@ 不是有效的別名格式";
|
||||
@@ -454,7 +454,7 @@
|
||||
"directory_server_type_homeserver" = "輸入一個家伺服器來列出所有公開聊天室";
|
||||
"directory_server_placeholder" = "matrix.org";
|
||||
// Events formatter
|
||||
"event_formatter_member_updates" = "變更 %tu 成員身分";
|
||||
"event_formatter_member_updates" = "%tu 筆成員狀態變更";
|
||||
"event_formatter_widget_added" = "%@ 小工具已由 %@ 新增";
|
||||
"event_formatter_widget_removed" = "%@ 小工具已由 %@ 移除";
|
||||
"event_formatter_jitsi_widget_added" = "VoIP 群組通話已由 %@ 新增";
|
||||
@@ -526,7 +526,7 @@
|
||||
"room_message_reply_to_placeholder" = "傳送回覆(未加密)…";
|
||||
"encrypted_room_message_reply_to_placeholder" = "傳送加密的回覆…";
|
||||
"room_message_reply_to_short_placeholder" = "傳送回覆…";
|
||||
"room_event_action_view_decrypted_source" = "檢視已解密的來源";
|
||||
"room_event_action_view_decrypted_source" = "檢視解密的原始碼";
|
||||
"room_predecessor_link" = "點擊此處以檢視更早以前的訊息。";
|
||||
"room_replacement_information" = "這個聊天室已被取代,且不再使用。";
|
||||
"room_replacement_link" = "對話在此繼續。";
|
||||
@@ -622,7 +622,7 @@
|
||||
"store_full_description" = "Element 是一套新型的通訊和協作應用程式,它提供下列功能:\n\n1. 您可以自行掌控隱私\n2. 可以與 Matrix 網路中的任何人進行通訊,甚至可以與 Slack 等應用程式整合\n3. 保護您免受廣告、資料探勘、後門和封閉平台的侵害\n4. 透過端到端加密和交叉簽署來驗證彼此,互相確保安全\n\nElement 是去中心化的開源軟體,因此與其他通訊和協作應用程式完全不同。\n\nElement 允許您自行架設(或選擇託管)伺服器,使您可針對隱私權,所有權以及對資料和對話內容的完整控制權。您可以連線到所有開放的網路,所以您不是只能與其他 Element 使用者聊天。而且還非常安全。\n\nElement 之所以能夠做到所有這些目標,是因為它使用 Matrix(一套開放、去中心化的通訊標準)運作。\n\nElement 讓您可以自行選擇要將對話放在哪一台伺服器來讓您可自行控制自己的訊息和資料。在 Element 應用程式中,您可以選擇以不同方式託管您的訊息:\n\n1. 在 matrix.org 公開伺服器註冊免費帳號\n2. 使用自行架設的硬體主機上的伺服器來註冊帳號\n3. 訂閱 Element Matrix Services 代管平台,註冊自己的伺服器\n\n為什麼要選擇 Element?\n\n自己擁有自己資料:由您決定將資料與訊息保留在何處。您自己擁有並管理這些資料,而不用讓某些「超大型企業」來探勘您的資料,或將資料提供給第三方。\n\n開放的通訊與協作機制:您可以與 Matrix 網路中的任何人聊天,不管他們使用的是 Element 還是其他 Matrix 應用程式,甚至他們也可以使用像 Slack 、IRC 或 XMPP 之類的其他通訊系統。\n\n超級安全:真正的端對端加密(只有對話中的人才能解開訊息內容),並進行交叉簽署以驗證對話參與者的設備。\n\n完整的通訊:傳訊息、進行語音或視訊通話、分享檔案、畫面,還有大量整合、機器人與小工具。建立聊天室、社群,保持聯繫並完成工作。\n\n無論您身在何處都可保持聯繫:無論您身在何處,都可以透過 https://element.io/app 在所有裝置與網路取得完全同步的訊息記錄來保持聯繫。";
|
||||
// String for App Store
|
||||
"store_short_description" = "去中心化的安全通訊/VoIP 軟體";
|
||||
"settings_three_pids_management_information_part1" = "在此管理您用作登入或恢復帳號的電子郵件地址或電話號碼。您也可控制誰可以用這些資料找到您 ";
|
||||
"settings_three_pids_management_information_part1" = "您可以在 ";
|
||||
"external_link_confirmation_message" = "此連結 %@ 將帶您到另一網頁:%@\n\n確定要前往嗎?";
|
||||
"external_link_confirmation_title" = "請確認此連結";
|
||||
"media_type_accessibility_sticker" = "貼圖";
|
||||
@@ -826,7 +826,7 @@
|
||||
"event_formatter_call_answer" = "接聽";
|
||||
"event_formatter_call_back" = "回撥";
|
||||
"event_formatter_call_has_ended" = "通話結束";
|
||||
"event_formatter_call_connecting" = "正在連接…";
|
||||
"event_formatter_call_connecting" = "連線中…";
|
||||
"event_formatter_message_edited_mention" = "(已編輯)";
|
||||
"image_picker_action_library" = "從媒體庫挑選";
|
||||
|
||||
@@ -881,14 +881,14 @@
|
||||
"settings_messages_containing_keywords" = "關鍵字";
|
||||
"settings_messages_containing_user_name" = "我的使用者名稱";
|
||||
"settings_messages_containing_display_name" = "我的顯示名稱";
|
||||
"settings_encrypted_group_messages" = "已加密的群組訊息";
|
||||
"settings_encrypted_group_messages" = "加密的群組訊息";
|
||||
"settings_group_messages" = "群組訊息";
|
||||
"settings_encrypted_direct_messages" = "已加密的私人訊息";
|
||||
"settings_encrypted_direct_messages" = "加密的私人訊息";
|
||||
"settings_direct_messages" = "私人訊息";
|
||||
"settings_default" = "預設通知";
|
||||
"settings_notifications_disabled_alert_title" = "已停用通知";
|
||||
"settings_device_notifications" = "裝置通知";
|
||||
"settings_three_pids_management_information_part3" = "。";
|
||||
"settings_three_pids_management_information_part3" = "管理您用作登入或恢復帳號的電子郵件地址或電話號碼。您也可控制誰可以用這些資料找到您。";
|
||||
"room_join_group_call" = "加入";
|
||||
"room_place_voice_call" = "語音通話";
|
||||
"room_accessibility_video_call" = "視訊通話";
|
||||
@@ -924,7 +924,7 @@
|
||||
"room_event_encryption_info_event" = "事件資訊\n";
|
||||
"room_event_encryption_info_event_user_id" = "使用者 ID\n";
|
||||
"room_event_encryption_info_event_identity_key" = "Curve25519 身分認證金鑰\n";
|
||||
"room_event_encryption_info_event_fingerprint_key" = "已聲請之 Ed25519 指紋金鑰\n";
|
||||
"room_event_encryption_info_event_fingerprint_key" = "聲稱的 Ed25519 指紋金鑰\n";
|
||||
"room_event_encryption_info_event_algorithm" = "演算法\n";
|
||||
"room_event_encryption_info_event_session_id" = "工作階段 ID\n";
|
||||
"room_event_encryption_info_event_decryption_error" = "解密錯誤\n";
|
||||
@@ -993,14 +993,14 @@
|
||||
"notice_room_ban" = "%@ 已封鎖 %@";
|
||||
"notice_room_withdraw" = "%@ 已撤回 %@ 的邀請";
|
||||
"notice_room_reason" = ",原因:%@";
|
||||
"notice_avatar_url_changed" = "%@ 已變更大頭照";
|
||||
"notice_display_name_set" = "%@ 已將他們的顯示名稱設定為 %@";
|
||||
"notice_display_name_changed_from" = "%@ 將自己的顯示名稱從 %@ 改為 %@";
|
||||
"notice_display_name_removed" = "%@ 已移除他們的顯示名稱";
|
||||
"notice_topic_changed" = "%@ 已經將主題變更為:%@。";
|
||||
"notice_avatar_url_changed" = "%@ 變更了大頭照";
|
||||
"notice_display_name_set" = "%@ 將顯示名稱設定為 %@";
|
||||
"notice_display_name_changed_from" = "%@ 將顯示名稱從 %@ 改為 %@";
|
||||
"notice_display_name_removed" = "%@ 移除了顯示名稱";
|
||||
"notice_topic_changed" = "%@ 將主題變更為「%@」。";
|
||||
"notice_room_name_changed" = "%@ 將聊天室名稱變更為 %@。";
|
||||
"notice_placed_voice_call" = "%@ 已播出語音通話";
|
||||
"notice_placed_video_call" = "%@ 已播出視訊通話";
|
||||
"notice_placed_voice_call" = "%@ 已撥出語音通話";
|
||||
"notice_placed_video_call" = "%@ 已撥出視訊通話";
|
||||
"notice_answered_video_call" = "%@ 已接聽通話";
|
||||
"notice_ended_video_call" = "%@ 已結束通話";
|
||||
"notice_conference_call_request" = "%@ 已請求 VoIP 會議";
|
||||
@@ -1098,7 +1098,7 @@
|
||||
"notice_room_topic_removed" = "%@ 移除了該主題";
|
||||
"notice_event_redacted_by" = " 由 %@";
|
||||
"notice_event_redacted_reason" = " [理由:%@]";
|
||||
"notice_profile_change_redacted" = "%@ 已更新他的個人檔案 %@";
|
||||
"notice_profile_change_redacted" = "%@ 更新了個人檔案 %@";
|
||||
"notice_room_created" = "%@ 已建立並設定該聊天室。";
|
||||
"notice_room_join_rule" = "加入規則: %@";
|
||||
"notice_room_power_level_intro" = "聊天室成員們的權限级别是:";
|
||||
@@ -1138,7 +1138,7 @@
|
||||
"notice_error_unexpected_event" = "意外事件";
|
||||
"notice_error_unknown_event_type" = "未知的事件類型";
|
||||
"notice_room_history_visible_to_anyone" = "%@ 讓任何人都能看到未來的聊天室歷史記錄。";
|
||||
"notice_room_history_visible_to_members" = "%@ 讓所有聊天室成員都能看到聊天室之後的歷史記錄。";
|
||||
"notice_room_history_visible_to_members" = "%@ 讓所有成員都能看到聊天室之後的歷史記錄。";
|
||||
"stop" = "停止";
|
||||
"joining" = "正在加入";
|
||||
"enable" = "啟用";
|
||||
@@ -1291,18 +1291,18 @@
|
||||
// Settings keys
|
||||
|
||||
// call string
|
||||
"call_connecting" = "正在連接…";
|
||||
"call_connecting" = "連線中…";
|
||||
"notification_settings_notify_all_other" = "其他訊息/聊天室的通知";
|
||||
"notification_settings_by_default" = "按預設…";
|
||||
"notification_settings_suppress_from_bots" = "限制來自機器人的通知";
|
||||
"notification_settings_receive_a_call" = "當我收到通話時,請通知我";
|
||||
"notification_settings_people_join_leave_rooms" = "有人加入或離開聊天室時,請通知我";
|
||||
"notification_settings_invite_to_a_new_room" = "當我被邀請到一個全新的聊天室時,請通知我";
|
||||
"notification_settings_just_sent_to_me" = "當收到只寄給我的訊息時,請用聲音通知我";
|
||||
"notification_settings_contain_my_display_name" = "訊息出現我的顯示名稱時,請用聲音通知我";
|
||||
"notification_settings_contain_my_user_name" = "訊息出現我的使用者名稱時,請用聲音通知我";
|
||||
"notification_settings_invite_to_a_new_room" = "當我被邀請到全新的聊天室時,請通知我";
|
||||
"notification_settings_just_sent_to_me" = "當收到只寄給我的訊息時,請用音效通知我";
|
||||
"notification_settings_contain_my_display_name" = "訊息出現我的顯示名稱時,請用音效通知我";
|
||||
"notification_settings_contain_my_user_name" = "訊息出現我的使用者名稱時,請用音效通知我";
|
||||
"notification_settings_other_alerts" = "其他警告";
|
||||
"notification_settings_select_room" = "選擇一個聊天室";
|
||||
"notification_settings_select_room" = "請選擇聊天室";
|
||||
"notification_settings_sender_hint" = "@user:domain.com";
|
||||
"notification_settings_per_sender_notifications" = "寄件人通知";
|
||||
"notification_settings_per_room_notifications" = "聊天室的通知";
|
||||
@@ -1346,11 +1346,11 @@
|
||||
"login_error_already_logged_in" = "已經登入";
|
||||
"message_unsaved_changes" = "還有變更未儲存。現在離開的話,您將會放棄這些變動。";
|
||||
"notice_room_history_visible_to_members_from_joined_point_by_you_for_dm" = "您讓所有人在加入後,就能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_from_joined_point_by_you" = "您讓所有聊天室成員在加入後,都能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_from_joined_point_by_you" = "您讓所有成員在加入後,都能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_from_invited_point_by_you_for_dm" = "您讓所有人收到邀請後,都能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_from_invited_point_by_you" = "您讓所有聊天室成員被邀請後,都能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_by_you_for_dm" = "您讓所有聊天室成員都能看到聊天室未來的歷史記錄。";
|
||||
"notice_room_history_visible_to_members_by_you" = "您讓所有聊天室成員都能看到聊天室未來的歷史記錄。";
|
||||
"notice_room_history_visible_to_members_from_invited_point_by_you" = "您讓所有成員被邀請後,都能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_by_you_for_dm" = "您讓所有成員都能看到聊天室未來的歷史記錄。";
|
||||
"notice_room_history_visible_to_members_by_you" = "您讓所有成員都能看到聊天室未來的歷史記錄。";
|
||||
"notice_room_history_visible_to_anyone_by_you" = "您讓任何人都能看到未來的聊天室歷史記錄。";
|
||||
"notice_redaction_by_you" = "您已取消一个事件(id: %@)";
|
||||
"notice_encryption_enabled_unknown_algorithm_by_you" = "您已開啟端到端加密(無法識別的演算法 %@)。";
|
||||
@@ -1366,14 +1366,14 @@
|
||||
"notice_declined_video_call_by_you" = "您已拒絕此通話";
|
||||
"notice_ended_video_call_by_you" = "您已結束通話";
|
||||
"notice_answered_video_call_by_you" = "您已接聽此通話";
|
||||
"notice_placed_video_call_by_you" = "您已播出視訊通話";
|
||||
"notice_placed_voice_call_by_you" = "您已播出語音通話";
|
||||
"notice_room_name_changed_by_you_for_dm" = "您已將名稱變更為 %@。";
|
||||
"notice_room_name_changed_by_you" = "您已將聊天室名稱變更為 %@。";
|
||||
"notice_topic_changed_by_you" = "您已經將主題變更為:%@。";
|
||||
"notice_placed_video_call_by_you" = "您已撥出視訊通話";
|
||||
"notice_placed_voice_call_by_you" = "您已撥出語音通話";
|
||||
"notice_room_name_changed_by_you_for_dm" = "您將名稱變更為 %@。";
|
||||
"notice_room_name_changed_by_you" = "您將聊天室名稱變更為 %@。";
|
||||
"notice_topic_changed_by_you" = "您將主題更改為:「%@」。";
|
||||
"notice_display_name_removed_by_you" = "您已移除自己的顯示名稱";
|
||||
"notice_display_name_changed_from_by_you" = "您已將顯示名稱從 %@ 變更為 %@";
|
||||
"notice_display_name_set_by_you" = "您已將顯示名稱設定為 %@";
|
||||
"notice_display_name_set_by_you" = "您將您的顯示名稱設定為 %@";
|
||||
"notice_avatar_url_changed_by_you" = "您已變更您的大頭照";
|
||||
"notice_room_withdraw_by_you" = "您已撤回 %@ 的邀請";
|
||||
"notice_room_ban_by_you" = "您已封鎖 %@";
|
||||
@@ -1392,12 +1392,12 @@
|
||||
// Notice Events with "You"
|
||||
"notice_room_invite_by_you" = "您已邀請 %@";
|
||||
"notice_declined_video_call" = "%@ 已拒絕此通話";
|
||||
"notice_room_name_changed_for_dm" = "%@ 把名稱變更為 %@。";
|
||||
"notice_room_name_changed_for_dm" = "%@ 將名稱變更為 %@。";
|
||||
"notice_room_third_party_revoked_invite_for_dm" = "%@ 已撤銷對 %@ 的邀請";
|
||||
"notice_room_third_party_revoked_invite" = "%@ 已撤銷對 %@ 加入聊天室的邀請";
|
||||
"notice_room_third_party_invite_for_dm" = "%@ 已邀請 %@";
|
||||
"microphone_access_not_granted_for_voice_message" = "語音簡訊需要使用麥克風的權限,但是 %@ 沒有存取權限";
|
||||
"error_common_message" = "發生了一個錯誤。請重新再試。";
|
||||
"error_common_message" = "發生錯誤。請稍後再試。";
|
||||
"e2e_passphrase_create" = "建立安全密語";
|
||||
"e2e_passphrase_too_short" = "安全密語太短(至少要 %d 字母的長度)";
|
||||
"e2e_passphrase_confirm" = "確認安全密語";
|
||||
@@ -1445,7 +1445,7 @@
|
||||
"room_member_ignore_prompt" = "您確定要隱藏所有來自此使用者的訊息嗎?";
|
||||
"message_reply_to_message_to_reply_to_prefix" = "回覆給";
|
||||
"message_reply_to_sender_sent_their_live_location" = "即時位置。";
|
||||
"message_reply_to_sender_sent_their_location" = "已經分享了他們的位置。";
|
||||
"message_reply_to_sender_sent_their_location" = "分享了他們的位置。";
|
||||
"message_reply_to_sender_sent_a_file" = "已傳送檔案。";
|
||||
"message_reply_to_sender_sent_a_voice_message" = "已傳送語音訊息。";
|
||||
"message_reply_to_sender_sent_an_audio_file" = "已傳送音訊檔。";
|
||||
@@ -1531,7 +1531,7 @@
|
||||
"user_session_rename_session_title" = "正在重新命名工作階段";
|
||||
"user_session_inactive_session_description" = "不活躍的工作階段是您有一段時間未使用的工作階段,但它們會繼續接收加密金鑰。\n\n移除不活躍的工作階段可以改善安全性與效能,並讓您可以更容易地識別新的工作階段是否可疑。";
|
||||
"user_session_inactive_session_title" = "不活躍的工作階段";
|
||||
"user_session_permanently_unverified_session_description" = "此工作階段無法對此對話進行加密,因此無法驗證。\n\n您無法進入已加密的聊天室中。\n\n為了安全與隱私,建議使用支援加密的 Matrix 客戶端。";
|
||||
"user_session_permanently_unverified_session_description" = "此工作階段不支援加密功能,所以無法驗證。\n\n您無法使用此工作階段進入有開啟加密的聊天室中。\n\n為了安全與隱私,建議使用支援加密的 Matrix 客戶端。";
|
||||
"user_session_unverified_session_description" = "未驗證的工作階段是使用您的憑證登入但交叉叉驗證的工作階段。\n\n您應特別確定您可以識別這些工作階段,因為它們可能代表未經授權使用您的帳號。";
|
||||
"user_session_unverified_session_title" = "未經驗證的工作階段";
|
||||
"user_session_verified_session_description" = "已驗證的工作階段,是您輸入安全密語或透過另一個已驗證工作階段確認您的身分後,使用此 Element 帳號的任何地方。\n\n這代表了您擁有解鎖加密訊息,並向其他使用者確認您信任此工作階段所需的所有金鑰。";
|
||||
@@ -1638,8 +1638,8 @@
|
||||
"poll_timeline_total_one_vote_not_voted" = "已投 1 票。投票後即可檢視結果";
|
||||
"poll_timeline_total_votes" = "共計 %lu 票";
|
||||
"poll_timeline_total_one_vote" = "共計 1 票";
|
||||
"poll_timeline_total_no_votes" = "尚未投票";
|
||||
"poll_timeline_votes_count" = "%lu 張票";
|
||||
"poll_timeline_total_no_votes" = "尚無投票";
|
||||
"poll_timeline_votes_count" = "%lu 票";
|
||||
"poll_timeline_one_vote" = "1 票";
|
||||
"poll_edit_form_poll_type_closed_description" = "結果僅在您結束投票後顯示";
|
||||
"poll_edit_form_poll_type_closed" = "秘密投票";
|
||||
@@ -1683,12 +1683,12 @@
|
||||
"all_chats_nothing_found_placeholder_title" = "找不到任何結果。";
|
||||
"all_chats_empty_unreads_placeholder_message" = "當您有一些未讀的訊息時,這裡會顯示您的未讀訊息。";
|
||||
"all_chats_empty_list_placeholder_title" = "您都看完了。";
|
||||
"all_chats_empty_view_information" = "適用於團隊、朋友與組織的多合一安全聊天應用程式。建立聊天室,或加入一個既有的聊天室。";
|
||||
"all_chats_empty_view_information" = "適用於團隊、朋友與組織的多合一安全聊天應用程式。建立聊天室,或加入現有的聊天室。";
|
||||
"all_chats_empty_space_information" = "聊天空間是一種為聊天室與人們分組的新方式。使用右下角的按鈕新增既有的聊天室或建立新的。";
|
||||
"all_chats_empty_view_title" = "%@\n看起來有點空。";
|
||||
"all_chats_all_filter" = "全部";
|
||||
"all_chats_edit_layout_alphabetical_order" = "按 A-Z 排列";
|
||||
"all_chats_edit_layout_activity_order" = "按活動排列";
|
||||
"all_chats_edit_layout_alphabetical_order" = "按名稱 A-Z 排序";
|
||||
"all_chats_edit_layout_activity_order" = "按頻道最新活動排列";
|
||||
"all_chats_edit_layout_show_filters" = "顯示過濾條件";
|
||||
"all_chats_edit_layout_show_recents" = "顯示最近的";
|
||||
"all_chats_edit_layout_sorting_options_title" = "分類您的訊息";
|
||||
@@ -1870,7 +1870,7 @@
|
||||
"home_context_menu_normal_priority" = "一般優先度";
|
||||
"home_context_menu_low_priority" = "低優先度";
|
||||
"home_context_menu_unfavourite" = "從我的最愛移除";
|
||||
"home_context_menu_favourite" = "我的最愛";
|
||||
"home_context_menu_favourite" = "加入我的最愛";
|
||||
"home_context_menu_unmute" = "解除靜音";
|
||||
"home_context_menu_mute" = "靜音";
|
||||
"home_context_menu_notifications" = "通知";
|
||||
@@ -1996,10 +1996,10 @@
|
||||
"notice_crypto_error_unknown_inbound_session_id" = "傳送者的工作階段,尚未傳送傳給我們這則訊息的金鑰。";
|
||||
"notice_crypto_unable_to_decrypt" = "** 無法解密:%@ **";
|
||||
"notice_room_history_visible_to_members_from_joined_point_for_dm" = "%@ 您讓所有人被邀請後,都能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_from_joined_point" = "%@ 讓所有聊天室成員被邀請後開始,都能看到未來的聊天室歷史紀錄。";
|
||||
"notice_room_history_visible_to_members_from_invited_point_for_dm" = "%@ 從他們被邀請開始,讓未來的聊天室歷史紀錄顯示給所有聊天室成員。";
|
||||
"notice_room_history_visible_to_members_from_invited_point" = "%@ 從他們被邀請開始,讓未來的聊天室歷史紀錄顯示給所有聊天室成員。";
|
||||
"notice_room_history_visible_to_members_for_dm" = "%@ 讓所有聊天室成員都能看到聊天室之後的歷史記錄。";
|
||||
"notice_room_history_visible_to_members_from_joined_point" = "%@ 讓所有成員被邀請後開始,都能看到未來的聊天紀錄。";
|
||||
"notice_room_history_visible_to_members_from_invited_point_for_dm" = "%@ 從他們被邀請開始,讓未來的聊天紀錄顯示給所有成員。";
|
||||
"notice_room_history_visible_to_members_from_invited_point" = "%@ 從他們被邀請開始,讓未來的聊天紀錄顯示給所有成員。";
|
||||
"notice_room_history_visible_to_members_for_dm" = "%@ 讓所有成員都能看到聊天室之後的歷史記錄。";
|
||||
"notice_error_unformattable_event" = "** 無法顯示這則訊息。請回報此錯誤";
|
||||
"notice_encryption_enabled_unknown_algorithm" = "%1$@ 已開啟端到端加密(無法識別的演算法 %2$@)。";
|
||||
"notice_encryption_enabled_ok" = "%@ 已開啟端到端加密。";
|
||||
@@ -2009,11 +2009,11 @@
|
||||
"notice_room_join_rule_public_by_you" = "您已公開此聊天室。";
|
||||
"notice_room_join_rule_public_for_dm" = "%@ 公開這個。";
|
||||
"notice_room_join_rule_public" = "%@ 公開此聊天室。";
|
||||
"notice_room_join_rule_invite_by_you_for_dm" = "您讓此變為邀請制。";
|
||||
"notice_room_join_rule_invite_by_you_for_dm" = "您將此處變為邀請制。";
|
||||
"notice_room_join_rule_invite_by_you" = "您讓聊天室變為邀請才可加入。";
|
||||
"notice_room_join_rule_invite_for_dm" = "%@讓此變為邀請制。";
|
||||
"notice_room_join_rule_invite_for_dm" = "%@ 將此處變為邀請制。";
|
||||
// New
|
||||
"notice_room_join_rule_invite" = "%@讓聊天室變為邀請才可加入。";
|
||||
"notice_room_join_rule_invite" = "%@ 將聊天室變為邀請制。";
|
||||
"notice_room_created_for_dm" = "%@ 已加入。";
|
||||
"notice_room_name_removed_for_dm" = "%@ 移除了該聊天室的名稱";
|
||||
"ignore_user" = "忽略使用者";
|
||||
@@ -2114,7 +2114,7 @@
|
||||
|
||||
|
||||
// Generic errors
|
||||
"error_invite_3pid_with_no_identity_server" = "在設定加入一個身分伺服器,才能用電子郵件寄送邀請。";
|
||||
"error_invite_3pid_with_no_identity_server" = "在設定加入身分伺服器後,才能用電子郵件寄送邀請。";
|
||||
"emoji_picker_flags_category" = "旗幟";
|
||||
"emoji_picker_symbols_category" = "符號";
|
||||
"emoji_picker_places_category" = "旅遊與景點";
|
||||
@@ -2128,7 +2128,7 @@
|
||||
|
||||
// User
|
||||
|
||||
"key_verification_verified_user_information" = "與此使用者的訊息是端到端加密的,無法被第三方讀取。";
|
||||
"key_verification_verified_user_information" = "與此使用者的訊息有端對端加密,無法被第三方讀取。";
|
||||
"key_verification_verified_this_session_information" = "您現在可以在此裝置上閱讀您的加密訊息,其他使用者也會知道他們能夠信任此裝置。";
|
||||
"key_verification_verified_new_session_information" = "您現在也可以在新的裝置上閱讀您的加密訊息,其他使用者也會知道他們能夠信任此裝置。";
|
||||
"key_verification_verified_other_session_information" = "您現在也可以在其他的工作階段閱讀您的加密訊息,其他使用者也會知道他們能夠信任此工作階段。";
|
||||
@@ -2300,7 +2300,7 @@
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_info" = "輸入只有您知道的安全密語,並產生備份的金鑰。";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_title" = "使用安全密語";
|
||||
"secure_key_backup_setup_intro_use_security_key_info" = "產生安全金鑰後,請儲存在密碼管理員或保險箱等安全的地方。";
|
||||
"secure_key_backup_setup_intro_info" = "透過備份您伺服器上的加密金鑰,來防止失去對您已加密的訊息與資料的存取權。";
|
||||
"secure_key_backup_setup_intro_info" = "透過備份您伺服器上的加密金鑰,來防止失去對加密訊息與資料的存取權。";
|
||||
"service_terms_modal_information_description_integration_manager" = "整合管理員能夠讓您加入第三方服務的功能。";
|
||||
"service_terms_modal_information_description_identity_server" = "身分伺服器讓您能夠用電話或電子郵件,查詢您的聯絡人是否已經申請帳號。";
|
||||
"service_terms_modal_information_title_integration_manager" = "整合管理員";
|
||||
@@ -2309,7 +2309,7 @@
|
||||
"service_terms_modal_information_title_identity_server" = "身分伺服器";
|
||||
"service_terms_modal_description_integration_manager" = "這會讓您可以使用聊天機器人、橋接、小工具和貼圖包。";
|
||||
"service_terms_modal_description_identity_server" = "這會讓手機上儲存您電話或電子郵件的人能找到您。";
|
||||
"service_terms_modal_table_header_integration_manager" = "管理整合服務使用條款";
|
||||
"service_terms_modal_table_header_integration_manager" = "整合管理員使用條款";
|
||||
"service_terms_modal_table_header_identity_server" = "身分伺服器條款";
|
||||
"service_terms_modal_footer" = "您可以隨時在設定中取消。";
|
||||
|
||||
@@ -2362,10 +2362,10 @@
|
||||
|
||||
"leave_space_action" = "離開聊天空間";
|
||||
"spaces_add_room_missing_permission_message" = "您沒有權限在此聊天空間中新增聊天室。";
|
||||
"spaces_creation_in_one_space" = "在一個聊天空間";
|
||||
"spaces_creation_in_one_space" = "在 1 個聊天空間";
|
||||
"spaces_creation_in_many_spaces" = "在 %@ 個聊天空間";
|
||||
"spaces_creation_in_spacename_plus_many" = "在 %@ 加入 %@ 個聊天空間";
|
||||
"spaces_creation_in_spacename_plus_one" = "在 %@ 加入一個聊天空間";
|
||||
"spaces_creation_in_spacename_plus_one" = "在 %@ 加入 1 個聊天空間";
|
||||
"spaces_creation_in_spacename" = "在 %@";
|
||||
"spaces_creation_post_process_inviting_users" = "邀請 %@ 位使用者";
|
||||
"spaces_creation_post_process_adding_rooms" = "加入 %@ 個聊天室";
|
||||
@@ -2424,7 +2424,7 @@
|
||||
"room_notifs_settings_mentions_and_keywords" = "僅提及和關鍵字";
|
||||
|
||||
// Room Notification Settings
|
||||
"room_notifs_settings_notify_me_for" = "通知我";
|
||||
"room_notifs_settings_notify_me_for" = "收到下列訊息時通知我";
|
||||
"room_suggestion_settings_screen_message" = "將向聊天空間中的成員推薦建議的聊天室。";
|
||||
"room_suggestion_settings_screen_title" = "將聊天室設為聊天空間中的建議聊天室";
|
||||
|
||||
@@ -2437,7 +2437,7 @@
|
||||
"room_access_settings_screen_upgrade_alert_upgrading" = "升級聊天室";
|
||||
"room_access_settings_screen_upgrade_alert_upgrade_button" = "升級";
|
||||
"room_access_settings_screen_upgrade_alert_auto_invite_switch" = "自動邀請成員到新的聊天室";
|
||||
"room_access_settings_screen_upgrade_alert_note" = "請注意,升級會創造一個新版本的聊天室。目前所有的訊息都會放在已封存的聊天室。";
|
||||
"room_access_settings_screen_upgrade_alert_note" = "請注意,升級會建立新版的聊天室。目前的所有訊息都將封存在此聊天室中。";
|
||||
"room_access_settings_screen_upgrade_alert_message_no_param" = "母聊天空間中的任何人都可以找到並加入此聊天室,不需要手動邀請所有人。您隨時都可以在聊天室設定中變更此設定。";
|
||||
"room_access_settings_screen_upgrade_alert_message" = "任何在 %@ 的人都能找到並加入此聊天室,不需手動邀請所有人。您可以在聊天室的設定中隨時變更此設定。";
|
||||
"room_access_settings_screen_upgrade_alert_title" = "升級聊天室";
|
||||
@@ -2474,7 +2474,7 @@
|
||||
"identity_server_settings_alert_change_title" = "變更身分伺服器";
|
||||
"identity_server_settings_alert_no_terms" = "您選擇的身分伺服器沒有任何服務條款。僅在您信任服務擁有者時才繼續。";
|
||||
"identity_server_settings_alert_no_terms_title" = "身分伺服器無使用條款";
|
||||
"identity_server_settings_disconnect_info" = "如果您未連線到您的身分伺服器,其他的使用者將無法找到您,您也無法經由電子郵件和電話找到其他使用者。";
|
||||
"identity_server_settings_disconnect_info" = "與您的身分伺服器中斷連線後,其他使用者就無法再探索到您,您也不能透過電子郵件地址或電話號碼邀請其他人。";
|
||||
"identity_server_settings_place_holder" = "輸入一個身分伺服器";
|
||||
"identity_server_settings_no_is_description" = "您目前未使用身分伺服器。若想要尋找或被您認識的聯絡人找到,請在上方加入伺服器。";
|
||||
"identity_server_settings_description" = "您正在使用 %@ 來讓其他現有的聯絡人和您能夠找到彼此。";
|
||||
@@ -2531,9 +2531,9 @@
|
||||
"settings_discovery_three_pid_details_revoke_action" = "撤回";
|
||||
"settings_discovery_three_pid_details_information_phone_number" = "在此管理讓其他使用者尋找您以及邀請您進入聊天室的電話號碼偏好設定。您可以在「帳號」中加入或刪除電話號碼。";
|
||||
"settings_discovery_three_pid_details_information_email" = "在此管理讓其他使用者尋找您以及邀請您進入聊天室的電子郵件地址偏好設定。您可以在「帳號」中加入或刪除電子郵件地址。";
|
||||
"settings_discovery_three_pids_management_information_part1" = "選擇您希望其他使用者用哪一個電子郵件(或電話)聯絡您,以及邀請您進入聊天室。您可以在此清單加入/移除電子郵件(或電話)。 ";
|
||||
"settings_discovery_three_pids_management_information_part1" = "選擇您希望其他使用者用哪一個電子郵件地址(或電話號碼)聯絡您,以及邀請您進入聊天室。您可以在此清單加入/移除電子郵件地址(或電話號碼)。 ";
|
||||
"settings_discovery_accept_terms" = "同意身分伺服器的使用條款";
|
||||
"settings_discovery_terms_not_signed" = "同意身分伺服器(%@)的使用條款,讓其他人可以用您的電子郵件或電話號碼找到您。";
|
||||
"settings_discovery_terms_not_signed" = "需同意身分伺服器(%@)的使用條款,讓其他人可以用電子郵件地址或電話號碼找到您。";
|
||||
"settings_discovery_no_identity_server" = "您目前未使用身分伺服器。若想要被您認識的聯絡人找到,請加入伺服器。";
|
||||
"settings_devices_description" = "所有與您通訊的聯絡人都能看到此工作階段的公開名稱";
|
||||
"settings_key_backup_delete_confirmation_prompt_msg" = "您確定嗎?如果您的金鑰沒有正確備份的話,將會遺失所有加密訊息。";
|
||||
@@ -2576,7 +2576,7 @@
|
||||
// Sessions list
|
||||
|
||||
"user_verification_sessions_list_user_trust_level_trusted_title" = "受信任";
|
||||
"user_verification_start_additional_information" = "要確定安全,請面對面進行或使用其他方式來通訊。";
|
||||
"user_verification_start_additional_information" = "為了確保安全,請面對面進行驗證,或使用其他方式來通訊。";
|
||||
"user_verification_start_waiting_partner" = "正在等待 %@…";
|
||||
"user_verification_start_information_part2" = " 雙方裝置上顯示的單次驗證碼。";
|
||||
"user_verification_start_information_part1" = "為了加強安全性,請確認 ";
|
||||
@@ -2648,8 +2648,8 @@
|
||||
"settings_call_invitations" = "通話邀請";
|
||||
"settings_room_invitations" = "聊天室邀請";
|
||||
"settings_messages_containing_at_room" = "@room";
|
||||
"settings_notify_me_for" = "通知我";
|
||||
"settings_mentions_and_keywords" = "僅有被提及與出現關鍵字時";
|
||||
"settings_notify_me_for" = "收到下列訊息時通知我";
|
||||
"settings_mentions_and_keywords" = "提及與關鍵字";
|
||||
"settings_notifications_disabled_alert_message" = "如需啟用通知,請前往裝置設定。";
|
||||
"settings_security" = "安全性";
|
||||
"settings_confirm_media_size_description" = "開啟此選項後,傳送檔案前,會先向您確認準備傳送的圖片與影片大小。";
|
||||
@@ -2733,7 +2733,7 @@
|
||||
|
||||
// Social login
|
||||
|
||||
"social_login_list_title_continue" = "繼續";
|
||||
"social_login_list_title_continue" = "使用下列方式繼續";
|
||||
"network_offline_message" = "您已離線,請確認您的網路連線。";
|
||||
"network_offline_title" = "您已離線";
|
||||
"event_formatter_jitsi_widget_removed_by_you" = "您已刪除 VoIP 會議";
|
||||
@@ -2743,7 +2743,7 @@
|
||||
// Events formatter with you
|
||||
"event_formatter_widget_added_by_you" = "您新增了小工具:%@";
|
||||
"event_formatter_message_deleted" = "訊息已刪除";
|
||||
"event_formatter_group_call_incoming" = "%@ 在 %@";
|
||||
"event_formatter_group_call_incoming" = "%@ (來自 %@)";
|
||||
"event_formatter_call_decline" = "拒絕";
|
||||
"event_formatter_call_connection_failed" = "連線失敗";
|
||||
"event_formatter_call_missed_video" = "未接聽的視訊通話";
|
||||
@@ -2824,8 +2824,8 @@
|
||||
"wysiwyg_composer_format_action_unordered_list" = "切換項目符號清單";
|
||||
"wysiwyg_composer_format_action_inline_code" = "套用內嵌程式碼格式";
|
||||
"user_other_session_security_recommendation_title" = "其他工作階段";
|
||||
"poll_timeline_reply_ended_poll" = "結束投票";
|
||||
"poll_timeline_ended_text" = "結束投票";
|
||||
"poll_timeline_reply_ended_poll" = "已結束投票";
|
||||
"poll_timeline_ended_text" = "投票已結束";
|
||||
"poll_timeline_decryption_error" = "因為解密錯誤,不會計算部份投票";
|
||||
"poll_history_load_more" = "載入更多投票";
|
||||
"poll_history_detail_view_in_timeline" = "在時間軸中檢視投票";
|
||||
@@ -2856,3 +2856,15 @@
|
||||
// MARK: - Launch loading
|
||||
|
||||
"launch_loading_generic" = "正在同步對話";
|
||||
"pill_message_in" = "在 %@ 的訊息";
|
||||
"pill_message_from" = "來自 %@ 的訊息";
|
||||
"pill_message" = "訊息";
|
||||
|
||||
// Pills
|
||||
"pill_room_fallback_display_name" = "聊天空間/聊天室";
|
||||
"key_verification_self_verify_security_upgrade_alert_message" = "最新版本中已改進加密訊息傳輸功能,請重新驗證您的裝置。";
|
||||
|
||||
// Legacy to Rust security upgrade
|
||||
|
||||
"key_verification_self_verify_security_upgrade_alert_title" = "已更新程式";
|
||||
"settings_acceptable_use" = "可接受使用政策";
|
||||
|
||||
@@ -256,40 +256,18 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed =
|
||||
|
||||
if (componentIndex < bubbleComponents.count)
|
||||
{
|
||||
MXKRoomBubbleComponent *component = bubbleComponents[componentIndex];
|
||||
|
||||
// Define the marker frame
|
||||
CGFloat markPosY = component.position.y + self.msgTextViewTopConstraint.constant;
|
||||
|
||||
NSInteger mostRecentComponentIndex = bubbleComponents.count - 1;
|
||||
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
|
||||
CGRect componentFrame = [self componentFrameInContentViewForIndex:componentIndex];
|
||||
if (CGRectIsEmpty(componentFrame))
|
||||
{
|
||||
mostRecentComponentIndex = ((RoomBubbleCellData*)bubbleData).mostRecentComponentIndex;
|
||||
}
|
||||
|
||||
// Compute the mark height.
|
||||
// Use the rest of the cell height by default.
|
||||
CGFloat markHeight = self.contentView.frame.size.height - markPosY;
|
||||
if (componentIndex != mostRecentComponentIndex)
|
||||
{
|
||||
// There is another component (with display) after this component in the cell.
|
||||
// Stop the marker height to the top of this component.
|
||||
for (NSInteger index = componentIndex + 1; index < bubbleComponents.count; index ++)
|
||||
{
|
||||
MXKRoomBubbleComponent *nextComponent = bubbleComponents[index];
|
||||
|
||||
if (nextComponent.attributedTextMessage)
|
||||
{
|
||||
markHeight = nextComponent.position.y - component.position.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
UIView *markerView = [[UIView alloc] initWithFrame:CGRectMake(VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_X,
|
||||
markPosY,
|
||||
VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_WIDTH,
|
||||
markHeight)];
|
||||
CGRect markerFrame = CGRectMake(VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_X,
|
||||
CGRectGetMinY(componentFrame),
|
||||
VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_WIDTH,
|
||||
CGRectGetHeight(componentFrame));
|
||||
|
||||
UIView *markerView = [[UIView alloc] initWithFrame:markerFrame];
|
||||
markerView.backgroundColor = ThemeService.shared.theme.tintColor;
|
||||
|
||||
[markerView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
@@ -303,28 +281,28 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed =
|
||||
toItem:self.contentView
|
||||
attribute:NSLayoutAttributeLeading
|
||||
multiplier:1.0
|
||||
constant:VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_X];
|
||||
constant:CGRectGetMinX(markerFrame)];
|
||||
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:markerView
|
||||
attribute:NSLayoutAttributeTop
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:self.contentView
|
||||
attribute:NSLayoutAttributeTop
|
||||
multiplier:1.0
|
||||
constant:markPosY];
|
||||
constant:CGRectGetMinY(markerFrame)];
|
||||
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:markerView
|
||||
attribute:NSLayoutAttributeWidth
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:nil
|
||||
attribute:NSLayoutAttributeNotAnAttribute
|
||||
multiplier:1.0
|
||||
constant:VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_WIDTH];
|
||||
constant:CGRectGetWidth(markerFrame)];
|
||||
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:markerView
|
||||
attribute:NSLayoutAttributeHeight
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:nil
|
||||
attribute:NSLayoutAttributeNotAnAttribute
|
||||
multiplier:1.0
|
||||
constant:markHeight];
|
||||
constant:CGRectGetHeight(markerFrame)];
|
||||
|
||||
// Available on iOS 8 and later
|
||||
[NSLayoutConstraint activateConstraints:@[leftConstraint, topConstraint, widthConstraint, heightConstraint]];
|
||||
@@ -600,36 +578,47 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed =
|
||||
}
|
||||
else if (roomBubbleTableViewCell.messageTextView)
|
||||
{
|
||||
// Force the textView used underneath to layout its frame properly
|
||||
[roomBubbleTableViewCell setNeedsLayout];
|
||||
[roomBubbleTableViewCell layoutIfNeeded];
|
||||
|
||||
// Compute the height
|
||||
CGFloat textMessageHeight = 0;
|
||||
|
||||
if ([bubbleCellData isKindOfClass:[RoomBubbleCellData class]])
|
||||
{
|
||||
RoomBubbleCellData *roomBubbleCellData = (RoomBubbleCellData*)bubbleCellData;
|
||||
|
||||
if (!roomBubbleCellData.attachment && selectedComponent.attributedTextMessage)
|
||||
{
|
||||
textMessageHeight = [roomBubbleCellData rawTextHeight:selectedComponent.attributedTextMessage];
|
||||
// Get the width of messageTextView to compute the needed height
|
||||
CGFloat maxTextWidth = CGRectGetWidth(roomBubbleTableViewCell.messageTextView.bounds);
|
||||
|
||||
// Compute text message height
|
||||
textMessageHeight = [roomBubbleCellData rawTextHeight:selectedComponent.attributedTextMessage withMaxWidth:maxTextWidth];
|
||||
}
|
||||
}
|
||||
|
||||
selectedComponentPositionY = selectedComponent.position.y;
|
||||
|
||||
|
||||
// Get the messageText frame in the cell content view (as the messageTextView may be inside a stackView and not directly a child of the tableViewCell)
|
||||
UITextView *messageTextView = roomBubbleTableViewCell.messageTextView;
|
||||
CGRect messageTextViewFrame = [messageTextView convertRect:messageTextView.bounds toView:roomBubbleTableViewCell.contentView];
|
||||
|
||||
if (textMessageHeight > 0)
|
||||
{
|
||||
selectedComponentHeight = textMessageHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedComponentHeight = roomBubbleTableViewCell.frame.size.height - selectedComponentPositionY;
|
||||
// if we don't have a height, use the messageTextView height without the text container vertical insets to stay aligned with the text.
|
||||
selectedComponentHeight = CGRectGetHeight(messageTextViewFrame) - messageTextView.textContainerInset.top - messageTextView.textContainerInset.bottom;
|
||||
}
|
||||
|
||||
// Force the textView used underneath to layout its frame properly
|
||||
[roomBubbleTableViewCell setNeedsLayout];
|
||||
[roomBubbleTableViewCell layoutIfNeeded];
|
||||
|
||||
selectedComponenContentViewYOffset = roomBubbleTableViewCell.messageTextView.frame.origin.y;
|
||||
// Get the vertical position of the messageTextView relative to the contentView
|
||||
selectedComponenContentViewYOffset = CGRectGetMinY(messageTextViewFrame);
|
||||
|
||||
// Get the position of the component inside the messageTextView
|
||||
selectedComponentPositionY = selectedComponent.position.y;
|
||||
}
|
||||
|
||||
|
||||
if (roomBubbleTableViewCell.attachmentView || roomBubbleTableViewCell.messageTextView)
|
||||
{
|
||||
CGFloat x = 0;
|
||||
@@ -801,8 +790,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed =
|
||||
|
||||
- (void)addTickView:(UIView *)tickView atIndex:(NSInteger)index
|
||||
{
|
||||
CGRect componentFrame = [self componentFrameInContentViewForIndex: index];
|
||||
|
||||
CGRect componentFrame = [self componentFrameInContentViewForIndex:index];
|
||||
tickView.frame = CGRectMake(self.contentView.bounds.size.width - tickView.frame.size.width - 2 * PlainRoomCellLayoutConstants.readReceiptsViewRightMargin, CGRectGetMaxY(componentFrame) - tickView.frame.size.height, tickView.frame.size.width, tickView.frame.size.height);
|
||||
|
||||
[self.contentView addSubview:tickView];
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#import "AvatarGenerator.h"
|
||||
#import "MatrixKit.h"
|
||||
|
||||
#import "GeneratedInterface-Swift.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation MXRoom (Riot)
|
||||
@@ -331,30 +331,10 @@
|
||||
{
|
||||
[self.mxSession.crypto trustLevelSummaryForUserIds:@[userId] forceDownload:NO success:^(MXUsersTrustLevelSummary *usersTrustLevelSummary) {
|
||||
|
||||
UserEncryptionTrustLevel userEncryptionTrustLevel;
|
||||
double trustedDevicesPercentage = usersTrustLevelSummary.trustedDevicesProgress.fractionCompleted;
|
||||
|
||||
if (trustedDevicesPercentage >= 1.0)
|
||||
{
|
||||
userEncryptionTrustLevel = UserEncryptionTrustLevelTrusted;
|
||||
}
|
||||
else if (trustedDevicesPercentage == 0.0)
|
||||
{
|
||||
// Verify if the user has the user has cross-signing enabled
|
||||
if ([self.mxSession.crypto.crossSigning crossSigningKeysForUser:userId])
|
||||
{
|
||||
userEncryptionTrustLevel = UserEncryptionTrustLevelNotVerified;
|
||||
}
|
||||
else
|
||||
{
|
||||
userEncryptionTrustLevel = UserEncryptionTrustLevelNoCrossSigning;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
userEncryptionTrustLevel = UserEncryptionTrustLevelWarning;
|
||||
}
|
||||
|
||||
MXCrossSigningInfo *crossSigningInfo = [self.mxSession.crypto.crossSigning crossSigningKeysForUser:userId];
|
||||
EncryptionTrustLevel *encryption = [[EncryptionTrustLevel alloc] init];
|
||||
UserEncryptionTrustLevel userEncryptionTrustLevel = [encryption userTrustLevelWithCrossSigning:crossSigningInfo
|
||||
trustedDevicesProgress:usersTrustLevelSummary.trustedDevicesProgress];
|
||||
onComplete(userEncryptionTrustLevel);
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
@@ -15,17 +15,7 @@
|
||||
*/
|
||||
|
||||
#import "MatrixKit.h"
|
||||
|
||||
/**
|
||||
RoomEncryptionTrustLevel represents the trust level in an encrypted room.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, RoomEncryptionTrustLevel) {
|
||||
RoomEncryptionTrustLevelTrusted,
|
||||
RoomEncryptionTrustLevelWarning,
|
||||
RoomEncryptionTrustLevelNormal,
|
||||
RoomEncryptionTrustLevelUnknown
|
||||
};
|
||||
|
||||
#import "RoomEncryptionTrustLevel.h"
|
||||
|
||||
/**
|
||||
Define a `MXRoomSummary` category at Riot level.
|
||||
|
||||
@@ -33,32 +33,15 @@
|
||||
|
||||
- (RoomEncryptionTrustLevel)roomEncryptionTrustLevel
|
||||
{
|
||||
RoomEncryptionTrustLevel roomEncryptionTrustLevel = RoomEncryptionTrustLevelUnknown;
|
||||
if (self.trust)
|
||||
MXUsersTrustLevelSummary *trust = self.trust;
|
||||
if (!trust)
|
||||
{
|
||||
double trustedUsersPercentage = self.trust.trustedUsersProgress.fractionCompleted;
|
||||
double trustedDevicesPercentage = self.trust.trustedDevicesProgress.fractionCompleted;
|
||||
|
||||
if (trustedUsersPercentage >= 1.0)
|
||||
{
|
||||
if (trustedDevicesPercentage >= 1.0)
|
||||
{
|
||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevelTrusted;
|
||||
}
|
||||
else
|
||||
{
|
||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevelWarning;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevelNormal;
|
||||
}
|
||||
|
||||
roomEncryptionTrustLevel = roomEncryptionTrustLevel;
|
||||
MXLogError(@"[MXRoomSummary] roomEncryptionTrustLevel: trust is missing");
|
||||
return RoomEncryptionTrustLevelUnknown;
|
||||
}
|
||||
|
||||
return roomEncryptionTrustLevel;
|
||||
EncryptionTrustLevel *encryption = [[EncryptionTrustLevel alloc] init];
|
||||
return [encryption roomTrustLevelWithSummary:trust];
|
||||
}
|
||||
|
||||
- (BOOL)isJoined
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Custom NSAttributedString.Key to specify the theme
|
||||
let themeIdentifierAttributeName = NSAttributedString.Key("ThemeIdentifier")
|
||||
/// Custom NSAttributedString.Key to specify a theme color by its name
|
||||
let themeColorNameAttributeName = NSAttributedString.Key("ThemeColorName")
|
||||
|
||||
extension NSAttributedString {
|
||||
/// Fix foreground color attributes if this attributed string contains the `themeIdentifierAttributeName` and `foregroundColorNameAttributeName` attributes
|
||||
/// - Returns: a new attributed string with updated colors
|
||||
@objc func fixForegroundColor() -> NSAttributedString {
|
||||
let activeTheme = ThemeService.shared().theme
|
||||
|
||||
// Check if a theme is defined for this attributed string
|
||||
var needUpdate = false
|
||||
self.vc_enumerateAttribute(themeIdentifierAttributeName) { (themeIdentifier: String, range: NSRange, _) in
|
||||
needUpdate = themeIdentifier != activeTheme.identifier
|
||||
}
|
||||
|
||||
guard needUpdate else {
|
||||
return self
|
||||
}
|
||||
|
||||
// Build a new attributedString with the proper colors if possible
|
||||
let mutableAttributedString = NSMutableAttributedString(attributedString: self)
|
||||
mutableAttributedString.vc_enumerateAttribute(themeColorNameAttributeName) { (colorName: String, range: NSRange, _) in
|
||||
if let color = ThemeColorResolver.getColorByName(colorName) {
|
||||
mutableAttributedString.addAttribute(.foregroundColor, value: color, range: range)
|
||||
}
|
||||
}
|
||||
return mutableAttributedString
|
||||
}
|
||||
}
|
||||
|
||||
extension NSMutableAttributedString {
|
||||
/// Adds a theme color name attribute
|
||||
/// - Parameters:
|
||||
/// - colorName: color name
|
||||
/// - range:range for this attribute
|
||||
@objc func addThemeColorNameAttribute(_ colorName: String, range: NSRange) {
|
||||
self.addAttribute(themeColorNameAttributeName, value: colorName, range: range)
|
||||
}
|
||||
|
||||
/// Adds a theme identifier attribute
|
||||
@objc func addThemeIdentifierAttribute() {
|
||||
self.addAttribute(themeIdentifierAttributeName, value: ThemeService.shared().theme.identifier, range: .init(location: 0, length: length))
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ import MatrixSDKCrypto
|
||||
|
||||
init(
|
||||
remoteFeature: RemoteFeaturesClientProtocol = PostHogAnalyticsClient.shared,
|
||||
localTargetPercentage: Double = 0.5
|
||||
localTargetPercentage: Double = 1
|
||||
) {
|
||||
var targetPercentage = 0.0
|
||||
if BWIBuildSettings.shared.useRustEncryption {
|
||||
|
||||
@@ -99,6 +99,10 @@ public class BWIL10n: NSObject {
|
||||
public static var bumAutheticationTitle: String {
|
||||
return BWIL10n.tr("Bwi", "bum_authetication_title")
|
||||
}
|
||||
/// Barrierefreiheitserklärung
|
||||
public static var bwiAccessibilityDeclarationButtonTitle: String {
|
||||
return BWIL10n.tr("Bwi", "bwi_accessibility_declaration_button_title")
|
||||
}
|
||||
/// Wir brauchen Deine Hilfe, um Fehler im %@ besser analysieren zu können. Dazu würden wir gerne anonymisierte Diagnosedaten erfassen. Es werden keine Daten an Dritte übermittelt. Details findest Du in der Datenschutzerklärung.\n\nFalls Du nicht mehr mithelfen möchtest, kannst Du dies in den Einstellungen jederzeit wieder deaktivieren.\n\nMöchtest du bei der Fehler-Analyse unterstützen?
|
||||
public static func bwiAnalyticsAlertBody(_ p1: String) -> String {
|
||||
return BWIL10n.tr("Bwi", "bwi_analytics_alert_body", p1)
|
||||
@@ -207,7 +211,19 @@ public class BWIL10n: NSObject {
|
||||
public static func bwiErrorInviteGeneral(_ p1: String) -> String {
|
||||
return BWIL10n.tr("Bwi", "bwi_error_invite_general", p1)
|
||||
}
|
||||
/// Du kannst jetzt aktive und vergangene Umfragen gesammelt in den Raumdetails einsehen (erreichbar unter Raumdetails, im Bereich "Umfrageverlauf").
|
||||
/// Abmelden ist ohne Internetverbindung nicht möglich.
|
||||
public static var bwiErrorLogoutOffline: String {
|
||||
return BWIL10n.tr("Bwi", "bwi_error_logout_offline")
|
||||
}
|
||||
/// Der Raum wurde bereits geschlossen, daher kannst Du nicht mehr beitreten.
|
||||
public static var bwiErrorRoomNotAvailableMessage: String {
|
||||
return BWIL10n.tr("Bwi", "bwi_error_room_not_available_message")
|
||||
}
|
||||
/// Link ungültig
|
||||
public static var bwiErrorRoomNotAvailableTitle: String {
|
||||
return BWIL10n.tr("Bwi", "bwi_error_room_not_available_title")
|
||||
}
|
||||
/// Neue Umfragen können vom Ersteller so konfiguriert werden, dass angezeigt wird, wer für welche Option gestimmt hat.
|
||||
public static var bwiFeatureBannerAdvertisementText: String {
|
||||
return BWIL10n.tr("Bwi", "bwi_feature_banner_advertisement_text")
|
||||
}
|
||||
@@ -967,6 +983,10 @@ public class BWIL10n: NSObject {
|
||||
public static var pollEditFormCreatePoll: String {
|
||||
return BWIL10n.tr("Bwi", "poll_edit_form_create_poll")
|
||||
}
|
||||
/// Anzeigen, wer für welche Option gestimmt hat.
|
||||
public static var pollEditFormParticipantToggle: String {
|
||||
return BWIL10n.tr("Bwi", "poll_edit_form_participant_toggle")
|
||||
}
|
||||
/// Umfragetyp
|
||||
public static var pollEditFormPollType: String {
|
||||
return BWIL10n.tr("Bwi", "poll_edit_form_poll_type")
|
||||
@@ -979,6 +999,18 @@ public class BWIL10n: NSObject {
|
||||
public static var pollEditFormPollTypeOpen: String {
|
||||
return BWIL10n.tr("Bwi", "poll_edit_form_poll_type_open")
|
||||
}
|
||||
/// Alle ansehen (%lu weitere)
|
||||
public static func pollParticipantDetailsShowMore(_ p1: Int) -> String {
|
||||
return BWIL10n.tr("Bwi", "poll_participant_details_show_more", p1)
|
||||
}
|
||||
/// Umfragedetails
|
||||
public static var pollParticipantDetailsTitle: String {
|
||||
return BWIL10n.tr("Bwi", "poll_participant_details_title")
|
||||
}
|
||||
/// Stimmen anzeigen
|
||||
public static var pollTimelineShowParticipantsButton: String {
|
||||
return BWIL10n.tr("Bwi", "poll_timeline_show_participants_button")
|
||||
}
|
||||
/// Wiederholen
|
||||
public static var retry: String {
|
||||
return BWIL10n.tr("Bwi", "retry")
|
||||
@@ -1067,7 +1099,7 @@ public class BWIL10n: NSObject {
|
||||
public static var roomEventActionRemovePoll: String {
|
||||
return BWIL10n.tr("Bwi", "room_event_action_remove_poll")
|
||||
}
|
||||
/// Das ist der Anfang deiner Direktnachricht mit
|
||||
/// Dies ist der Beginn deiner Direktnachrichten mit
|
||||
public static var roomIntroCellInformationDmSentence1Part1: String {
|
||||
return BWIL10n.tr("Bwi", "room_intro_cell_information_dm_sentence1_part1")
|
||||
}
|
||||
@@ -1491,6 +1523,10 @@ public class BWIL10n: NSObject {
|
||||
public static var settingsGroupMessages: String {
|
||||
return BWIL10n.tr("Bwi", "settings_group_messages")
|
||||
}
|
||||
/// Impressum
|
||||
public static var settingsImprint: String {
|
||||
return BWIL10n.tr("Bwi", "settings_imprint")
|
||||
}
|
||||
/// Mentions and Keywords
|
||||
public static var settingsMentionsAndKeywords: String {
|
||||
return BWIL10n.tr("Bwi", "settings_mentions_and_keywords")
|
||||
@@ -1687,6 +1723,10 @@ public class BWIL10n: NSObject {
|
||||
public static var userSessionVerifiedSessionDescription: String {
|
||||
return BWIL10n.tr("Bwi", "user_session_verified_session_description")
|
||||
}
|
||||
/// Sitzung verifizieren
|
||||
public static var userVerificationSessionDetailsVerifyActionCurrentUser: String {
|
||||
return BWIL10n.tr("Bwi", "user_verification_session_details_verify_action_current_user")
|
||||
}
|
||||
/// Ansehen
|
||||
public static var view: String {
|
||||
return BWIL10n.tr("Bwi", "view")
|
||||
|
||||
@@ -3899,6 +3899,10 @@ public class VectorL10n: NSObject {
|
||||
public static func noticeDisplayNameChangedFromByYou(_ p1: String, _ p2: String) -> String {
|
||||
return VectorL10n.tr("Vector", "notice_display_name_changed_from_by_you", p1, p2)
|
||||
}
|
||||
/// %@ changed their display name to %@
|
||||
public static func noticeDisplayNameChangedTo(_ p1: String, _ p2: String) -> String {
|
||||
return VectorL10n.tr("Vector", "notice_display_name_changed_to", p1, p2)
|
||||
}
|
||||
/// %@ removed their display name
|
||||
public static func noticeDisplayNameRemoved(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "notice_display_name_removed", p1)
|
||||
@@ -4923,6 +4927,10 @@ public class VectorL10n: NSObject {
|
||||
public static var pollTimelineEndedText: String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_ended_text")
|
||||
}
|
||||
/// Loading...
|
||||
public static var pollTimelineLoading: String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_loading")
|
||||
}
|
||||
/// Please try again
|
||||
public static var pollTimelineNotClosedSubtitle: String {
|
||||
return VectorL10n.tr("Vector", "poll_timeline_not_closed_subtitle")
|
||||
@@ -5211,6 +5219,58 @@ public class VectorL10n: NSObject {
|
||||
public static var roomAvatarViewAccessibilityLabel: String {
|
||||
return VectorL10n.tr("Vector", "room_avatar_view_accessibility_label")
|
||||
}
|
||||
/// Bans user with given id
|
||||
public static var roomCommandBanUserDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_ban_user_description")
|
||||
}
|
||||
/// Changes your display nickname
|
||||
public static var roomCommandChangeDisplayNameDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_change_display_name_description")
|
||||
}
|
||||
/// Sets the room topic
|
||||
public static var roomCommandChangeRoomTopicDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_change_room_topic_description")
|
||||
}
|
||||
/// Forces the current outbound group session in an encrypted room to be discarded
|
||||
public static var roomCommandDiscardSessionDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_discard_session_description")
|
||||
}
|
||||
/// Displays action
|
||||
public static var roomCommandEmoteDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_emote_description")
|
||||
}
|
||||
/// Invalid or unhandled command
|
||||
public static var roomCommandErrorUnknownCommand: String {
|
||||
return VectorL10n.tr("Vector", "room_command_error_unknown_command")
|
||||
}
|
||||
/// Invites user with given id to current room
|
||||
public static var roomCommandInviteUserDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_invite_user_description")
|
||||
}
|
||||
/// Joins room with given address
|
||||
public static var roomCommandJoinRoomDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_join_room_description")
|
||||
}
|
||||
/// Removes user with given id from this room
|
||||
public static var roomCommandKickUserDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_kick_user_description")
|
||||
}
|
||||
/// Leave room
|
||||
public static var roomCommandPartRoomDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_part_room_description")
|
||||
}
|
||||
/// Deops user with given id
|
||||
public static var roomCommandResetUserPowerLevelDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_reset_user_power_level_description")
|
||||
}
|
||||
/// Define the power level of a user
|
||||
public static var roomCommandSetUserPowerLevelDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_set_user_power_level_description")
|
||||
}
|
||||
/// Unbans user with given id
|
||||
public static var roomCommandUnbanUserDescription: String {
|
||||
return VectorL10n.tr("Vector", "room_command_unban_user_description")
|
||||
}
|
||||
/// You need permission to manage conference call in this room
|
||||
public static var roomConferenceCallNoPower: String {
|
||||
return VectorL10n.tr("Vector", "room_conference_call_no_power")
|
||||
|
||||
@@ -28,7 +28,7 @@ enum ThemeIdentifier: String, RawRepresentable {
|
||||
case "dark":
|
||||
self = .dark
|
||||
case "black":
|
||||
self = .black
|
||||
self = .dark // bwi: 4744 (map previous set black theme to dark)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan
|
||||
}
|
||||
else if ([themeId isEqualToString:@"black"])
|
||||
{
|
||||
theme = [BlackTheme new];
|
||||
theme = [DarkTheme new]; // bwi: 4744 (map previous set black theme to dark)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -23,5 +23,5 @@ extension ThemeService {
|
||||
return nil
|
||||
}
|
||||
return ThemeIdentifier(rawValue: themeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,6 +401,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
}
|
||||
[NSBundle mxk_setLanguage:language];
|
||||
[NSBundle mxk_setFallbackLanguage:@"en"];
|
||||
UIApplication.sharedApplication.accessibilityLanguage = language;
|
||||
|
||||
if (BuildSettings.disableRightToLeftLayout)
|
||||
{
|
||||
@@ -796,7 +797,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
[application keyWindow].accessibilityIgnoresInvertColors = YES;
|
||||
|
||||
[BWIAnalytics.sharedTracker firstCall];
|
||||
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"PinLogin"];
|
||||
[BWIAnalytics.sharedTracker trackEventWithCategory:@"Session" action:@"PinLogin" name:@"pin_login_default" number:nil];
|
||||
|
||||
|
||||
self.isPinUnlocked = true;
|
||||
@@ -1677,7 +1678,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
[self peekInRoomWithNavigationParameters:roomPreviewNavigationParameters pathParams:pathParams];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
[self peekInRoomWithNavigationParameters:roomPreviewNavigationParameters pathParams:pathParams];
|
||||
[self peekInRoomWithNavigationParameters:roomPreviewNavigationParameters pathParams:pathParams];
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -2259,7 +2260,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
[topVC startActivityIndicator];
|
||||
}
|
||||
|
||||
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"Logout"];
|
||||
[BWIAnalytics.sharedTracker trackEventWithCategory:@"Session" action:@"Logout" name:@"logout_default" number:nil];
|
||||
[BWIAnalytics.sharedTracker dispatchAll];
|
||||
|
||||
[self logoutSendingRequestServer:YES completion:^(BOOL isLoggedOut) {
|
||||
@@ -2271,6 +2272,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
[BWIBuildSettings.shared reset];
|
||||
[BWIAnalytics.sharedTracker resetUserdefaults];
|
||||
|
||||
// bwi #4573 reset chatsfilter on logout
|
||||
[AllChatsLayoutSettingsManager.shared reset];
|
||||
}
|
||||
completion (YES);
|
||||
}
|
||||
@@ -2340,7 +2343,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
[topVC startActivityIndicator];
|
||||
}
|
||||
|
||||
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"Logout"];
|
||||
[BWIAnalytics.sharedTracker trackEventWithCategory:@"Session" action:@"Logout" name:@"logout_default" number:nil];
|
||||
[BWIAnalytics.sharedTracker dispatchAll];
|
||||
|
||||
[self logoutSendingRequestServer:YES completion:^(BOOL isLoggedOut) {
|
||||
@@ -2586,6 +2589,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
{
|
||||
MXLogDebug(@"[AppDelegate] showLaunchAnimation");
|
||||
|
||||
/* bwi: 4782 removed by nv
|
||||
UIView *launchLoadingView;
|
||||
if (MXSDKOptions.sharedInstance.enableStartupProgress)
|
||||
{
|
||||
@@ -2593,15 +2597,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
{
|
||||
launchLoadingView = [BUMLaunchLoadingViewController makeView];
|
||||
} else {
|
||||
if (MXSDKOptions.sharedInstance.enableStartupProgress)
|
||||
{
|
||||
MXSession *mainSession = self.mxSessions.firstObject;
|
||||
launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:mainSession.startupProgress];
|
||||
}
|
||||
else
|
||||
{
|
||||
launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:nil];
|
||||
}
|
||||
MXSession *mainSession = self.mxSessions.firstObject;
|
||||
launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:mainSession.startupProgress];
|
||||
[(LaunchLoadingView *) launchLoadingView updateWithTheme:ThemeService.shared.theme];
|
||||
}
|
||||
|
||||
@@ -2610,9 +2607,21 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
|
||||
[window addSubview:launchLoadingView];
|
||||
}
|
||||
|
||||
launchAnimationContainerView = launchLoadingView;
|
||||
*/
|
||||
|
||||
/* bwi: 4782 - new code from nv
|
||||
MXSession *mainSession = self.mxSessions.firstObject;
|
||||
LaunchLoadingView *launchLoadingView = [LaunchLoadingView instantiateWithStartupProgress:mainSession.startupProgress];
|
||||
|
||||
launchLoadingView.frame = window.bounds;
|
||||
[launchLoadingView updateWithTheme:ThemeService.shared.theme];
|
||||
launchLoadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
|
||||
[window addSubview:launchLoadingView];
|
||||
|
||||
|
||||
launchAnimationContainerView = launchLoadingView;
|
||||
*/
|
||||
[MXSDKOptions.sharedInstance.profiler startMeasuringTaskWithName:MXTaskProfileNameStartupLaunchScreen];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,8 +635,7 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
|
||||
loadingViewController.modalPresentationStyle = .fullScreen
|
||||
navigationRouter.setRootModule(loadingViewController)
|
||||
} else {
|
||||
let startupProgress: MXSessionStartupProgress? = MXSDKOptions.sharedInstance().enableStartupProgress ? session?.startupProgress : nil
|
||||
let loadingViewController = LaunchLoadingViewController(startupProgress: startupProgress)
|
||||
let loadingViewController = LaunchLoadingViewController(startupProgress: session?.startupProgress)
|
||||
loadingViewController.modalPresentationStyle = .fullScreen
|
||||
|
||||
// Replace the navigation stack with the loading animation
|
||||
|
||||
@@ -1320,7 +1320,14 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0;
|
||||
[self saveCustomServerInputs];
|
||||
|
||||
// Restore default configuration
|
||||
[self setHomeServerTextFieldText:self.defaultHomeServerUrl];
|
||||
if (BuildSettings.forceHomeserverSelection)
|
||||
{
|
||||
[self setHomeServerTextFieldText:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setHomeServerTextFieldText:self.defaultHomeServerUrl];
|
||||
}
|
||||
[self setIdentityServerTextFieldText:self.defaultIdentityServerUrl];
|
||||
|
||||
[self.customServersTickButton setImage:AssetImages.selectionUntick.image forState:UIControlStateNormal];
|
||||
|
||||
@@ -121,8 +121,7 @@ final class LegacyAuthenticationCoordinator: NSObject, AuthenticationCoordinator
|
||||
loadingViewController.modalPresentationStyle = .fullScreen
|
||||
navigationRouter.setRootModule(loadingViewController)
|
||||
} else {
|
||||
let startupProgress: MXSessionStartupProgress? = MXSDKOptions.sharedInstance().enableStartupProgress ? session?.startupProgress : nil
|
||||
let loadingViewController = LaunchLoadingViewController(startupProgress: startupProgress)
|
||||
let loadingViewController = LaunchLoadingViewController(startupProgress: session?.startupProgress)
|
||||
loadingViewController.modalPresentationStyle = .fullScreen
|
||||
|
||||
// Replace the navigation stack with the loading animation
|
||||
|
||||
@@ -103,6 +103,7 @@ class AvatarView: UIView, Themable {
|
||||
|
||||
func updateAvatarImageView(with viewData: AvatarViewDataProtocol) {
|
||||
guard let avatarImageView = self.avatarImageView else {
|
||||
MXLog.warning("[AvatarView] avatar not updated because avatarImageView is nil.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,6 +121,10 @@ class AvatarView: UIView, Themable {
|
||||
let (defaultAvatarImage, defaultAvatarImageContentMode) = viewData.fallbackImageParameters() ?? (nil, .scaleAspectFill)
|
||||
updateAvatarImageView(image: defaultAvatarImage, contentMode: defaultAvatarImageContentMode)
|
||||
|
||||
if defaultAvatarImage == nil {
|
||||
MXLog.warning("[AvatarView] defaultAvatarImage is nil")
|
||||
}
|
||||
|
||||
if let avatarUrl = viewData.avatarUrl {
|
||||
avatarImageView.setImageURI(avatarUrl,
|
||||
withType: nil,
|
||||
@@ -129,6 +134,10 @@ class AvatarView: UIView, Themable {
|
||||
previewImage: defaultAvatarImage,
|
||||
mediaManager: viewData.mediaManager)
|
||||
updateAvatarContentMode(contentMode: .scaleAspectFill)
|
||||
|
||||
if avatarImageView.frame.size.width < 8 || avatarImageView.frame.size.height < 8 {
|
||||
MXLog.warning("[AvatarView] small avatarImageView frame: \(avatarImageView.frame)")
|
||||
}
|
||||
} else {
|
||||
updateAvatarImageView(image: defaultAvatarImage, contentMode: defaultAvatarImageContentMode)
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@
|
||||
// Manage lastEventAttributedTextMessage optional property
|
||||
if (!roomCellData.roomSummary.spaceChildInfo && [roomCellData respondsToSelector:@selector(lastEventAttributedTextMessage)])
|
||||
{
|
||||
self.lastEventDescription.attributedText = roomCellData.lastEventAttributedTextMessage;
|
||||
// Attempt to correct the attributed string colors to match the current theme
|
||||
self.lastEventDescription.attributedText = [roomCellData.lastEventAttributedTextMessage fixForegroundColor];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ class RecentsInvitesTableViewCell: UITableViewCell, NibReusable, Themable {
|
||||
badgeLabel.textColor = theme.colors.background
|
||||
badgeLabel.font = theme.fonts.footnoteSB
|
||||
|
||||
titleLabel.textColor = theme.colors.accent
|
||||
titleLabel.textColor = BWIBuildSettings.shared.useNewBumColors ? theme.tintColor : theme.colors.accent // bwi: 4769
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@@ -47,7 +47,7 @@ class AllChatsFilterOptionListView: UIView, Themable {
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
|
||||
private let backgroundView = UIView() // bwi: 4769
|
||||
private let separator = UIView()
|
||||
private let tabListView = TabListView()
|
||||
|
||||
@@ -90,6 +90,10 @@ class AllChatsFilterOptionListView: UIView, Themable {
|
||||
// MARK: - Themable
|
||||
|
||||
func update(theme: Theme) {
|
||||
|
||||
// bwi: 4769
|
||||
backgroundView.backgroundColor = ThemeService.shared().theme.backgroundColor
|
||||
|
||||
backgroundColor = theme.colors.background.withAlphaComponent(0.7)
|
||||
|
||||
tabListView.itemFont = theme.fonts.calloutSB
|
||||
@@ -102,6 +106,9 @@ class AllChatsFilterOptionListView: UIView, Themable {
|
||||
// MARK: - Private
|
||||
|
||||
private func setupView() {
|
||||
|
||||
// bwi: 4769
|
||||
backgroundView.backgroundColor = ThemeService.shared().theme.backgroundColor
|
||||
vc_addSubViewMatchingParent(backgroundView)
|
||||
|
||||
addSubview(separator)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Object responsible for calculating user and room trust level
|
||||
///
|
||||
/// For legacy reasons, the trust of multiple items is represented as `Progress` object,
|
||||
/// where `completedUnitCount` represents the number of trusted users / devices.
|
||||
@objc class EncryptionTrustLevel: NSObject {
|
||||
struct TrustSummary {
|
||||
let totalCount: Int64
|
||||
let trustedCount: Int64
|
||||
let areAllTrusted: Bool
|
||||
|
||||
init(progress: Progress) {
|
||||
totalCount = max(progress.totalUnitCount, progress.completedUnitCount)
|
||||
trustedCount = progress.completedUnitCount
|
||||
areAllTrusted = trustedCount == totalCount
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Calculate trust level for a single user given their cross-signing info
|
||||
@objc func userTrustLevel(
|
||||
crossSigning: MXCrossSigningInfo?,
|
||||
trustedDevicesProgress: Progress
|
||||
) -> UserEncryptionTrustLevel {
|
||||
let devices = TrustSummary(progress: trustedDevicesProgress)
|
||||
|
||||
// If we could cross-sign but we haven't, the user is simply not verified
|
||||
if let crossSigning, !crossSigning.trustLevel.isVerified {
|
||||
return .notVerified
|
||||
|
||||
// If we cannot cross-sign the user (legacy behaviour) and have not signed
|
||||
// any devices manually, the user is not verified
|
||||
} else if crossSigning == nil && devices.trustedCount == 0 {
|
||||
return .notVerified
|
||||
}
|
||||
|
||||
// In all other cases we check devices for trust level
|
||||
return devices.areAllTrusted ? .trusted : .warning
|
||||
}
|
||||
|
||||
/// Calculate trust level for a room given trust level of users and their devices
|
||||
@objc func roomTrustLevel(summary: MXUsersTrustLevelSummary) -> RoomEncryptionTrustLevel {
|
||||
let users = TrustSummary(progress: summary.trustedUsersProgress)
|
||||
let devices = TrustSummary(progress: summary.trustedDevicesProgress)
|
||||
|
||||
guard users.totalCount > 0 && users.areAllTrusted else {
|
||||
return .normal
|
||||
}
|
||||
return devices.areAllTrusted ? .trusted : .warning
|
||||
}
|
||||
}
|
||||
+11
-7
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -14,8 +14,12 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol UserSuggestionViewModelProtocol {
|
||||
var completion: ((UserSuggestionViewModelResult) -> Void)? { get set }
|
||||
}
|
||||
/**
|
||||
RoomEncryptionTrustLevel represents the trust level in an encrypted room.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, RoomEncryptionTrustLevel) {
|
||||
RoomEncryptionTrustLevelTrusted,
|
||||
RoomEncryptionTrustLevelWarning,
|
||||
RoomEncryptionTrustLevelNormal,
|
||||
RoomEncryptionTrustLevelUnknown
|
||||
};
|
||||
@@ -422,7 +422,11 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func updateAvatarButtonItem() {
|
||||
MXLog.info("[AllChatsCoordinator] updating avatar button item.")
|
||||
if let avatar = userAvatarViewData(from: currentMatrixSession) {
|
||||
if avatarMenuView == nil {
|
||||
MXLog.warning("[AllChatsCoordinator] updateAvatarButtonItem: avatarMenuView is nil.")
|
||||
}
|
||||
avatarMenuView?.fill(with: avatar)
|
||||
avatarMenuButton?.setImage(nil, for: .normal)
|
||||
} else {
|
||||
|
||||
@@ -51,6 +51,11 @@ final class AllChatsLayoutSettingsManager: NSObject {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
// bwi #4573 reset filters for logout
|
||||
@objc func reset() {
|
||||
activeFilters = .all
|
||||
}
|
||||
|
||||
var activeFilters: AllChatsLayoutFilterType {
|
||||
get {
|
||||
guard let value = RiotSettings.defaults.object(forKey: Constants.activeFiltersKey) as? NSNumber else {
|
||||
|
||||
@@ -137,7 +137,13 @@ class AllChatsViewController: HomeViewController {
|
||||
emptyViewBottomAnchor = toolbar.topAnchor
|
||||
|
||||
// bwi: 4179
|
||||
toolbar.tintColor = ThemeService.shared().theme.tintColor
|
||||
|
||||
if BWIBuildSettings.shared.useNewBumColors { // bwi: #4883
|
||||
toolbar.tintColor = ThemeService.shared().theme.tintColor
|
||||
toolbar.barTintColor = ThemeService.shared().theme.backgroundColor
|
||||
} else {
|
||||
toolbar.tintColor = theme.colors.accent
|
||||
}
|
||||
|
||||
updateUI()
|
||||
|
||||
@@ -150,12 +156,22 @@ class AllChatsViewController: HomeViewController {
|
||||
|
||||
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)
|
||||
|
||||
// bwi: 4769
|
||||
self.registerThemeServiceDidChangeThemeNotification()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
self.toolbar.tintColor = theme.colors.accent
|
||||
// bwi: 4769
|
||||
if BWIBuildSettings.shared.useNewBumColors {
|
||||
self.toolbar.tintColor = theme.tintColor
|
||||
self.toolbar.barTintColor = theme.backgroundColor
|
||||
} else {
|
||||
self.toolbar.tintColor = theme.colors.accent
|
||||
}
|
||||
|
||||
if self.navigationItem.searchController == nil {
|
||||
self.navigationItem.searchController = searchController
|
||||
}
|
||||
@@ -205,6 +221,17 @@ class AllChatsViewController: HomeViewController {
|
||||
}
|
||||
}
|
||||
|
||||
// bwi: 4769
|
||||
private func registerThemeServiceDidChangeThemeNotification() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
|
||||
}
|
||||
|
||||
// bwi: 4769
|
||||
@objc private func themeDidChange() {
|
||||
self.update(with: ThemeService.shared().theme)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func switchSpace(withId spaceId: String?) {
|
||||
@@ -316,15 +343,10 @@ class AllChatsViewController: HomeViewController {
|
||||
alert.addAction(UIAlertAction(title: BWIL10n.bwiAnalyticsAlertInfoButton,
|
||||
style: .default,
|
||||
handler: { [self] action in
|
||||
if let webViewController = WebViewViewController(url: BWIBuildSettings.shared.applicationPrivacyPolicyWithMatomoSectionUrlString) {
|
||||
navigationBar = UINavigationController(rootViewController: webViewController)
|
||||
webViewController.navigationItem.setLeftBarButton(UIBarButtonItem(title: VectorL10n.close, style: .plain, target: self, action: #selector(self.bwiCloseModal)), animated: false)
|
||||
webViewController.title = VectorL10n.settingsPrivacyPolicy
|
||||
navigationBar?.presentationController?.delegate = self
|
||||
if let url = URL(string: BWIBuildSettings.shared.applicationPrivacyPolicyWithMatomoSectionUrlString) {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
showMatomoConsentAlertOnCloseModal = true
|
||||
present(navigationBar ?? webViewController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}))
|
||||
|
||||
alert.addAction(UIAlertAction(title: BWIL10n.bwiAnalyticsAlertCancelButton,
|
||||
@@ -544,7 +566,16 @@ class AllChatsViewController: HomeViewController {
|
||||
}
|
||||
|
||||
private func update(with theme: Theme) {
|
||||
self.navigationController?.toolbar?.tintColor = theme.colors.accent
|
||||
// bwi: 4769
|
||||
if BWIBuildSettings.shared.useNewBumColors {
|
||||
toolbar.tintColor = ThemeService.shared().theme.tintColor
|
||||
toolbar.barTintColor = ThemeService.shared().theme.backgroundColor
|
||||
|
||||
UIToolbar.appearance().tintColor = ThemeService.shared().theme.tintColor
|
||||
UIToolbar.appearance().barTintColor = ThemeService.shared().theme.backgroundColor
|
||||
} else {
|
||||
self.navigationController?.toolbar?.tintColor = theme.colors.accent
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -628,8 +659,8 @@ class AllChatsViewController: HomeViewController {
|
||||
|
||||
// bwi: 4179
|
||||
var allChatsEditButton = UIBarButtonItem(image: Asset.Images.allChatsEditIcon.image, menu: menu)
|
||||
allChatsEditButton.tintColor = ThemeService.shared().theme.tintColor
|
||||
|
||||
allChatsEditButton.tintColor = ThemeService.shared().theme.tintColor // bwi: #4883
|
||||
|
||||
if BWIBuildSettings.shared.enableSpaces {
|
||||
self.toolbar.items = [
|
||||
spacesButton,
|
||||
|
||||
@@ -137,7 +137,7 @@ final class KeyVerificationCoordinator: KeyVerificationCoordinatorType {
|
||||
case .incomingSASTransaction(let incomingSASTransaction):
|
||||
rootCoordinator = self.createDataLoadingScreenCoordinator(otherUserId: incomingSASTransaction.otherUserId, otherDeviceId: incomingSASTransaction.otherDeviceId)
|
||||
case .completeSecurity(let isNewSignIn):
|
||||
if BWIBuildSettings.shared.disableSelfUserVerification {
|
||||
if BWIBuildSettings.shared.disableCrosssigning {
|
||||
let coordinator = self.createSecretsRecoveryCoordinator(with: .passphraseOrKey)
|
||||
rootCoordinator = coordinator
|
||||
} else {
|
||||
|
||||
+5
@@ -24,4 +24,9 @@ class VerifyEmojiCollectionViewCell: UICollectionViewCell, Reusable, Themable {
|
||||
func update(theme: Theme) {
|
||||
name.textColor = theme.textPrimaryColor
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
emoji.isAccessibilityElement = false
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ final class UserVerificationSessionStatusViewController: UIViewController {
|
||||
|
||||
if viewData.isCurrentUser {
|
||||
unstrustedInformationText = VectorL10n.userVerificationSessionDetailsAdditionalInformationUntrustedCurrentUser
|
||||
verifyButtonTitle = VectorL10n.userVerificationSessionDetailsVerifyActionCurrentUser
|
||||
verifyButtonTitle = BWIL10n.userVerificationSessionDetailsVerifyActionCurrentUser
|
||||
} else {
|
||||
unstrustedInformationText = VectorL10n.userVerificationSessionDetailsAdditionalInformationUntrustedOtherUser
|
||||
verifyButtonTitle = VectorL10n.userVerificationSessionDetailsVerifyActionOtherUser
|
||||
|
||||
Binary file not shown.
@@ -350,4 +350,18 @@ NSString *const kMXKWebViewViewControllerJavaScriptEnableLog =
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - BWI: WebViewLinkPolicy
|
||||
-(void)webView:(WKWebView *)webview decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler
|
||||
{
|
||||
if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
|
||||
// bwi: clicked links should be opened in system browser
|
||||
[[UIApplication sharedApplication] openURL:navigationAction.request.URL options:@{} completionHandler:nil];
|
||||
decisionHandler(WKNavigationActionPolicyCancel);
|
||||
} else {
|
||||
// bwi: Open url in webview
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,3 +17,4 @@
|
||||
#import "MXKRoomBubbleCellData.h"
|
||||
#import "UserIndicatorCancel.h"
|
||||
#import "VoiceBroadcastInfo.h"
|
||||
#import "MXKSoundPlayer.h"
|
||||
|
||||
@@ -145,5 +145,3 @@
|
||||
|
||||
#import "MXKCountryPickerViewController.h"
|
||||
#import "MXKLanguagePickerViewController.h"
|
||||
|
||||
#import "MXKSlashCommands.h"
|
||||
|
||||
@@ -144,6 +144,15 @@
|
||||
*/
|
||||
- (CGFloat)rawTextHeight:(NSAttributedString*)attributedText;
|
||||
|
||||
/**
|
||||
Return the raw height of the provided text by removing any vertical margin/inset and constraining the width.
|
||||
|
||||
@param attributedText the attributed text to measure
|
||||
@param maxTextViewWidth the maximum text width
|
||||
@return the computed height
|
||||
*/
|
||||
- (CGFloat)rawTextHeight:(NSAttributedString*)attributedText withMaxWidth:(CGFloat)maxTextViewWidth;
|
||||
|
||||
/**
|
||||
Return the content size of a text view initialized with the provided attributed text.
|
||||
CAUTION: This method runs only on main thread.
|
||||
|
||||
@@ -500,23 +500,34 @@
|
||||
|
||||
// Return the raw height of the provided text by removing any margin
|
||||
- (CGFloat)rawTextHeight: (NSAttributedString*)attributedText
|
||||
{
|
||||
return [self rawTextHeight:attributedText withMaxWidth:_maxTextViewWidth];
|
||||
}
|
||||
|
||||
// Return the raw height of the provided text by removing any vertical margin/inset and constraining the width.
|
||||
- (CGFloat)rawTextHeight: (NSAttributedString*)attributedText withMaxWidth:(CGFloat)maxTextViewWidth
|
||||
{
|
||||
__block CGSize textSize;
|
||||
if ([NSThread currentThread] != [NSThread mainThread])
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
textSize = [self textContentSize:attributedText removeVerticalInset:YES];
|
||||
textSize = [self textContentSize:attributedText removeVerticalInset:YES maxTextViewWidth:maxTextViewWidth];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
textSize = [self textContentSize:attributedText removeVerticalInset:YES];
|
||||
textSize = [self textContentSize:attributedText removeVerticalInset:YES maxTextViewWidth:maxTextViewWidth];
|
||||
}
|
||||
|
||||
return textSize.height;
|
||||
}
|
||||
|
||||
- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset
|
||||
{
|
||||
return [self textContentSize:attributedText removeVerticalInset:removeVerticalInset maxTextViewWidth:_maxTextViewWidth];
|
||||
}
|
||||
|
||||
- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset maxTextViewWidth:(CGFloat)maxTextViewWidth
|
||||
{
|
||||
static UITextView* measurementTextView = nil;
|
||||
static UITextView* measurementTextViewWithoutInset = nil;
|
||||
@@ -535,7 +546,7 @@
|
||||
// Select the right text view for measurement
|
||||
UITextView *selectedTextView = (removeVerticalInset ? measurementTextViewWithoutInset : measurementTextView);
|
||||
|
||||
selectedTextView.frame = CGRectMake(0, 0, _maxTextViewWidth, 0);
|
||||
selectedTextView.frame = CGRectMake(0, 0, maxTextViewWidth, 0);
|
||||
selectedTextView.attributedText = attributedText;
|
||||
|
||||
// Force the layout manager to layout the text, fixes problems starting iOS 16
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
|
||||
#import "MXKAppSettings.h"
|
||||
|
||||
#import "MXKSlashCommands.h"
|
||||
|
||||
#import "GeneratedInterface-Swift.h"
|
||||
|
||||
const BOOL USE_THREAD_TIMELINE = YES;
|
||||
@@ -316,7 +314,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
_filterMessagesWithURL = NO;
|
||||
|
||||
emoteMessageSlashCommandPrefix = [NSString stringWithFormat:@"%@ ", kMXKSlashCmdEmote];
|
||||
emoteMessageSlashCommandPrefix = [NSString stringWithFormat:@"%@ ", [MXKSlashCommandsHelper commandNameFor:MXKSlashCommandEmote]];
|
||||
|
||||
// Set default data and view classes
|
||||
// Cell data
|
||||
@@ -458,11 +456,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[self resetNotifying:YES];
|
||||
}
|
||||
|
||||
- (void)resetNotifying:(BOOL)notify
|
||||
{
|
||||
if (roomDidFlushDataNotificationObserver)
|
||||
{
|
||||
@@ -558,12 +551,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
|
||||
_serverSyncEventCount = 0;
|
||||
|
||||
// Notify the delegate to reload its tableview
|
||||
if (notify && self.delegate)
|
||||
{
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reload
|
||||
@@ -577,10 +564,16 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
[self setState:MXKDataSourceStatePreparing];
|
||||
|
||||
[self resetNotifying:notify];
|
||||
[self reset];
|
||||
|
||||
// Reload
|
||||
[self didMXSessionStateChange];
|
||||
|
||||
// Notify the delegate to refresh the tableview
|
||||
if (notify && self.delegate)
|
||||
{
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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;
|
||||
|
||||
/**
|
||||
Slash commands used to perform actions from a room.
|
||||
*/
|
||||
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdChangeDisplayName;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdEmote;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdJoinRoom;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdPartRoom;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdInviteUser;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdKickUser;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdBanUser;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdUnbanUser;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdSetUserPowerLevel;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdResetUserPowerLevel;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdChangeRoomTopic;
|
||||
FOUNDATION_EXPORT NSString *const kMXKSlashCmdDiscardSession;
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 "MXKSlashCommands.h"
|
||||
|
||||
NSString *const kMXKSlashCmdChangeDisplayName = @"/nick";
|
||||
NSString *const kMXKSlashCmdEmote = @"/me";
|
||||
NSString *const kMXKSlashCmdJoinRoom = @"/join";
|
||||
NSString *const kMXKSlashCmdPartRoom = @"/part";
|
||||
NSString *const kMXKSlashCmdInviteUser = @"/invite";
|
||||
NSString *const kMXKSlashCmdKickUser = @"/kick";
|
||||
NSString *const kMXKSlashCmdBanUser = @"/ban";
|
||||
NSString *const kMXKSlashCmdUnbanUser = @"/unban";
|
||||
NSString *const kMXKSlashCmdSetUserPowerLevel = @"/op";
|
||||
NSString *const kMXKSlashCmdResetUserPowerLevel = @"/deop";
|
||||
NSString *const kMXKSlashCmdChangeRoomTopic = @"/topic";
|
||||
NSString *const kMXKSlashCmdDiscardSession = @"/discardsession";
|
||||
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
@objc final class MXKSlashCommandsHelper: NSObject {
|
||||
@objc static func commandNameFor(_ slashCommand: MXKSlashCommand) -> String {
|
||||
slashCommand.cmd
|
||||
}
|
||||
|
||||
@objc static func commandUsageFor(_ slashCommand: MXKSlashCommand) -> String {
|
||||
"Usage: \(slashCommand.cmd) \(slashCommand.parametersFormat)"
|
||||
}
|
||||
}
|
||||
|
||||
@objc enum MXKSlashCommand: Int, CaseIterable {
|
||||
case changeDisplayName
|
||||
case emote
|
||||
case joinRoom
|
||||
case partRoom
|
||||
case inviteUser
|
||||
case kickUser
|
||||
case banUser
|
||||
case unbanUser
|
||||
case setUserPowerLevel
|
||||
case resetUserPowerLevel
|
||||
case changeRoomTopic
|
||||
case discardSession
|
||||
|
||||
var cmd: String {
|
||||
switch self {
|
||||
case .changeDisplayName:
|
||||
return "/nick"
|
||||
case .emote:
|
||||
return "/me"
|
||||
case .joinRoom:
|
||||
return "/join"
|
||||
case .partRoom:
|
||||
return "/part"
|
||||
case .inviteUser:
|
||||
return "/invite"
|
||||
case .kickUser:
|
||||
return "/kick"
|
||||
case .banUser:
|
||||
return "/ban"
|
||||
case .unbanUser:
|
||||
return "/unban"
|
||||
case .setUserPowerLevel:
|
||||
return "/op"
|
||||
case .resetUserPowerLevel:
|
||||
return "/deop"
|
||||
case .changeRoomTopic:
|
||||
return "/topic"
|
||||
case .discardSession:
|
||||
return "/discardsession"
|
||||
}
|
||||
}
|
||||
|
||||
// Note: not localized for consistency, as commands are in english
|
||||
// also translating these parameters could lead to inconsistency in
|
||||
// the UI in case of languages with overlength translation.
|
||||
var parametersFormat: String {
|
||||
switch self {
|
||||
case .changeDisplayName:
|
||||
return "<display_name>"
|
||||
case .emote:
|
||||
return "<message>"
|
||||
case .joinRoom:
|
||||
return "<room-address>"
|
||||
case .partRoom:
|
||||
return "[<room-address>]"
|
||||
case .inviteUser:
|
||||
return "<user-id>"
|
||||
case .kickUser:
|
||||
return "<user-id> [<reason>]"
|
||||
case .banUser:
|
||||
return "<user-id> [<reason>]"
|
||||
case .unbanUser:
|
||||
return "<user-id>"
|
||||
case .setUserPowerLevel:
|
||||
return "<user-id> <power-level>"
|
||||
case .resetUserPowerLevel:
|
||||
return "<user-id>"
|
||||
case .changeRoomTopic:
|
||||
return "<topic>"
|
||||
case .discardSession:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +344,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
if ((RiotSettings.shared.enableThreads && [mxSession.threadingService isEventThreadRoot:event])
|
||||
|| _settings.showRedactionsInRoomHistory)
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Redacted event %@ (%@)", event.description, event.redactedBecause);
|
||||
MXLogDebug(@"[MXKEventFormatter] Redacted event %@ (%@)", event.eventId, event.redactedBecause);
|
||||
|
||||
NSString *redactorId = event.redactedBecause[@"sender"];
|
||||
NSString *redactedBy = @"";
|
||||
@@ -571,7 +571,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
}
|
||||
else
|
||||
{
|
||||
displayText = [VectorL10n noticeDisplayNameChangedFrom:event.sender :prevDisplayname :displayname];
|
||||
displayText = [VectorL10n noticeDisplayNameChangedTo:prevDisplayname :displayname];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1316,7 +1316,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
// Check attachment validity
|
||||
if (![self isSupportedAttachment:event])
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment %@", event.description);
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment in event %@", event.eventId);
|
||||
body = [VectorL10n noticeInvalidAttachment];
|
||||
*error = MXKEventFormatterErrorUnsupported;
|
||||
}
|
||||
@@ -1326,7 +1326,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
body = body? body : [VectorL10n noticeAudioAttachment];
|
||||
if (![self isSupportedAttachment:event])
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment %@", event.description);
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment in event %@", event.eventId);
|
||||
if (_isForSubtitle || !_settings.showUnsupportedEventsInRoomHistory)
|
||||
{
|
||||
body = [VectorL10n noticeInvalidAttachment];
|
||||
@@ -1343,7 +1343,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
body = body? body : [VectorL10n noticeVideoAttachment];
|
||||
if (![self isSupportedAttachment:event])
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment %@", event.description);
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment in event %@", event.eventId);
|
||||
if (_isForSubtitle || !_settings.showUnsupportedEventsInRoomHistory)
|
||||
{
|
||||
body = [VectorL10n noticeInvalidAttachment];
|
||||
@@ -1374,14 +1374,14 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported m.file format: %@", event.description);
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported m.file format in event: %@", event.eventId);
|
||||
*error = MXKEventFormatterErrorUnsupported;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment %@", event.description);
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported attachment in event %@", event.eventId);
|
||||
body = [VectorL10n noticeInvalidAttachment];
|
||||
*error = MXKEventFormatterErrorUnsupported;
|
||||
}
|
||||
@@ -1620,7 +1620,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
// Check sticker validity
|
||||
if (![self isSupportedAttachment:event])
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported sticker %@", event.description);
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported sticker in event %@", event.eventId);
|
||||
body = [VectorL10n noticeInvalidAttachment];
|
||||
*error = MXKEventFormatterErrorUnsupported;
|
||||
}
|
||||
@@ -1674,7 +1674,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
|
||||
if (!attributedDisplayText)
|
||||
{
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported event %@)", event.description);
|
||||
MXLogDebug(@"[MXKEventFormatter] Warning: Unsupported event %@)", event.eventId);
|
||||
if (_settings.showUnsupportedEventsInRoomHistory)
|
||||
{
|
||||
if (MXKEventFormatterErrorNone == *error)
|
||||
@@ -1914,7 +1914,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
// No message content in a non-redacted event. Formatter should use fallback.
|
||||
if (!repliedEventContent)
|
||||
{
|
||||
MXLogWarning(@"[MXKEventFormatter] Unable to retrieve content from replied event %@", repliedEvent.description)
|
||||
MXLogWarning(@"[MXKEventFormatter] Unable to retrieve content from replied event %@", repliedEvent.eventId)
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
@@ -1949,7 +1949,7 @@ static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogWarning(@"[MXKEventFormatter] Unable to build reply event %@", event.description)
|
||||
MXLogWarning(@"[MXKEventFormatter] Unable to build reply event %@", event.eventId)
|
||||
}
|
||||
|
||||
return html;
|
||||
|
||||
@@ -102,6 +102,14 @@ typedef enum : NSUInteger
|
||||
*/
|
||||
- (void)roomInputToolbarView:(MXKRoomInputToolbarView *)toolbarView sendFormattedTextMessage:(NSString *)formattedTextMessage withRawText:(NSString *)rawText;
|
||||
|
||||
/**
|
||||
Tells the delegate that the user wants to send a command.
|
||||
|
||||
@param toolbarView the room input toolbar view.
|
||||
@param commandText the command to send.
|
||||
*/
|
||||
- (void)roomInputToolbarView:(MXKRoomInputToolbarView *)toolbarView sendCommand:(NSString *)commandText;
|
||||
|
||||
/**
|
||||
Tells the delegate that the user wants to display the send media actions.
|
||||
|
||||
@@ -205,6 +213,15 @@ typedef enum : NSUInteger
|
||||
*/
|
||||
- (void)roomInputToolbarView:(MXKRoomInputToolbarView*)toolbarView updateActivityIndicator:(BOOL)isAnimating;
|
||||
|
||||
/**
|
||||
Tells the delegate that the partial content of the composer has changed
|
||||
and should be stored to allow restoring it later if needed.
|
||||
|
||||
@param toolbarView the room input toolbar view
|
||||
@param partialAttributedTextMessage the partial content to store
|
||||
*/
|
||||
- (void)roomInputToolbarView:(MXKRoomInputToolbarView*)toolbarView shouldStorePartialContent:(NSAttributedString*)partialAttributedTextMessage;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
@@ -382,6 +399,16 @@ typedef enum : NSUInteger
|
||||
*/
|
||||
@property (nonatomic) NSAttributedString *attributedTextMessage;
|
||||
|
||||
/**
|
||||
Sets the partial text message to apply to the current message composer.
|
||||
*/
|
||||
- (void)setPartialContent:(NSAttributedString *)attributedTextMessage;
|
||||
|
||||
/**
|
||||
Default font for the message composer.
|
||||
*/
|
||||
@property (nonatomic, readonly, nonnull) UIFont *defaultFont;
|
||||
|
||||
- (void)dismissValidationView:(MXKImageView*)validationView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -358,6 +358,10 @@
|
||||
self.textMessage = [NSString stringWithFormat:@"%@%@", self.textMessage, text];
|
||||
}
|
||||
|
||||
- (UIFont *)defaultFont
|
||||
{
|
||||
return [UIFont systemFontOfSize:15.f];
|
||||
}
|
||||
|
||||
#pragma mark - MXKFileSizes
|
||||
|
||||
@@ -1401,4 +1405,9 @@ NSString* MXKFileSizes_description(MXKFileSizes sizes)
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)setPartialContent:(NSAttributedString *)attributedTextMessage
|
||||
{
|
||||
self.attributedTextMessage = attributedTextMessage;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -65,6 +65,11 @@ NSString *const kInviteRecentTableViewCellRoomKey = @"kInviteRecentTableViewCell
|
||||
|
||||
self.rightButton.backgroundColor = ThemeService.shared.theme.tintColor;
|
||||
self.rightButton.titleLabel.font = ThemeService.shared.theme.fonts.body;
|
||||
|
||||
// bwi: 4769
|
||||
if(BWIBuildSettings.shared.useNewBumColors) {
|
||||
[self.rightButton setTitleColor:ThemeService.shared.theme.backgroundColor forState:UIControlStateNormal];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)prepareForReuse
|
||||
|
||||
@@ -25,25 +25,29 @@ import UIKit
|
||||
avatarLeading: 2.0,
|
||||
avatarSideLength: 16.0,
|
||||
itemSpacing: 4)
|
||||
private weak var messageTextView: MXKMessageTextView?
|
||||
private weak var messageTextView: UITextView?
|
||||
private var pillViewFlusher: PillViewFlusher? {
|
||||
messageTextView as? PillViewFlusher
|
||||
}
|
||||
|
||||
// MARK: - Override
|
||||
override init(textAttachment: NSTextAttachment, parentView: UIView?, textLayoutManager: NSTextLayoutManager?, location: NSTextLocation) {
|
||||
super.init(textAttachment: textAttachment, parentView: parentView, textLayoutManager: textLayoutManager, location: location)
|
||||
|
||||
self.messageTextView = parentView?.superview as? MXKMessageTextView
|
||||
// Keep a reference to the parent text view for size adjustments and pills flushing.
|
||||
messageTextView = parentView?.superview as? UITextView
|
||||
}
|
||||
|
||||
override func loadView() {
|
||||
super.loadView()
|
||||
|
||||
guard let textAttachment = self.textAttachment as? PillTextAttachment else {
|
||||
MXLog.debug("[PillAttachmentViewProvider]: attachment is missing or not of expected class")
|
||||
MXLog.failure("[PillAttachmentViewProvider]: attachment is missing or not of expected class")
|
||||
return
|
||||
}
|
||||
|
||||
guard var pillData = textAttachment.data else {
|
||||
MXLog.debug("[PillAttachmentViewProvider]: attachment misses pill data")
|
||||
MXLog.failure("[PillAttachmentViewProvider]: attachment misses pill data")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -59,6 +63,11 @@ import UIKit
|
||||
mediaManager: mainSession?.mediaManager,
|
||||
andPillData: pillData)
|
||||
view = pillView
|
||||
messageTextView?.registerPillView(pillView)
|
||||
|
||||
if let pillViewFlusher {
|
||||
pillViewFlusher.registerPillView(pillView)
|
||||
} else {
|
||||
MXLog.failure("[PillAttachmentViewProvider]: no handler found, pill will not be flushed properly")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ private enum PillAttachmentKind {
|
||||
struct PillProvider {
|
||||
private let session: MXSession
|
||||
private let eventFormatter: MXKEventFormatter
|
||||
private let event: MXEvent
|
||||
private let event: MXEvent?
|
||||
private let roomState: MXRoomState
|
||||
private let latestRoomState: MXRoomState?
|
||||
private let isEditMode: Bool
|
||||
|
||||
init(withSession session: MXSession,
|
||||
eventFormatter: MXKEventFormatter,
|
||||
event: MXEvent,
|
||||
event: MXEvent?,
|
||||
roomState: MXRoomState,
|
||||
andLatestRoomState latestRoomState: MXRoomState?,
|
||||
isEditMode: Bool) {
|
||||
@@ -46,7 +46,7 @@ struct PillProvider {
|
||||
self.isEditMode = isEditMode
|
||||
}
|
||||
|
||||
func pillTextAttachmentString(forUrl url: URL, withLabel label: String, event: MXEvent) -> NSAttributedString? {
|
||||
func pillTextAttachmentString(forUrl url: URL, withLabel label: String) -> NSAttributedString? {
|
||||
|
||||
// Try to get a pill from this url
|
||||
guard let pillType = PillType.from(url: url) else {
|
||||
@@ -133,6 +133,10 @@ struct PillProvider {
|
||||
let avatarUrl = roomMember?.avatarUrl ?? user?.avatarUrl
|
||||
let displayName = roomMember?.displayname ?? user?.displayName ?? userId
|
||||
let isHighlighted = userId == session.myUserId
|
||||
// No actual event means it is a composer Pill. No highlight
|
||||
&& event != nil
|
||||
// No highlight on self-mentions
|
||||
&& event?.sender != session.myUserId
|
||||
|
||||
let avatar: PillTextAttachmentItem
|
||||
if roomMember == nil && user == nil {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import WysiwygComposer
|
||||
|
||||
/// Defines behaviour for an object that is able to manage views created
|
||||
/// by a `NSTextAttachmentViewProvider`. This can be implemented
|
||||
/// by an `UITextView` that would keep track of views in order to
|
||||
/// (internally) clear them when required (e.g. when setting a new attributed text).
|
||||
///
|
||||
/// Note: It is necessary to clear views manually due to a bug in iOS. See `MXKMessageTextView`.
|
||||
@available(iOS 15.0, *)
|
||||
protocol PillViewFlusher: AnyObject {
|
||||
/// Register a pill view that has been added through `NSTextAttachmentViewProvider`.
|
||||
/// Should be called within the `loadView` function in order to clear the pills properly on text updates.
|
||||
///
|
||||
/// - Parameter pillView: View to register.
|
||||
func registerPillView(_ pillView: UIView)
|
||||
}
|
||||
|
||||
@available(iOS 15.0, *)
|
||||
extension MXKMessageTextView: PillViewFlusher { }
|
||||
|
||||
@available(iOS 15.0, *)
|
||||
extension WysiwygTextView: PillViewFlusher { }
|
||||
@@ -65,7 +65,7 @@ class PillsFormatter: NSObject {
|
||||
|
||||
// try to get a mention pill from the url
|
||||
let label = Range(range, in: newAttr.string).flatMap { String(newAttr.string[$0]) }
|
||||
if let attachmentString: NSAttributedString = provider.pillTextAttachmentString(forUrl: url, withLabel: label ?? "", event: event) {
|
||||
if let attachmentString: NSAttributedString = provider.pillTextAttachmentString(forUrl: url, withLabel: label ?? "") {
|
||||
// replace the url with the pill
|
||||
newAttr.replaceCharacters(in: range, with: attachmentString)
|
||||
}
|
||||
@@ -74,6 +74,41 @@ class PillsFormatter: NSObject {
|
||||
return newAttr
|
||||
}
|
||||
|
||||
/// Insert text attachments for pills inside given attributed string containing markdown.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - markdownString: An attributed string with markdown formatting
|
||||
/// - roomState: The current room state
|
||||
/// - font: The font to use for the pill text
|
||||
/// - Returns: A new attributed string with pills.
|
||||
static func insertPills(in markdownString: NSAttributedString,
|
||||
withSession session: MXSession,
|
||||
eventFormatter: MXKEventFormatter,
|
||||
roomState: MXRoomState,
|
||||
font: UIFont) -> NSAttributedString {
|
||||
let matches = markdownLinks(in: markdownString)
|
||||
|
||||
// If we have some matches, replace permalinks by a pill version.
|
||||
guard !matches.isEmpty else { return markdownString }
|
||||
|
||||
let pillProvider = PillProvider(withSession: session,
|
||||
eventFormatter: eventFormatter,
|
||||
event: nil,
|
||||
roomState: roomState,
|
||||
andLatestRoomState: nil,
|
||||
isEditMode: true)
|
||||
|
||||
let mutable = NSMutableAttributedString(attributedString: markdownString)
|
||||
|
||||
matches.reversed().forEach {
|
||||
if let attachmentString = pillProvider.pillTextAttachmentString(forUrl: $0.url, withLabel: $0.label) {
|
||||
mutable.replaceCharacters(in: $0.range, with: attachmentString)
|
||||
}
|
||||
}
|
||||
|
||||
return mutable
|
||||
}
|
||||
|
||||
/// Creates a string with all pills of given attributed string replaced by display names.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -123,6 +158,20 @@ class PillsFormatter: NSObject {
|
||||
}
|
||||
return attributedStringWithAttachment(attachment, link: url, font: font)
|
||||
}
|
||||
|
||||
static func mentionPill(withUrl url: URL,
|
||||
andLabel label: String,
|
||||
session: MXSession,
|
||||
eventFormatter: MXKEventFormatter,
|
||||
roomState: MXRoomState) -> NSAttributedString? {
|
||||
let pillProvider = PillProvider(withSession: session,
|
||||
eventFormatter: eventFormatter,
|
||||
event: nil,
|
||||
roomState: roomState,
|
||||
andLatestRoomState: nil,
|
||||
isEditMode: true)
|
||||
return pillProvider.pillTextAttachmentString(forUrl: url, withLabel: label)
|
||||
}
|
||||
|
||||
/// Update alpha of all `PillTextAttachment` contained in given attributed string.
|
||||
///
|
||||
@@ -160,12 +209,45 @@ class PillsFormatter: NSObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Private Methods
|
||||
@available (iOS 15.0, *)
|
||||
extension PillsFormatter {
|
||||
struct MarkdownLinkResult: Equatable {
|
||||
let url: URL
|
||||
let label: String
|
||||
let range: NSRange
|
||||
}
|
||||
|
||||
static func markdownLinks(in attributedString: NSAttributedString) -> [MarkdownLinkResult] {
|
||||
// Create a regexp that detects markdown links.
|
||||
// Pattern source: https://gist.github.com/hugocf/66d6cd241eff921e0e02
|
||||
let pattern = "\\[([^\\]]+)\\]\\(([^\\)\"\\s]+)(?:\\s+\"(.*)\")?\\)"
|
||||
guard let regExp = try? NSRegularExpression(pattern: pattern) else { return [] }
|
||||
|
||||
let matches = regExp.matches(in: attributedString.string,
|
||||
range: .init(location: 0, length: attributedString.length))
|
||||
|
||||
return matches.compactMap { match in
|
||||
let labelRange = match.range(at: 1)
|
||||
let urlRange = match.range(at: 2)
|
||||
let label = attributedString.attributedSubstring(from: labelRange).string
|
||||
var url = attributedString.attributedSubstring(from: urlRange).string
|
||||
|
||||
// Note: a valid markdown link can be written with
|
||||
// enclosing <..>, remove them for userId detection.
|
||||
if url.first == "<" && url.last == ">" {
|
||||
url = String(url[url.index(after: url.startIndex)...url.index(url.endIndex, offsetBy: -2)])
|
||||
}
|
||||
|
||||
if let url = URL(string: url) {
|
||||
return MarkdownLinkResult(url: url, label: label, range: match.range)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func attributedStringWithAttachment(_ attachment: PillTextAttachment, link: URL?, font: UIFont) -> NSAttributedString {
|
||||
let string = NSMutableAttributedString(attachment: attachment)
|
||||
|
||||
@@ -19,7 +19,7 @@ import Foundation
|
||||
extension RoomDataSource {
|
||||
// MARK: - Private Constants
|
||||
private enum Constants {
|
||||
static let emoteMessageSlashCommandPrefix = String(format: "%@ ", kMXKSlashCmdEmote)
|
||||
static let emoteMessageSlashCommandPrefix = String(format: "%@ ", MXKSlashCommand.emote.cmd)
|
||||
}
|
||||
|
||||
// MARK: - NSAttributedString Sending
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#import "MXKEncryptionKeysImportView.h"
|
||||
|
||||
#import "NSBundle+MatrixKit.h"
|
||||
#import "MXKSlashCommands.h"
|
||||
#import "MXKSwiftHeader.h"
|
||||
|
||||
#import "MXKPreviewViewController.h"
|
||||
@@ -361,7 +360,7 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
{
|
||||
// Retrieve the potential message partially typed during last room display.
|
||||
// Note: We have to wait for viewDidAppear before updating growingTextView (viewWillAppear is too early)
|
||||
inputToolbarView.attributedTextMessage = roomDataSource.partialAttributedTextMessage;
|
||||
[inputToolbarView setPartialContent:roomDataSource.partialAttributedTextMessage];
|
||||
}
|
||||
|
||||
if (!hasAppearedOnce)
|
||||
@@ -1284,8 +1283,14 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
|
||||
// TODO: display an alert with the cmd usage in case of error or unrecognized cmd.
|
||||
NSString *cmdUsage;
|
||||
|
||||
NSString* kMXKSlashCmdChangeDisplayName = [MXKSlashCommandsHelper commandNameFor:MXKSlashCommandChangeDisplayName];
|
||||
NSString* kMXKSlashCmdJoinRoom = [MXKSlashCommandsHelper commandNameFor:MXKSlashCommandJoinRoom];
|
||||
NSString* kMXKSlashCmdPartRoom = [MXKSlashCommandsHelper commandNameFor:MXKSlashCommandPartRoom];
|
||||
NSString* kMXKSlashCmdChangeRoomTopic = [MXKSlashCommandsHelper commandNameFor:MXKSlashCommandChangeRoomTopic];
|
||||
|
||||
|
||||
if ([cmd isEqualToString:kMXKSlashCmdEmote])
|
||||
if ([cmd isEqualToString:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandEmote]])
|
||||
{
|
||||
// send message as an emote
|
||||
[self sendTextMessage:string];
|
||||
@@ -1320,7 +1325,7 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /nick <display_name>";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandChangeDisplayName];
|
||||
}
|
||||
}
|
||||
else if ([string hasPrefix:kMXKSlashCmdJoinRoom])
|
||||
@@ -1355,7 +1360,7 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /join <room_alias>";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandJoinRoom];
|
||||
}
|
||||
}
|
||||
else if ([string hasPrefix:kMXKSlashCmdPartRoom])
|
||||
@@ -1413,7 +1418,7 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /part [<room_alias>]";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandPartRoom];
|
||||
}
|
||||
}
|
||||
else if ([string hasPrefix:kMXKSlashCmdChangeRoomTopic])
|
||||
@@ -1445,10 +1450,10 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /topic <topic>";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandChangeRoomTopic];
|
||||
}
|
||||
}
|
||||
else if ([string hasPrefix:kMXKSlashCmdDiscardSession])
|
||||
else if ([string hasPrefix:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandDiscardSession]])
|
||||
{
|
||||
[roomDataSource.mxSession.crypto discardOutboundGroupSessionForRoomWithRoomId:roomDataSource.roomId onComplete:^{
|
||||
MXLogDebug(@"[MXKRoomVC] Manually discarded outbound group session");
|
||||
@@ -1470,7 +1475,7 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
userId = nil;
|
||||
}
|
||||
|
||||
if ([cmd isEqualToString:kMXKSlashCmdInviteUser])
|
||||
if ([cmd isEqualToString:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandInviteUser]])
|
||||
{
|
||||
if (userId)
|
||||
{
|
||||
@@ -1489,10 +1494,10 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /invite <userId>";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandInviteUser];
|
||||
}
|
||||
}
|
||||
else if ([cmd isEqualToString:kMXKSlashCmdKickUser])
|
||||
else if ([cmd isEqualToString:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandKickUser]])
|
||||
{
|
||||
if (userId)
|
||||
{
|
||||
@@ -1524,10 +1529,10 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /kick <userId> [<reason>]";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandKickUser];
|
||||
}
|
||||
}
|
||||
else if ([cmd isEqualToString:kMXKSlashCmdBanUser])
|
||||
else if ([cmd isEqualToString:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandBanUser]])
|
||||
{
|
||||
if (userId)
|
||||
{
|
||||
@@ -1559,10 +1564,10 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /ban <userId> [<reason>]";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandBanUser];
|
||||
}
|
||||
}
|
||||
else if ([cmd isEqualToString:kMXKSlashCmdUnbanUser])
|
||||
else if ([cmd isEqualToString:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandUnbanUser]])
|
||||
{
|
||||
if (userId)
|
||||
{
|
||||
@@ -1581,10 +1586,10 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /unban <userId>";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandUnbanUser];
|
||||
}
|
||||
}
|
||||
else if ([cmd isEqualToString:kMXKSlashCmdSetUserPowerLevel])
|
||||
else if ([cmd isEqualToString:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandSetUserPowerLevel]])
|
||||
{
|
||||
// Retrieve power level
|
||||
NSString *powerLevel = nil;
|
||||
@@ -1617,10 +1622,10 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /op <userId> <power level>";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandSetUserPowerLevel];
|
||||
}
|
||||
}
|
||||
else if ([cmd isEqualToString:kMXKSlashCmdResetUserPowerLevel])
|
||||
else if ([cmd isEqualToString:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandResetUserPowerLevel]])
|
||||
{
|
||||
if (userId)
|
||||
{
|
||||
@@ -1639,7 +1644,7 @@ static const CGFloat kCellVisibilityMinimumHeight = 8.0;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
cmdUsage = @"Usage: /deop <userId>";
|
||||
cmdUsage = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandResetUserPowerLevel];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -143,6 +143,12 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
|
||||
navigationRouter.setRootModule(self, popCompletion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
// FRROT its like sleep() again -> hopefully there is a better solution. When directly calling self.navigation router here its still nil and it needs to be called this early because soon afterwards the pollCells get build
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
|
||||
TimelinePollProvider.shared.navigationRouter = self.navigationRouter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func start(withEventId eventId: String, completion: (() -> Void)?) {
|
||||
|
||||
@@ -98,7 +98,7 @@ final class RoomInfoListViewModel: NSObject, RoomInfoListViewModelType {
|
||||
}
|
||||
|
||||
func isInviteOnlyRoom() -> Bool {
|
||||
return room.summary.membership == .invite
|
||||
return room.summary.joinRule == MXRoomJoinRule.invite.identifier
|
||||
}
|
||||
|
||||
func isPermalinkableRoom() -> Bool {
|
||||
|
||||
@@ -78,19 +78,11 @@ class RoomInfoBasicView: UIView {
|
||||
func configure(withViewData viewData: RoomInfoBasicViewData) {
|
||||
let avatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.roomId, withDisplayName: viewData.roomDisplayName)
|
||||
|
||||
if BWIBuildSettings.shared.bwiUseCustomPersonalNotesAvatar {
|
||||
if let session = AppDelegate.theDelegate().mxSessions.first as? MXSession {
|
||||
let service = PersonalNotesDefaultService(mxSession: session)
|
||||
if let personalNotesRoomId = service.personalNotesRoomId(), personalNotesRoomId == viewData.roomId {
|
||||
avatarImageView.image = UIImage(named: service.avatarImageUrl())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if avatarImageView.image == nil {
|
||||
if let avatarUrl = viewData.avatarUrl {
|
||||
// bwi: update room avatar
|
||||
if let avatarUrl = viewData.avatarUrl {
|
||||
if !avatarUrl.isEmpty {
|
||||
avatarImageView.enableInMemoryCache = true
|
||||
|
||||
|
||||
avatarImageView.setImageURI(avatarUrl,
|
||||
withType: nil,
|
||||
andImageOrientation: .up,
|
||||
@@ -101,6 +93,17 @@ class RoomInfoBasicView: UIView {
|
||||
} else {
|
||||
avatarImageView.image = avatarImage
|
||||
}
|
||||
} else {
|
||||
avatarImageView.image = avatarImage
|
||||
}
|
||||
|
||||
if BWIBuildSettings.shared.bwiUseCustomPersonalNotesAvatar {
|
||||
if let session = AppDelegate.theDelegate().mxSessions.first as? MXSession {
|
||||
let service = PersonalNotesDefaultService(mxSession: session)
|
||||
if let personalNotesRoomId = service.personalNotesRoomId(), personalNotesRoomId == viewData.roomId {
|
||||
avatarImageView.image = UIImage(named: service.avatarImageUrl())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
badgeImageView.image = viewData.encryptionImage
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
@class VoiceBroadcastService;
|
||||
@class ComposerLinkActionBridgePresenter;
|
||||
@class PerformanceProfile;
|
||||
@class BWIAnalyticsHelper;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -62,7 +63,7 @@ extern NSTimeInterval const kResizeComposerAnimationDuration;
|
||||
// The preview header
|
||||
@property (weak, nonatomic, nullable) IBOutlet UIView *previewHeaderContainer;
|
||||
@property (weak, nonatomic, nullable) IBOutlet NSLayoutConstraint *previewHeaderContainerHeightConstraint;
|
||||
@property (weak, nonatomic, nullable) IBOutlet NSLayoutConstraint *userSuggestionContainerHeightConstraint;
|
||||
@property (weak, nonatomic, nullable) IBOutlet NSLayoutConstraint *completionSuggestionContainerHeightConstraint;
|
||||
|
||||
// The jump to last unread banner
|
||||
@property (weak, nonatomic, nullable) IBOutlet UIView *jumpToLastUnreadBannerContainer;
|
||||
|
||||
@@ -100,7 +100,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
@interface RoomViewController () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
|
||||
ReactionsMenuViewModelCoordinatorDelegate, EditHistoryCoordinatorBridgePresenterDelegate, MXKDocumentPickerPresenterDelegate, EmojiPickerCoordinatorBridgePresenterDelegate,
|
||||
ReactionHistoryCoordinatorBridgePresenterDelegate, CameraPresenterDelegate, MediaPickerCoordinatorBridgePresenterDelegate,
|
||||
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate, ThreadsBetaCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate, RoomParticipantsInviteCoordinatorBridgePresenterDelegate, RoomInputToolbarViewDelegate, ComposerCreateActionListBridgePresenterDelegate>
|
||||
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, CompletionSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate, ThreadsBetaCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate, RoomParticipantsInviteCoordinatorBridgePresenterDelegate, RoomInputToolbarViewDelegate, ComposerCreateActionListBridgePresenterDelegate>
|
||||
{
|
||||
|
||||
// The preview header
|
||||
@@ -226,8 +226,8 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
@property (nonatomic, strong) ShareManager *shareManager;
|
||||
@property (nonatomic, strong) EventMenuBuilder *eventMenuBuilder;
|
||||
|
||||
@property (nonatomic, strong) UserSuggestionCoordinatorBridge *userSuggestionCoordinator;
|
||||
@property (nonatomic, weak) IBOutlet UIView *userSuggestionContainerView;
|
||||
@property (nonatomic, strong) CompletionSuggestionCoordinatorBridge *completionSuggestionCoordinator;
|
||||
@property (nonatomic, weak) IBOutlet UIView *completionSuggestionContainerView;
|
||||
|
||||
@property (nonatomic, readwrite) RoomDisplayConfiguration *displayConfiguration;
|
||||
|
||||
@@ -431,7 +431,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
[self setupActions];
|
||||
|
||||
[self setupUserSuggestionViewIfNeeded];
|
||||
[self setupCompletionSuggestionViewIfNeeded];
|
||||
|
||||
[self.topBannersStackView vc_removeAllSubviews];
|
||||
}
|
||||
@@ -713,7 +713,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
{
|
||||
// Retrieve the potential message partially typed during last room display.
|
||||
// Note: We have to wait for viewDidAppear before updating growingTextView (viewWillAppear is too early)
|
||||
self.inputToolbarView.attributedTextMessage = self.roomDataSource.partialAttributedTextMessage;
|
||||
[self.inputToolbarView setPartialContent:self.roomDataSource.partialAttributedTextMessage];
|
||||
}
|
||||
|
||||
[self setMaximisedToolbarIsHiddenIfNeeded: NO];
|
||||
@@ -1108,12 +1108,14 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[VoiceMessageMediaServiceProvider.sharedProvider setCurrentRoomSummary:dataSource.room.summary];
|
||||
_voiceMessageController.roomId = dataSource.roomId;
|
||||
|
||||
_userSuggestionCoordinator = [[UserSuggestionCoordinatorBridge alloc] initWithMediaManager:self.roomDataSource.mxSession.mediaManager
|
||||
_completionSuggestionCoordinator = [[CompletionSuggestionCoordinatorBridge alloc] initWithMediaManager:self.roomDataSource.mxSession.mediaManager
|
||||
room:dataSource.room
|
||||
userID:self.roomDataSource.mxSession.myUserId];
|
||||
_userSuggestionCoordinator.delegate = self;
|
||||
_completionSuggestionCoordinator.delegate = self;
|
||||
|
||||
[self setupUserSuggestionViewIfNeeded];
|
||||
[self setupCompletionSuggestionViewIfNeeded];
|
||||
|
||||
[self updateRoomInputToolbarViewClassIfNeeded];
|
||||
|
||||
[self updateTopBanners];
|
||||
}
|
||||
@@ -1214,6 +1216,12 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
- (void)updateRoomInputToolbarViewClassIfNeeded
|
||||
{
|
||||
Class roomInputToolbarViewClass = [RoomViewController mainToolbarClass];
|
||||
|
||||
// If RTE is enabled, delay the toolbar setup until `completionSuggestionCoordinator` is ready.
|
||||
if (roomInputToolbarViewClass == WysiwygInputToolbarView.class && _completionSuggestionCoordinator == nil)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL shouldDismissContextualMenu = NO;
|
||||
|
||||
@@ -1301,6 +1309,8 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
- (BOOL)sendAsIRCStyleCommandIfPossible:(NSString*)string
|
||||
{
|
||||
// Override the default behavior for `/join` command in order to open automatically the joined room
|
||||
|
||||
NSString* kMXKSlashCmdJoinRoom = [MXKSlashCommandsHelper commandNameFor:MXKSlashCommandJoinRoom];
|
||||
|
||||
if ([string hasPrefix:kMXKSlashCmdJoinRoom])
|
||||
{
|
||||
@@ -1337,7 +1347,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
else
|
||||
{
|
||||
// Display cmd usage in text input as placeholder
|
||||
self.inputToolbarView.placeholder = @"Usage: /join <room_alias>";
|
||||
self.inputToolbarView.placeholder = [MXKSlashCommandsHelper commandUsageFor:MXKSlashCommandJoinRoom];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@@ -2770,13 +2780,13 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupUserSuggestionViewIfNeeded
|
||||
- (void)setupCompletionSuggestionViewIfNeeded
|
||||
{
|
||||
if(!self.isViewLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIViewController *suggestionsViewController = self.userSuggestionCoordinator.toPresentable;
|
||||
UIViewController *suggestionsViewController = self.completionSuggestionCoordinator.toPresentable;
|
||||
|
||||
if (!suggestionsViewController)
|
||||
{
|
||||
@@ -2786,12 +2796,12 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[suggestionsViewController.view setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
[self addChildViewController:suggestionsViewController];
|
||||
[self.userSuggestionContainerView addSubview:suggestionsViewController.view];
|
||||
[self.completionSuggestionContainerView addSubview:suggestionsViewController.view];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[[suggestionsViewController.view.topAnchor constraintEqualToAnchor:self.userSuggestionContainerView.topAnchor],
|
||||
[suggestionsViewController.view.leadingAnchor constraintEqualToAnchor:self.userSuggestionContainerView.leadingAnchor],
|
||||
[suggestionsViewController.view.trailingAnchor constraintEqualToAnchor:self.userSuggestionContainerView.trailingAnchor],
|
||||
[suggestionsViewController.view.bottomAnchor constraintEqualToAnchor:self.userSuggestionContainerView.bottomAnchor],]];
|
||||
[NSLayoutConstraint activateConstraints:@[[suggestionsViewController.view.topAnchor constraintEqualToAnchor:self.completionSuggestionContainerView.topAnchor],
|
||||
[suggestionsViewController.view.leadingAnchor constraintEqualToAnchor:self.completionSuggestionContainerView.leadingAnchor],
|
||||
[suggestionsViewController.view.trailingAnchor constraintEqualToAnchor:self.completionSuggestionContainerView.trailingAnchor],
|
||||
[suggestionsViewController.view.bottomAnchor constraintEqualToAnchor:self.completionSuggestionContainerView.bottomAnchor],]];
|
||||
|
||||
[suggestionsViewController didMoveToParentViewController:self];
|
||||
}
|
||||
@@ -4332,7 +4342,9 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (BWIBuildSettings.shared.messageDetailsAllowPermalink && !(self.roomDataSource.room.isDirect || self.roomDataSource.room.isPersonalNotesRoom || self.roomDataSource.room.summary.membership == MXMembershipInvite))
|
||||
if (BWIBuildSettings.shared.messageDetailsAllowPermalink && !(self.roomDataSource.room.isDirect || self.roomDataSource.room.isPersonalNotesRoom ||
|
||||
// bwi #4390: remove permalink action if room is private
|
||||
[self.roomDataSource.room.summary.joinRule isEqualToString: kMXRoomJoinRuleInvite]))
|
||||
{
|
||||
[self.eventMenuBuilder addItemWithType:EventMenuItemTypePermalink
|
||||
action:[UIAlertAction actionWithTitle:[BWIL10n roomEventActionPermalink]
|
||||
@@ -5202,7 +5214,22 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
- (void)roomInputToolbarViewDidChangeTextMessage:(RoomInputToolbarView *)toolbarView
|
||||
{
|
||||
[self.userSuggestionCoordinator processTextMessage:toolbarView.textMessage];
|
||||
[self.completionSuggestionCoordinator processTextMessage:toolbarView.textMessage];
|
||||
}
|
||||
|
||||
- (void)didDetectTextPattern:(SuggestionPatternWrapper *)suggestionPattern
|
||||
{
|
||||
[self.completionSuggestionCoordinator processSuggestionPattern:suggestionPattern];
|
||||
}
|
||||
|
||||
- (CompletionSuggestionViewModelContextWrapper *)completionSuggestionContext
|
||||
{
|
||||
return [self.completionSuggestionCoordinator sharedContext];
|
||||
}
|
||||
|
||||
- (MXMediaManager *)mediaManager
|
||||
{
|
||||
return self.roomDataSource.mxSession.mediaManager;
|
||||
}
|
||||
|
||||
- (void)roomInputToolbarViewDidOpenActionMenu:(RoomInputToolbarView*)toolbarView
|
||||
@@ -5228,6 +5255,27 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)roomInputToolbarView:(MXKRoomInputToolbarView *)toolbarView sendCommand:(NSString *)commandText
|
||||
{
|
||||
// Create before sending the message in case of a discussion (direct chat)
|
||||
MXWeakify(self);
|
||||
[self createDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (readyToSend) {
|
||||
if (![self sendAsIRCStyleCommandIfPossible:commandText])
|
||||
{
|
||||
// Display an error for unknown command
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
|
||||
message:[VectorL10n roomCommandErrorUnknownCommand]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] style:UIAlertActionStyleDefault handler:nil]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)roomInputToolbarViewShowSendMediaActions:(MXKRoomInputToolbarView *)toolbarView
|
||||
{
|
||||
NSMutableArray *actionItems = [NSMutableArray new];
|
||||
@@ -5277,7 +5325,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
if (readyToSend) {
|
||||
BOOL isMessageAHandledCommand = NO;
|
||||
// "/me" command is supported with Pills in RoomDataSource.
|
||||
if (![attributedTextMessage.string hasPrefix:kMXKSlashCmdEmote])
|
||||
if (![attributedTextMessage.string hasPrefix:[MXKSlashCommandsHelper commandNameFor:MXKSlashCommandEmote]])
|
||||
{
|
||||
// Other commands currently work with identifiers (e.g. ban, invite, op, etc).
|
||||
NSString *message;
|
||||
@@ -5302,6 +5350,11 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)roomInputToolbarView:(MXKRoomInputToolbarView *)toolbarView shouldStorePartialContent:(NSAttributedString *)partialAttributedTextMessage
|
||||
{
|
||||
self.roomDataSource.partialAttributedTextMessage = partialAttributedTextMessage;
|
||||
}
|
||||
|
||||
#pragma mark - MXKRoomMemberDetailsViewControllerDelegate
|
||||
|
||||
- (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)roomMemberDetailsViewController startChatWithMemberId:(NSString *)matrixId completion:(void (^)(void))completion
|
||||
@@ -6154,7 +6207,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
if (self.saveProgressTextInput)
|
||||
{
|
||||
// Restore the potential message partially typed before jump to last unread messages.
|
||||
self.inputToolbarView.attributedTextMessage = roomDataSource.partialAttributedTextMessage;
|
||||
[self.inputToolbarView setPartialContent:roomDataSource.partialAttributedTextMessage];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7543,23 +7596,47 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray<NSIndexPath *> *rowsToReload = [[NSMutableArray alloc] init];
|
||||
// Get the current hightlighted event because we will need to reload it
|
||||
NSString *currentHiglightedEventId = self.customizedRoomDataSource.highlightedEventId;
|
||||
if (currentHiglightedEventId)
|
||||
{
|
||||
NSInteger currentHiglightedRow = [self.roomDataSource indexOfCellDataWithEventId:currentHiglightedEventId];
|
||||
if (currentHiglightedRow != NSNotFound)
|
||||
{
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentHiglightedRow inSection:0];
|
||||
if ([[self.bubblesTableView indexPathsForVisibleRows] containsObject:indexPath])
|
||||
{
|
||||
[rowsToReload addObject:indexPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.customizedRoomDataSource.highlightedEventId = eventId;
|
||||
|
||||
// Add the new highligted event to the list of rows to reload
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
|
||||
if ([[self.bubblesTableView indexPathsForVisibleRows] containsObject:indexPath])
|
||||
BOOL indexPathIsVisible = [[self.bubblesTableView indexPathsForVisibleRows] containsObject:indexPath];
|
||||
if (indexPathIsVisible)
|
||||
{
|
||||
[self.bubblesTableView reloadRowsAtIndexPaths:@[indexPath]
|
||||
[rowsToReload addObject:indexPath];
|
||||
}
|
||||
|
||||
// Reload rows
|
||||
if (rowsToReload.count > 0)
|
||||
{
|
||||
[self.bubblesTableView reloadRowsAtIndexPaths:rowsToReload
|
||||
withRowAnimation:UITableViewRowAnimationNone];
|
||||
[self.bubblesTableView scrollToRowAtIndexPath:indexPath
|
||||
atScrollPosition:UITableViewScrollPositionMiddle
|
||||
animated:YES];
|
||||
}
|
||||
else if ([self.bubblesTableView vc_hasIndexPath:indexPath])
|
||||
|
||||
// Scroll to the newly highlighted row
|
||||
if (indexPathIsVisible || [self.bubblesTableView vc_hasIndexPath:indexPath])
|
||||
{
|
||||
[self.bubblesTableView scrollToRowAtIndexPath:indexPath
|
||||
atScrollPosition:UITableViewScrollPositionMiddle
|
||||
animated:YES];
|
||||
}
|
||||
|
||||
if (completion)
|
||||
{
|
||||
completion();
|
||||
@@ -8111,6 +8188,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
{
|
||||
[self.roomDataSource sendVoiceMessage:url additionalContentParams:nil mimeType:nil duration:duration samples:samples success:^(NSString *eventId) {
|
||||
MXLogDebug(@"Success with event id %@", eventId);
|
||||
[self trackVoiceMessage: duration];
|
||||
completion(YES);
|
||||
} failure:^(NSError *error) {
|
||||
MXLogError(@"Failed sending voice message");
|
||||
@@ -8137,24 +8215,29 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[[LegacyAppDelegate theDelegate] openSpaceWithId:spaceId];
|
||||
}
|
||||
|
||||
#pragma mark - Bwi Measurements
|
||||
|
||||
- (void) finishTextMessageProfil:(PerformanceProfile*)profile {
|
||||
[profile stopMeasurement];
|
||||
if( [profile isLogable] ) {
|
||||
[self.roomDataSource.room members:^(MXRoomMembers *roomMembers) {
|
||||
NSUInteger noOfUsers = roomMembers.joinedMembers.count;
|
||||
NSUInteger noOfDevices = 0;
|
||||
for (MXRoomMember* member in roomMembers.joinedMembers) {
|
||||
noOfDevices += [self.mainSession.crypto devicesForUser:member.userId].count;
|
||||
}
|
||||
[profile log2AnalyticsWithUsers:noOfUsers devices:noOfDevices];
|
||||
[BWIAnalyticsHelper getRoomDeviceCountWithRoom:self.roomDataSource.room completion:^(NSInteger deviceCount) {
|
||||
[profile log2AnalyticsWithUsers:noOfUsers devices:deviceCount];
|
||||
}];
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
// Bwi #4795: voice message
|
||||
- (void) trackVoiceMessage:(NSInteger)duration {
|
||||
[BWIAnalyticsHelper getRoomDeviceCountWithRoom:self.roomDataSource.room completion:^(NSInteger deviceCount) {
|
||||
NSString *deviceCountString = [BWIAnalyticsHelper dimensionForDeviceCount: deviceCount];
|
||||
NSNumber *durationInSeconds = [NSNumber numberWithInteger:(duration / 1000)];
|
||||
[BWIAnalytics.sharedTracker trackEventWithDimensionWithCategory:@"Feature" action:@"SendVoiceMessage" dimension:deviceCountString value:durationInSeconds name:@"send_voice_message_default"];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - BWI Emoji History
|
||||
|
||||
- (void) bwiAddedEmoji:(NSString*)emoji {
|
||||
@@ -8164,7 +8247,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
#pragma mark - UserSuggestionCoordinatorBridgeDelegate
|
||||
|
||||
- (void)userSuggestionCoordinatorBridge:(UserSuggestionCoordinatorBridge *)coordinator
|
||||
- (void)completionSuggestionCoordinatorBridge:(CompletionSuggestionCoordinatorBridge *)coordinator
|
||||
didRequestMentionForMember:(MXRoomMember *)member
|
||||
textTrigger:(NSString *)textTrigger
|
||||
{
|
||||
@@ -8172,16 +8255,32 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self mention:member];
|
||||
}
|
||||
|
||||
- (void)userSuggestionCoordinatorBridgeDidRequestMentionForRoom:(UserSuggestionCoordinatorBridge *)coordinator
|
||||
- (void)completionSuggestionCoordinatorBridgeDidRequestMentionForRoom:(CompletionSuggestionCoordinatorBridge *)coordinator
|
||||
textTrigger:(NSString *)textTrigger
|
||||
{
|
||||
[self removeTriggerTextFromComposer:textTrigger];
|
||||
[self.inputToolbarView pasteText:[UserSuggestionID.room stringByAppendingString:@" "]];
|
||||
[self.inputToolbarView pasteText:[CompletionSuggestionUserID.room stringByAppendingString:@" "]];
|
||||
}
|
||||
|
||||
- (void)completionSuggestionCoordinatorBridge:(CompletionSuggestionCoordinatorBridge *)coordinator
|
||||
didRequestCommand:(NSString *)command
|
||||
textTrigger:(NSString *)textTrigger
|
||||
{
|
||||
[self removeTriggerTextFromComposer:textTrigger];
|
||||
[self setCommand:command];
|
||||
}
|
||||
|
||||
- (void)removeTriggerTextFromComposer:(NSString *)textTrigger
|
||||
{
|
||||
RoomInputToolbarView *toolbar = (RoomInputToolbarView *)self.inputToolbarView;
|
||||
Class roomInputToolbarViewClass = [RoomViewController mainToolbarClass];
|
||||
|
||||
// RTE handles removing the text trigger by itself.
|
||||
if (roomInputToolbarViewClass == WysiwygInputToolbarView.class && RiotSettings.shared.enableWysiwygTextFormatting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (toolbar && textTrigger.length) {
|
||||
NSMutableAttributedString *attributedTextMessage = [[NSMutableAttributedString alloc] initWithAttributedString:toolbar.attributedTextMessage];
|
||||
[[attributedTextMessage mutableString] replaceOccurrencesOfString:textTrigger
|
||||
@@ -8192,11 +8291,11 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)userSuggestionCoordinatorBridge:(UserSuggestionCoordinatorBridge *)coordinator didUpdateViewHeight:(CGFloat)height
|
||||
- (void)completionSuggestionCoordinatorBridge:(CompletionSuggestionCoordinatorBridge *)coordinator didUpdateViewHeight:(CGFloat)height
|
||||
{
|
||||
if (self.userSuggestionContainerHeightConstraint.constant != height)
|
||||
if (self.completionSuggestionContainerHeightConstraint.constant != height)
|
||||
{
|
||||
self.userSuggestionContainerHeightConstraint.constant = height;
|
||||
self.completionSuggestionContainerHeightConstraint.constant = height;
|
||||
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
|
||||
@@ -14,46 +14,68 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import HTMLParser
|
||||
import UIKit
|
||||
import WysiwygComposer
|
||||
|
||||
extension RoomViewController {
|
||||
// MARK: - Override
|
||||
open override func mention(_ roomMember: MXRoomMember) {
|
||||
guard let inputToolbar = inputToolbar else {
|
||||
return
|
||||
}
|
||||
|
||||
let newAttributedString = NSMutableAttributedString(attributedString: inputToolbar.attributedTextMessage)
|
||||
|
||||
if inputToolbar.attributedTextMessage.length > 0 {
|
||||
if #available(iOS 15.0, *) {
|
||||
newAttributedString.append(PillsFormatter.mentionPill(withRoomMember: roomMember,
|
||||
isHighlighted: false,
|
||||
font: inputToolbar.textDefaultFont))
|
||||
} else {
|
||||
newAttributedString.appendString(roomMember.displayname.count > 0 ? roomMember.displayname : roomMember.userId)
|
||||
}
|
||||
newAttributedString.appendString(" ")
|
||||
} else if roomMember.userId == self.mainSession.myUser.userId {
|
||||
newAttributedString.appendString("/me ")
|
||||
if let wysiwygInputToolbar, wysiwygInputToolbar.textFormattingEnabled {
|
||||
wysiwygInputToolbar.mention(roomMember)
|
||||
wysiwygInputToolbar.becomeFirstResponder()
|
||||
} else {
|
||||
if #available(iOS 15.0, *) {
|
||||
newAttributedString.append(PillsFormatter.mentionPill(withRoomMember: roomMember,
|
||||
isHighlighted: false,
|
||||
font: inputToolbar.textDefaultFont))
|
||||
} else {
|
||||
newAttributedString.appendString(roomMember.displayname.count > 0 ? roomMember.displayname : roomMember.userId)
|
||||
}
|
||||
newAttributedString.appendString(": ")
|
||||
}
|
||||
guard let attributedText = inputToolbarView.attributedTextMessage else { return }
|
||||
let newAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||
|
||||
inputToolbar.attributedTextMessage = newAttributedString
|
||||
inputToolbar.becomeFirstResponder()
|
||||
if attributedText.length > 0 {
|
||||
if #available(iOS 15.0, *) {
|
||||
newAttributedString.append(PillsFormatter.mentionPill(withRoomMember: roomMember,
|
||||
isHighlighted: false,
|
||||
font: inputToolbarView.defaultFont))
|
||||
} else {
|
||||
newAttributedString.appendString(roomMember.displayname.count > 0 ? roomMember.displayname : roomMember.userId)
|
||||
}
|
||||
newAttributedString.appendString(" ")
|
||||
} else if roomMember.userId == self.mainSession.myUser.userId {
|
||||
newAttributedString.appendString("/me ")
|
||||
newAttributedString.addAttribute(.font,
|
||||
value: inputToolbarView.defaultFont,
|
||||
range: .init(location: 0, length: newAttributedString.length))
|
||||
} else {
|
||||
if #available(iOS 15.0, *) {
|
||||
newAttributedString.append(PillsFormatter.mentionPill(withRoomMember: roomMember,
|
||||
isHighlighted: false,
|
||||
font: inputToolbarView.defaultFont))
|
||||
} else {
|
||||
newAttributedString.appendString(roomMember.displayname.count > 0 ? roomMember.displayname : roomMember.userId)
|
||||
}
|
||||
newAttributedString.appendString(": ")
|
||||
}
|
||||
|
||||
inputToolbarView.attributedTextMessage = newAttributedString
|
||||
inputToolbarView.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func setCommand(_ command: String) {
|
||||
if let wysiwygInputToolbar, wysiwygInputToolbar.textFormattingEnabled {
|
||||
wysiwygInputToolbar.command(command)
|
||||
wysiwygInputToolbar.becomeFirstResponder()
|
||||
} else {
|
||||
guard let attributedText = inputToolbarView.attributedTextMessage else { return }
|
||||
|
||||
let newAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||
newAttributedString.append(NSAttributedString(string: "\(command) ",
|
||||
attributes: [.font: inputToolbarView.defaultFont]))
|
||||
|
||||
inputToolbarView.attributedTextMessage = newAttributedString
|
||||
inputToolbarView.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Send the formatted text message and its raw counterpat to the room
|
||||
/// Send the formatted text message and its raw counterpart to the room
|
||||
///
|
||||
/// - Parameter rawTextMsg: the raw text message
|
||||
/// - Parameter htmlMsg: the html text message
|
||||
@@ -85,7 +107,7 @@ extension RoomViewController {
|
||||
"event_id": eventModified.eventId
|
||||
])
|
||||
})
|
||||
} else if !self.send(asIRCStyleCommandIfPossible: rawTextMsg) {
|
||||
} else {
|
||||
roomDataSource.sendFormattedTextMessage(rawTextMsg, html: htmlMsg) { response in
|
||||
switch response {
|
||||
case .success:
|
||||
@@ -369,6 +391,48 @@ extension RoomViewController: ComposerLinkActionBridgePresenterDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - PermalinkReplacer
|
||||
extension RoomViewController: PermalinkReplacer {
|
||||
public func replacementForLink(_ url: String, text: String) -> NSAttributedString? {
|
||||
guard #available(iOS 15.0, *),
|
||||
let url = URL(string: url),
|
||||
let session = roomDataSource.mxSession,
|
||||
let eventFormatter = roomDataSource.eventFormatter,
|
||||
let roomState = roomDataSource.roomState else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return PillsFormatter.mentionPill(withUrl: url,
|
||||
andLabel: text,
|
||||
session: session,
|
||||
eventFormatter: eventFormatter,
|
||||
roomState: roomState)
|
||||
}
|
||||
|
||||
public func postProcessMarkdown(in attributedString: NSAttributedString) -> NSAttributedString {
|
||||
guard #available(iOS 15.0, *),
|
||||
let roomDataSource,
|
||||
let session = roomDataSource.mxSession,
|
||||
let eventFormatter = roomDataSource.eventFormatter,
|
||||
let roomState = roomDataSource.roomState else {
|
||||
return attributedString
|
||||
}
|
||||
return PillsFormatter.insertPills(in: attributedString,
|
||||
withSession: session,
|
||||
eventFormatter: eventFormatter,
|
||||
roomState: roomState,
|
||||
font: inputToolbarView.defaultFont)
|
||||
}
|
||||
|
||||
public func restoreMarkdown(in attributedString: NSAttributedString) -> String {
|
||||
if #available(iOS 15.0, *) {
|
||||
return PillsFormatter.stringByReplacingPills(in: attributedString, mode: .markdown)
|
||||
} else {
|
||||
return attributedString.string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - VoiceBroadcast
|
||||
extension RoomViewController {
|
||||
@objc func stopUncompletedVoiceBroadcastIfNeeded() {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -13,6 +12,8 @@
|
||||
<connections>
|
||||
<outlet property="bubblesTableView" destination="BGD-sd-SQR" id="OG4-Tw-Ovt"/>
|
||||
<outlet property="bubblesTableViewBottomConstraint" destination="1SD-y2-oTg" id="n8D-hT-eqt"/>
|
||||
<outlet property="completionSuggestionContainerHeightConstraint" destination="1Cd-cT-gOr" id="au5-3q-r54"/>
|
||||
<outlet property="completionSuggestionContainerView" destination="oni-F4-X1U" id="0js-Ji-8Mm"/>
|
||||
<outlet property="inputBackgroundView" destination="Xt7-83-dQh" id="xoG-eb-zFB"/>
|
||||
<outlet property="jumpToLastUnreadBanner" destination="S6r-bo-jxw" id="FSS-Be-E15"/>
|
||||
<outlet property="jumpToLastUnreadBannerContainer" destination="S6H-Az-RCM" id="YlI-fu-OpT"/>
|
||||
@@ -32,13 +33,12 @@
|
||||
<outlet property="scrollToBottomBadgeLabel" destination="QHs-rM-UU8" id="wk7-PQ-9Jm"/>
|
||||
<outlet property="scrollToBottomButton" destination="Ih9-EU-BOU" id="Wwg-gS-Sfp"/>
|
||||
<outlet property="topBannersStackView" destination="3z2-8P-wlg" id="uf5-gw-zWi"/>
|
||||
<outlet property="userSuggestionContainerHeightConstraint" destination="1Cd-cT-gOr" id="au5-3q-r54"/>
|
||||
<outlet property="userSuggestionContainerView" destination="oni-F4-X1U" id="0js-Ji-8Mm"/>
|
||||
<outlet property="view" destination="iN0-l3-epB" id="ieV-u7-rXU"/>
|
||||
<outletCollection property="toolbarContainerConstraints" destination="T1Y-r9-bYV" id="wax-9P-KGn"/>
|
||||
<outletCollection property="toolbarContainerConstraints" destination="pRw-S0-6WL" id="q4S-0g-sqQ"/>
|
||||
<outletCollection property="toolbarContainerConstraints" destination="QO8-nF-xys" id="aQe-20-4Pq"/>
|
||||
<outletCollection property="toolbarContainerConstraints" destination="acJ-g8-R7x" id="uEo-Ez-seV"/>
|
||||
<outletCollection property="toolbarContainerConstraints" destination="ave-fu-X1D" id="xfF-6Q-MDo"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
@@ -47,20 +47,20 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="3z2-8P-wlg" userLabel="Top Banners Stack View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="0.0"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="0.0"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" priority="250" id="Y9P-Ek-wjg"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<tableView contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="BGD-sd-SQR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="626"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="606"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="RoomVCBubblesTableView"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</tableView>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="54r-18-K1g">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="368"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="368"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="RoomVCPreviewHeaderContainer"/>
|
||||
<constraints>
|
||||
@@ -68,7 +68,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="fmF-ad-erE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="0.0"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="0.0"/>
|
||||
<subviews>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hB3-nR-MVR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="54"/>
|
||||
@@ -188,7 +188,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gt1-EO-UVY">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
@@ -236,11 +236,6 @@
|
||||
<point key="canvasLocation" x="136.80000000000001" y="152.47376311844079"/>
|
||||
</view>
|
||||
</objects>
|
||||
<designables>
|
||||
<designable name="QHs-rM-UU8">
|
||||
<size key="intrinsicContentSize" width="7.5" height="13.5"/>
|
||||
</designable>
|
||||
</designables>
|
||||
<resources>
|
||||
<image name="new_close" width="16" height="16"/>
|
||||
<image name="room_scroll_up" width="24" height="24"/>
|
||||
|
||||
@@ -132,6 +132,8 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
{
|
||||
// The updated user data
|
||||
NSMutableDictionary<NSString*, id> *updatedItemsDict;
|
||||
// bwi #4743: remove room avatar
|
||||
BOOL shouldRemoveRoomAvatarImage;
|
||||
|
||||
// The current table items
|
||||
UITextField* nameTextField;
|
||||
@@ -1342,7 +1344,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
[self dismissFirstResponder];
|
||||
|
||||
// Check whether some changes have been done
|
||||
if (updatedItemsDict.count)
|
||||
if (updatedItemsDict.count|| shouldRemoveRoomAvatarImage)
|
||||
{
|
||||
[self promptUserToSaveChanges];
|
||||
}
|
||||
@@ -1408,7 +1410,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
|
||||
- (IBAction)onSave:(id)sender
|
||||
{
|
||||
if (updatedItemsDict.count)
|
||||
if (updatedItemsDict.count || shouldRemoveRoomAvatarImage)
|
||||
{
|
||||
[self startActivityIndicator];
|
||||
|
||||
@@ -1417,6 +1419,43 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
// check if there is some updates related to room state
|
||||
if (mxRoomState)
|
||||
{
|
||||
// bwi #4743: remove room avatar
|
||||
if (shouldRemoveRoomAvatarImage) {
|
||||
shouldRemoveRoomAvatarImage = false;
|
||||
[updatedItemsDict removeObjectForKey:kRoomSettingsAvatarKey];
|
||||
// delete room avatar
|
||||
pendingOperation = [mxRoom sendStateEventOfType:kMXEventTypeStringRoomAvatar content:@{} stateKey:@"" success:^(NSString *eventId) {
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
self->pendingOperation = nil;
|
||||
|
||||
[self onSave:nil];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
MXLogDebug(@"[RoomSettingsViewController] reset image failed");
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
self->pendingOperation = nil;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
NSString* message = error.localizedDescription;
|
||||
if (!message.length)
|
||||
{
|
||||
message = [VectorL10n roomDetailsFailToUpdateAvatar];
|
||||
}
|
||||
[self onSaveFailed:message withKeys:@[kRoomSettingsAvatarKey]];
|
||||
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
if (updatedItemsDict[kRoomSettingsAvatarKey])
|
||||
{
|
||||
// Retrieve the current picture and make sure its orientation is up
|
||||
@@ -2226,6 +2265,11 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
{
|
||||
roomPhotoCell.mxkImageView.image = (UIImage*) updatedItemsDict[kRoomSettingsAvatarKey];
|
||||
}
|
||||
else if (shouldRemoveRoomAvatarImage) {
|
||||
// bwi #4743: remove room avatar
|
||||
NSString *roomName = mxRoom.summary.displayName;
|
||||
roomPhotoCell.mxkImageView.image = [AvatarGenerator generateAvatarForMatrixItem:mxRoom.roomId withDisplayName:roomName];
|
||||
}
|
||||
else
|
||||
{
|
||||
// bwi if the room is a personal notes room use a local image
|
||||
@@ -3254,6 +3298,8 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
if (!mxRoom.isDirect || BWIBuildSettings.shared.showUnrelatedRoomSettingsForDirectMessages) {
|
||||
SingleImagePickerPresenter *singleImagePickerPresenter = [[SingleImagePickerPresenter alloc] initWithSession:self.mainSession];
|
||||
singleImagePickerPresenter.delegate = self;
|
||||
// bwi #4743: remove room avatar
|
||||
singleImagePickerPresenter.allowsRemoveImage = (updatedItemsDict[kRoomSettingsAvatarKey] != nil || (mxRoom.summary.avatar != nil && ![mxRoom.summary.avatar isEqual: @""]));
|
||||
|
||||
UIView *sourceView;
|
||||
|
||||
@@ -3679,6 +3725,12 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
// This method should never be called here because room settings should not show the remove image option. But nevertheless we do a nice cleanup also for this delegate call
|
||||
[presenter dismissWithAnimated:YES completion:nil];
|
||||
self.imagePickerPresenter = nil;
|
||||
|
||||
// bwi #4743: the room avatar should be removable
|
||||
[updatedItemsDict removeObjectForKey:kRoomSettingsAvatarKey];
|
||||
shouldRemoveRoomAvatarImage = true;
|
||||
[self getNavigationItem].rightBarButtonItem.enabled = YES;
|
||||
[self refreshRoomSettings];
|
||||
}
|
||||
|
||||
#pragma mark - TableViewSectionsDelegate
|
||||
|
||||
@@ -165,6 +165,11 @@ class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
|
||||
roomCellContentView.didTapAddParticipants = { [weak self] in
|
||||
self?.notifyDelegate(with: RoomCreationIntroCell.tapOnAddParticipants)
|
||||
}
|
||||
|
||||
self.accessibilityElements = [roomCellContentView.roomAvatarView as Any,
|
||||
roomCellContentView.titleLabel as Any,
|
||||
roomCellContentView.informationLabel as Any,
|
||||
roomCellContentView.addParticipantsContainerView as Any]
|
||||
}
|
||||
|
||||
|
||||
|
||||
+14
-7
@@ -70,8 +70,10 @@ final class RoomCreationIntroCellContentView: UIView, NibLoadable, Themable {
|
||||
|
||||
self.addParticipantsButton.layer.masksToBounds = true
|
||||
self.addParticipantsButton.addTarget(self, action: #selector(socialButtonAction(_:)), for: .touchUpInside)
|
||||
self.addParticipantsButton.accessibilityLabel = VectorL10n.roomIntroCellAddParticipantsAction
|
||||
|
||||
self.addParticipantsLabel.text = VectorL10n.roomIntroCellAddParticipantsAction
|
||||
self.addParticipantsLabel.isAccessibilityElement = false
|
||||
|
||||
self.roomAvatarView.showCameraBadgeOnFallbackImage = true
|
||||
}
|
||||
@@ -161,10 +163,17 @@ final class RoomCreationIntroCellContentView: UIView, NibLoadable, Themable {
|
||||
if let topic = topic, topic.isEmpty == false {
|
||||
attributedString.append(NSAttributedString(string: VectorL10n.roomIntroCellInformationRoomWithTopicSentence2(topic), attributes: informationTextDefaultAttributes))
|
||||
} else {
|
||||
let secondSentencePart1 = NSAttributedString(string: VectorL10n.roomIntroCellInformationRoomWithoutTopicSentence2Part1, attributes: [.foregroundColor: self.theme.tintColor])
|
||||
let secondSentencePart2 = NSAttributedString(string: VectorL10n.roomIntroCellInformationRoomWithoutTopicSentence2Part2, attributes: informationTextDefaultAttributes)
|
||||
attributedString.append(secondSentencePart1)
|
||||
attributedString.append(secondSentencePart2)
|
||||
if BWIBuildSettings.shared.useNewBumColors {
|
||||
let secondSentencePart1 = NSAttributedString(string: VectorL10n.roomIntroCellInformationRoomWithoutTopicSentence2Part1, attributes: [.foregroundColor: self.theme.tintColor, .font: self.theme.fonts.bodySB]) // bwi: 4769
|
||||
let secondSentencePart2 = NSAttributedString(string: VectorL10n.roomIntroCellInformationRoomWithoutTopicSentence2Part2, attributes: informationTextDefaultAttributes)
|
||||
attributedString.append(secondSentencePart1)
|
||||
attributedString.append(secondSentencePart2)
|
||||
} else {
|
||||
let secondSentencePart1 = NSAttributedString(string: VectorL10n.roomIntroCellInformationRoomWithoutTopicSentence2Part1, attributes: [.foregroundColor: self.theme.tintColor])
|
||||
let secondSentencePart2 = NSAttributedString(string: VectorL10n.roomIntroCellInformationRoomWithoutTopicSentence2Part2, attributes: informationTextDefaultAttributes)
|
||||
attributedString.append(secondSentencePart1)
|
||||
attributedString.append(secondSentencePart2)
|
||||
}
|
||||
}
|
||||
|
||||
return attributedString
|
||||
@@ -182,9 +191,7 @@ final class RoomCreationIntroCellContentView: UIView, NibLoadable, Themable {
|
||||
attributedString.append(firstSentencePart2)
|
||||
attributedString.append(firstSentencePart3)
|
||||
|
||||
if isDirect {
|
||||
attributedString.append(NSAttributedString(string: VectorL10n.roomIntroCellInformationDmSentence2, attributes: informationTextDefaultAttributes))
|
||||
} else {
|
||||
if !isDirect {
|
||||
attributedString.append(NSAttributedString(string: VectorL10n.roomIntroCellInformationMultipleDmSentence2, attributes: informationTextDefaultAttributes))
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -35,6 +35,15 @@ class TextMessageOutgoingWithoutSenderInfoBubbleCell: TextMessageBaseBubbleCell,
|
||||
self.textMessageContentView?.bubbleBackgroundView?.backgroundColor = theme.roomCellOutgoingBubbleBackgroundColor
|
||||
}
|
||||
|
||||
override func render(_ cellData: MXKCellData!) {
|
||||
// This cell displays an outgoing message without any sender information.
|
||||
// However, we need to set the following properties to our cellData, otherwise, to make room for the timestamp, a whitespace could be added when calculating the position of the components.
|
||||
// If we don't, the component frame calculation will not work for this cell.
|
||||
(cellData as? RoomBubbleCellData)?.shouldHideSenderName = false
|
||||
(cellData as? RoomBubbleCellData)?.shouldHideSenderInformation = false
|
||||
super.render(cellData)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupBubbleConstraints() {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
class RoomInputToolbarTextView: UITextView {
|
||||
|
||||
private var heightConstraint: NSLayoutConstraint!
|
||||
private var pillViews = [UIView]()
|
||||
|
||||
weak var toolbarDelegate: RoomInputToolbarTextViewDelegate?
|
||||
|
||||
@@ -51,12 +52,18 @@ class RoomInputToolbarTextView: UITextView {
|
||||
}
|
||||
|
||||
override var text: String! {
|
||||
willSet {
|
||||
flushPills()
|
||||
}
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
override var attributedText: NSAttributedString! {
|
||||
willSet {
|
||||
flushPills()
|
||||
}
|
||||
didSet {
|
||||
updateUI()
|
||||
}
|
||||
@@ -162,3 +169,17 @@ class RoomInputToolbarTextView: UITextView {
|
||||
delegate.onTouchUp(inside: delegate.rightInputToolbarButton)
|
||||
}
|
||||
}
|
||||
|
||||
extension RoomInputToolbarTextView: PillViewFlusher {
|
||||
func registerPillView(_ pillView: UIView) {
|
||||
pillViews.append(pillView)
|
||||
}
|
||||
|
||||
private func flushPills() {
|
||||
for view in pillViews {
|
||||
view.alpha = 0.0
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
pillViews.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
@class RoomActionsBar;
|
||||
@class RoomInputToolbarView;
|
||||
@class LinkActionWrapper;
|
||||
@class SuggestionPatternWrapper;
|
||||
@class CompletionSuggestionViewModelContextWrapper;
|
||||
|
||||
/**
|
||||
Destination of the message in the composer
|
||||
@@ -59,7 +61,7 @@ typedef NS_ENUM(NSUInteger, RoomInputToolbarViewSendMode)
|
||||
|
||||
@param toolbarView the room input toolbar view
|
||||
*/
|
||||
- (void)roomInputToolbarViewDidChangeTextMessage:(RoomInputToolbarView*)toolbarView;
|
||||
- (void)roomInputToolbarViewDidChangeTextMessage:(MXKRoomInputToolbarView*)toolbarView;
|
||||
|
||||
/**
|
||||
Inform the delegate that the action menu was opened.
|
||||
@@ -80,6 +82,12 @@ typedef NS_ENUM(NSUInteger, RoomInputToolbarViewSendMode)
|
||||
|
||||
- (void)didSendLinkAction: (LinkActionWrapper *)linkAction;
|
||||
|
||||
- (void)didDetectTextPattern: (SuggestionPatternWrapper *)suggestionPattern;
|
||||
|
||||
- (CompletionSuggestionViewModelContextWrapper *)completionSuggestionContext;
|
||||
|
||||
- (MXMediaManager *)mediaManager;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
@@ -128,8 +136,6 @@ typedef NS_ENUM(NSUInteger, RoomInputToolbarViewSendMode)
|
||||
*/
|
||||
@property (nonatomic, weak, readonly) UIButton *attachMediaButton;
|
||||
|
||||
@property (nonatomic, readonly, nonnull) UIFont *textDefaultFont;
|
||||
|
||||
/**
|
||||
Adds a voice message toolbar view to be displayed inside this input toolbar
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user