diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index f170a1fd1..88458a696 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -57,8 +57,9 @@ body:
id: homeserver
attributes:
label: Homeserver
- description: Which server is your account registered on?
- placeholder: e.g. matrix.org
+ description: |
+ Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
+ placeholder: e.g. matrix.org or Synapse 1.50.0rc1
validations:
required: false
- type: dropdown
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 68a169237..24e8ab2e6 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -11,7 +11,6 @@ on:
env:
# Make the git branch for a PR available to our Fastfile
MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }}
- MapTilerAPIKey: ${{ secrets.MAPTILER_API_KEY }}
jobs:
build:
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index 3fcc19ed3..00d4fa2f9 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -12,7 +12,6 @@ on:
env:
# Make the git branch for a PR available to our Fastfile
MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }}
- MapTilerAPIKey: ${{ secrets.MAPTILER_API_KEY }}
jobs:
tests:
diff --git a/.github/workflows/release-alpha.yml b/.github/workflows/release-alpha.yml
index 7ab8b331d..dfbd7ac6a 100644
--- a/.github/workflows/release-alpha.yml
+++ b/.github/workflows/release-alpha.yml
@@ -11,7 +11,6 @@ on:
env:
# Make the git branch for a PR available to our Fastfile
MX_GIT_BRANCH: ${{ github.event.pull_request.head.ref }}
- MapTilerAPIKey: ${{ secrets.MAPTILER_API_KEY }}
jobs:
build:
diff --git a/CHANGES.md b/CHANGES.md
index 8c2112418..c5c23b33f 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,35 @@
+## Changes in 1.7.0 (2022-01-25)
+
+✨ Features
+
+- Message bubbles: Text message layout. ([#5208](https://github.com/vector-im/element-ios/issues/5208))
+- Message Bubbles: Layout for Media. ([#5209](https://github.com/vector-im/element-ios/issues/5209))
+- Message Bubbles: Support URL Previews. ([#5212](https://github.com/vector-im/element-ios/issues/5212))
+- Message Bubbles: Support reactions. ([#5214](https://github.com/vector-im/element-ios/issues/5214))
+- Added static location sharing sending and rendering support. ([#5298](https://github.com/vector-im/element-ios/issues/5298))
+- Message bubbles: Add settings and build flag. ([#5321](https://github.com/vector-im/element-ios/issues/5321))
+
+🙌 Improvements
+
+- Upgrade MatrixSDK version ([v0.21.0](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.21.0)).
+- Using mutable room list fetch sort options after chaning them to be a structure. Adaptation to MXStore api changes. ([#4384](https://github.com/vector-im/element-ios/issues/4384))
+- Reduce grace period to report decryption failure ([#5345](https://github.com/vector-im/element-ios/issues/5345))
+
+🐛 Bugfixes
+
+- Fixed home screen not updating properly on theme changes. ([#4208](https://github.com/vector-im/element-ios/issues/4208))
+- Fixes DTMF(dial tones) during voice calls. ([#5375](https://github.com/vector-im/element-ios/issues/5375))
+- Fix crash when uploading a video on iPad when "Confirm size when sending" is enabled in settings. ([#5399](https://github.com/vector-im/element-ios/issues/5399))
+- Fix BuildSetting to show/hide the "Invite Friends" button in the side SideMenu. ([#5402](https://github.com/vector-im/element-ios/issues/5402))
+- Add BuildSetting to hide social login in favour of the simple SSO button. ([#5404](https://github.com/vector-im/element-ios/issues/5404))
+- Fix grey spinner showing indefinitely over the home view after launch. ([#5407](https://github.com/vector-im/element-ios/issues/5407))
+- RecentsViewController: Update tab bar badges on section-only updates. ([#5421](https://github.com/vector-im/element-ios/issues/5421))
+
+Others
+
+- Fix graphql warnings in issue workflow automation ([#5294](https://github.com/vector-im/element-ios/issues/5294))
+
+
## Changes in 1.6.12 (2022-01-11)
🙌 Improvements
diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig
index f0f3b8161..cc05f87f8 100644
--- a/Config/AppVersion.xcconfig
+++ b/Config/AppVersion.xcconfig
@@ -15,5 +15,5 @@
//
// Version
-MARKETING_VERSION = 1.6.13
-CURRENT_PROJECT_VERSION = 1.6.13
+MARKETING_VERSION = 1.7.1
+CURRENT_PROJECT_VERSION = 1.7.1
diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift
index 98483d53f..3f3e1c15c 100644
--- a/Config/BuildSettings.swift
+++ b/Config/BuildSettings.swift
@@ -15,7 +15,6 @@
//
import Foundation
-import Keys
/// BuildSettings provides settings computed at build time.
/// In future, it may be automatically generated from xcconfig files
@@ -213,8 +212,10 @@ final class BuildSettings: NSObject {
static let allowInviteExernalUsers: Bool = true
+ // MARK: - Side Menu
static let enableSideMenu: Bool = true
-
+ static let sideMenuShowInviteFriends: Bool = true
+
/// Whether to read the `io.element.functional_members` state event and exclude any service members when computing a room's name and avatar.
static let supportFunctionalMembers: Bool = true
@@ -261,7 +262,6 @@ final class BuildSettings: NSObject {
static let settingsScreenAllowBugReportingManually: Bool = true
static let settingsScreenAllowDeactivatingAccount: Bool = true
static let settingsScreenShowChangePassword:Bool = true
- static let settingsScreenShowInviteFriends:Bool = true
static let settingsScreenShowEnableStunServerFallback: Bool = true
static let settingsScreenShowNotificationDecodedContentOption: Bool = true
static let settingsScreenShowNsfwRoomsOption: Bool = true
@@ -349,6 +349,7 @@ final class BuildSettings: NSObject {
static let authScreenShowPhoneNumber = true
static let authScreenShowForgotPassword = true
static let authScreenShowCustomServerOptions = true
+ static let authScreenShowSocialLoginSection = true
// MARK: - Unified Search
static let unifiedSearchScreenShowPublicDirectory = true
@@ -368,7 +369,7 @@ final class BuildSettings: NSObject {
// MARK: - Location Sharing
- static let tileServerMapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=" + RiotKeys().mapTilerAPIKey)!
+ static let tileServerMapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx")!
static var locationSharingEnabled: Bool {
guard #available(iOS 14, *) else {
diff --git a/Gemfile b/Gemfile
index ea061a17e..53efbaf92 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,7 +3,6 @@ source "https://rubygems.org"
gem "xcode-install"
gem "fastlane"
gem "cocoapods", '~>1.11.2'
-gem "cocoapods-keys"
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)
diff --git a/Gemfile.lock b/Gemfile.lock
index 78fe028a3..610cbbadd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -3,9 +3,6 @@ GEM
specs:
CFPropertyList (3.0.5)
rexml
- RubyInline (3.12.5)
- ZenTest (~> 4.3)
- ZenTest (4.12.0)
activesupport (6.1.4.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
@@ -67,9 +64,6 @@ GEM
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.5.1)
- cocoapods-keys (2.2.1)
- dotenv
- osx_keychain
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
@@ -231,8 +225,6 @@ GEM
netrc (0.11.0)
optparse (0.1.1)
os (1.1.4)
- osx_keychain (1.0.2)
- RubyInline (~> 3)
plist (3.6.0)
public_suffix (4.0.6)
rake (13.0.6)
@@ -300,7 +292,6 @@ PLATFORMS
DEPENDENCIES
cocoapods (~> 1.11.2)
- cocoapods-keys
fastlane
fastlane-plugin-diawi
fastlane-plugin-versioning
@@ -308,4 +299,4 @@ DEPENDENCIES
xcode-install
BUNDLED WITH
- 2.2.28
+ 2.2.32
diff --git a/Podfile b/Podfile
index 6a5620b94..495a84db4 100644
--- a/Podfile
+++ b/Podfile
@@ -13,7 +13,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.20.16'
+$matrixSDKVersion = '= 0.21.0'
# $matrixSDKVersion = :local
# $matrixSDKVersion = { :branch => 'develop'}
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }
@@ -129,11 +129,6 @@ abstract_target 'RiotPods' do
end
-plugin 'cocoapods-keys', {
- :project => "Riot",
- :keys => ["MapTilerAPIKey"]
-}
-
post_install do |installer|
installer.pods_project.targets.each do |target|
diff --git a/Podfile.lock b/Podfile.lock
index 749fe065f..366d83a2e 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -49,7 +49,6 @@ PODS:
- Introspect (0.1.3)
- JitsiMeetSDK (3.10.2)
- KeychainAccess (4.2.2)
- - Keys (1.0.1)
- KituraContracts (1.2.1):
- LoggerAPI (~> 1.7)
- KTCenterFlowLayout (1.3.1)
@@ -58,16 +57,16 @@ PODS:
- LoggerAPI (1.9.200):
- Logging (~> 1.1)
- Logging (1.4.0)
- - MatrixSDK (0.20.16):
- - MatrixSDK/Core (= 0.20.16)
- - MatrixSDK/Core (0.20.16):
+ - MatrixSDK (0.21.0):
+ - MatrixSDK/Core (= 0.21.0)
+ - MatrixSDK/Core (0.21.0):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.3.0)
- libbase58 (~> 0.1.4)
- OLMKit (~> 3.2.5)
- Realm (= 10.16.0)
- SwiftyBeaver (= 1.9.5)
- - MatrixSDK/JingleCallStack (0.20.16):
+ - MatrixSDK/JingleCallStack (0.21.0):
- JitsiMeetSDK (= 3.10.2)
- MatrixSDK/Core
- OLMKit (3.2.5):
@@ -115,11 +114,10 @@ DEPENDENCIES:
- HPGrowingTextView (~> 1.1)
- Introspect (~> 0.1)
- KeychainAccess (~> 4.2.2)
- - Keys (from `Pods/CocoaPodsKeys`)
- KTCenterFlowLayout (~> 1.3.1)
- libPhoneNumber-iOS (~> 0.9.13)
- - MatrixSDK (= 0.20.16)
- - MatrixSDK/JingleCallStack (= 0.20.16)
+ - MatrixSDK (= 0.21.0)
+ - MatrixSDK/JingleCallStack (= 0.21.0)
- OLMKit
- PostHog (~> 1.4.4)
- ReadMoreTextView (~> 3.0.1)
@@ -179,12 +177,10 @@ EXTERNAL SOURCES:
AnalyticsEvents:
:branch: release/swift
:git: https://github.com/matrix-org/matrix-analytics-events.git
- Keys:
- :path: Pods/CocoaPodsKeys
CHECKOUT OPTIONS:
AnalyticsEvents:
- :commit: f1805ad7c3fafa7fd9c6e2eaa9e0165f8142ecd2
+ :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c
:git: https://github.com/matrix-org/matrix-analytics-events.git
SPEC CHECKSUMS:
@@ -207,14 +203,13 @@ SPEC CHECKSUMS:
Introspect: 2be020f30f084ada52bb4387fff83fa52c5c400e
JitsiMeetSDK: 2f118fa770f23e518f3560fc224fae3ac7062223
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
- Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9
KituraContracts: e845e60dc8627ad0a76fa55ef20a45451d8f830b
KTCenterFlowLayout: 6e02b50ab2bd865025ae82fe266ed13b6d9eaf97
libbase58: 7c040313537b8c44b6e2d15586af8e21f7354efd
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
Logging: beeb016c9c80cf77042d62e83495816847ef108b
- MatrixSDK: af6a70532bb43af59f43a1f4dae512a26afeab0b
+ MatrixSDK: cd98e3e4287b8a4f3a5bb47642beae80e8f62534
OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5
PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
@@ -230,6 +225,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
-PODFILE CHECKSUM: 2493587902f8f28bb2638303dd583c47e9f24d8b
+PODFILE CHECKSUM: 39329dd448eb0ad10c396f84f854a18962ab1fc4
COCOAPODS: 1.11.2
diff --git a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Contents.json
index 32dd965fb..d2c033d2d 100644
--- a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Contents.json
+++ b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Contents.json
@@ -1,17 +1,17 @@
{
"images" : [
{
- "filename" : "Vector.png",
+ "filename" : "Thread.png",
"idiom" : "universal",
"scale" : "1x"
},
{
- "filename" : "Vector@2x.png",
+ "filename" : "Thread@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
- "filename" : "Vector@3x.png",
+ "filename" : "Thread@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
@@ -19,8 +19,5 @@
"info" : {
"author" : "xcode",
"version" : 1
- },
- "properties" : {
- "template-rendering-intent" : "original"
}
}
diff --git a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread.png b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread.png
new file mode 100644
index 000000000..632a63307
Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread.png differ
diff --git a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread@2x.png b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread@2x.png
new file mode 100644
index 000000000..dcd35cf62
Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread@2x.png differ
diff --git a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread@3x.png b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread@3x.png
new file mode 100644
index 000000000..32d13c5db
Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Thread@3x.png differ
diff --git a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector.png b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector.png
deleted file mode 100644
index 38cd35e5f..000000000
Binary files a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector.png and /dev/null differ
diff --git a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector@2x.png b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector@2x.png
deleted file mode 100644
index dc6713ff5..000000000
Binary files a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector@2x.png and /dev/null differ
diff --git a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector@3x.png b/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector@3x.png
deleted file mode 100644
index 11067906e..000000000
Binary files a/Riot/Assets/Images.xcassets/Room/ContextMenu/room_context_menu_thread.imageset/Vector@3x.png and /dev/null differ
diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_marker_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/Location/location_marker_icon.imageset/Contents.json
index 707b2f06b..0bf02ac7f 100644
--- a/Riot/Assets/Images.xcassets/Room/Location/location_marker_icon.imageset/Contents.json
+++ b/Riot/Assets/Images.xcassets/Room/Location/location_marker_icon.imageset/Contents.json
@@ -19,5 +19,8 @@
"info" : {
"author" : "xcode",
"version" : 1
+ },
+ "properties" : {
+ "template-rendering-intent" : "template"
}
}
diff --git a/Riot/Assets/cs.lproj/InfoPlist.strings b/Riot/Assets/cs.lproj/InfoPlist.strings
new file mode 100644
index 000000000..88c506408
--- /dev/null
+++ b/Riot/Assets/cs.lproj/InfoPlist.strings
@@ -0,0 +1,7 @@
+
+
+// Permissions usage explanations
+"NSCameraUsageDescription" = "Kamera slouží k focení, zachycení videí a k videohovorům.";
+"NSPhotoLibraryUsageDescription" = "Galerie se používá k posílání obrázků a videí.";
+"NSCalendarsUsageDescription" = "Zobrazuje události v aplikaci.";
+"NSFaceIDUsageDescription" = "Face ID se používá k přístupu do aplikace.";
diff --git a/Riot/Assets/cs.lproj/Localizable.strings b/Riot/Assets/cs.lproj/Localizable.strings
index 8b1378917..15e6ddbbf 100644
--- a/Riot/Assets/cs.lproj/Localizable.strings
+++ b/Riot/Assets/cs.lproj/Localizable.strings
@@ -1 +1,170 @@
+
+
+/** Reactions **/
+
+/* A user has reacted to a message, including the reaction e.g. "Alice reacted 👍". */
+"REACTION_FROM_USER" = "%@ reagoval/a %@";
+
+/* Look, stuff's happened, alright? Just open the app. */
+"MSGS_IN_TWO_PLUS_ROOMS" = "%@ nových zpráv v %@, %@ a dalších";
+
+/* Multiple messages in two rooms */
+"MSGS_IN_TWO_ROOMS" = "%@ nových zpráv v %@ a %@";
+
+/* Multiple unread messages from two plus people (ie. for 4+ people: 'others' replaces the third person) */
+"MSGS_FROM_TWO_PLUS_USERS" = "%@ nových zpráv od %@, %@ a dalších";
+
+/* Multiple unread messages from three people */
+"MSGS_FROM_THREE_USERS" = "%@ nových zpráv od %@, %@ a %@";
+
+/* Multiple unread messages from two people */
+"MSGS_FROM_TWO_USERS" = "%@ nových zpráv od %@ a %@";
+
+/* Multiple unread messages from a specific person, not referencing a room */
+"MSGS_FROM_USER" = "%@ nové zprávy od %@";
+
+/** Coalesced messages **/
+
+/* Multiple unread messages in a room */
+"UNREAD_IN_ROOM" = "%@ nové zprávy v %@";
+
+/* New message with hidden content due to PIN enabled */
+"MESSAGE_PROTECTED" = "Nová zpráva";
+
+/* New message indicator on a room */
+"MESSAGE_IN_X" = "Zpráva v %@";
+
+/* New message indicator from a DM */
+"MESSAGE_FROM_X" = "Zpráva od %@";
+
+/** Notification messages **/
+
+/* New message indicator on unknown room */
+"MESSAGE" = "Zpráva";
+
+/* Sticker from a specific person, not referencing a room. */
+"STICKER_FROM_USER" = "%@ poslal/a nálepku";
+
+/* A single unread message */
+"SINGLE_UNREAD" = "Dostali jste zprávu";
+
+/* A single unread message in a room */
+"SINGLE_UNREAD_IN_ROOM" = "V %@ vám přišla zpráva";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ sdílel/a svou polohu";
+
+/** Single, unencrypted messages (where we can include the content */
+
+/* New message from a specific person, not referencing a room. Content included. */
+"MSG_FROM_USER_WITH_CONTENT" = "%@: %@";
+
+/** Key verification **/
+
+"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ žádá o ověření";
+
+/* Group call from user, CallKit caller name */
+"GROUP_CALL_FROM_USER" = "%@ (Skupinový hovor)";
+
+/* A user added a Jitsi call to a room */
+"GROUP_CALL_STARTED" = "Začal skupinový hovor";
+
+/* Incoming named video conference invite from a specific person */
+"VIDEO_CONF_NAMED_FROM_USER" = "Skupinový videohovor od %@: '%@'";
+
+/* Incoming named voice conference invite from a specific person */
+"VOICE_CONF_NAMED_FROM_USER" = "Skupinový hovor od %@: '%@'";
+
+/* Incoming unnamed video conference invite from a specific person */
+"VIDEO_CONF_FROM_USER" = "Skupinový videohovor od %@";
+
+/* Incoming unnamed voice conference invite from a specific person */
+"VOICE_CONF_FROM_USER" = "Skupinový hovor od %@";
+
+/* Incoming one-to-one video call */
+"VIDEO_CALL_FROM_USER" = "Videohovor od %@";
+
+/** Calls **/
+
+/* Incoming one-to-one voice call */
+"VOICE_CALL_FROM_USER" = "Hovor od %@";
+
+/* A user's membership has updated in an unknown way */
+"USER_MEMBERSHIP_UPDATED" = "%@ aktualizoval/a svůj profil";
+
+/* A user has change their avatar */
+"USER_UPDATED_AVATAR" = "%@ změnil/a svůj avatar";
+
+/* A user has change their name to a new name which we don't know */
+"GENERIC_USER_UPDATED_DISPLAYNAME" = "%@ změnil/a svůj alias";
+
+/** Membership Updates **/
+
+/* A user has change their name to a new name */
+"USER_UPDATED_DISPLAYNAME" = "%@ změnil/a svůj alias na %@";
+
+/* A user has invited you to a named room */
+"USER_INVITE_TO_NAMED_ROOM" = "%@ vás pozval/a do %@";
+
+/* A user has invited you to an (unamed) group chat */
+"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ vás pozval/a ke skupinové konverzaci";
+
+/** Invites **/
+
+/* A user has invited you to a chat */
+"USER_INVITE_TO_CHAT" = "%@ vás pozval/a ke konverzaci";
+
+/* A user has reacted to a message, but the reaction content is unknown */
+"GENERIC_REACTION_FROM_USER" = "%@ poslal/a reakci";
+
+/* New message from a specific person in a named room */
+"MSG_FROM_USER_IN_ROOM" = "%@ něco zveřejnil v %@";
+
+/* New file message from a specific person, not referencing a room. */
+"FILE_FROM_USER" = "%@ poslal/a soubor %@";
+
+/* New voice message from a specific person, not referencing a room. */
+"VOICE_MESSAGE_FROM_USER" = "%@ poslal/a zvukový soubor";
+
+/* New audio message from a specific person, not referencing a room. */
+"AUDIO_FROM_USER" = "%@ poslal/a zvukový soubor %@";
+
+/* New video message from a specific person, not referencing a room. */
+"VIDEO_FROM_USER" = "%@ poslal/a video";
+
+/* New image message from a specific person in a named room. */
+"IMAGE_FROM_USER_IN_ROOM" = "%@ zveřejnil/a obrázek %@ v %@";
+
+/** Media Messages **/
+
+/* New image message from a specific person, not referencing a room. */
+"PICTURE_FROM_USER" = "%@ poslal/a obrázek";
+
+/* New action message from a specific person in a named room. */
+"ACTION_FROM_USER_IN_ROOM" = "%@: * %@ %@";
+
+/* New action message from a specific person, not referencing a room. */
+"ACTION_FROM_USER" = "* %@ %@";
+
+/* New message from a specific person in a named room. Content included. */
+"MSG_FROM_USER_IN_ROOM_WITH_CONTENT" = "%@ v %@: %@";
+
+/** Single, end-to-end encrypted messages (ie. we don't know what they say) */
+
+/* New message from a specific person, not referencing a room */
+"MSG_FROM_USER" = "%@ poslal/a zprávu";
+
+/* New message reply from a specific person in a named room. */
+"REPLY_FROM_USER_IN_ROOM_TITLE" = "%@ odpověděl/a v %@";
+
+/* New message reply from a specific person, not referencing a room. */
+"REPLY_FROM_USER_TITLE" = "%@ odpověděl/a";
+
+/** Titles **/
+
+/* Message title for a specific person in a named room */
+"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ v %@";
+/** General **/
+
+"NOTIFICATION" = "Oznámení";
diff --git a/Riot/Assets/de.lproj/InfoPlist.strings b/Riot/Assets/de.lproj/InfoPlist.strings
index 571d56f44..594fb19a0 100644
--- a/Riot/Assets/de.lproj/InfoPlist.strings
+++ b/Riot/Assets/de.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSContactsUsageDescription" = "Element zeigt deine Kontakte an, damit du sie zum chatten einladen kannst.";
"NSCalendarsUsageDescription" = "Sieh dir deine geplanten Meetings in der App an.";
"NSFaceIDUsageDescription" = "Face-ID wird zum Zugriff auf deine App verwendet.";
+"NSLocationWhenInUseUsageDescription" = "Wenn du deinen Standort mit Personen teilst, braucht Element Zugriff um ihnen eine Karte anzuzeigen.";
diff --git a/Riot/Assets/de.lproj/Localizable.strings b/Riot/Assets/de.lproj/Localizable.strings
index 3c7e1f066..a5edb4e62 100644
--- a/Riot/Assets/de.lproj/Localizable.strings
+++ b/Riot/Assets/de.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/* A user's membership has updated in an unknown way */
"USER_MEMBERSHIP_UPDATED" = "Profil von %@ geupdatet";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ hat den eigenen Standort geteilt";
diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings
index f0fb19fc2..df03d8813 100644
--- a/Riot/Assets/de.lproj/Vector.strings
+++ b/Riot/Assets/de.lproj/Vector.strings
@@ -136,12 +136,12 @@
"room_participants_action_section_other" = "Optionen";
"room_participants_action_invite" = "Einladen";
"room_participants_action_leave" = "Diesen Raum verlassen";
-"room_participants_action_remove" = "Von diesem Raum entfernen";
+"room_participants_action_remove" = "Aus diesem Raum entfernen";
"room_participants_action_ban" = "Aus diesem Raum bannen";
-"room_participants_action_ignore" = "Alle Nachrichten von diesem Nutzer verbergen";
-"room_participants_action_unignore" = "Zeige alle Nachrichten von diesem Nutzer";
-"room_participants_action_set_moderator" = "Gib Moderationsrechte";
-"room_participants_action_set_admin" = "Mache zum Administrator";
+"room_participants_action_ignore" = "Alle Nachrichten dieser Person verbergen";
+"room_participants_action_unignore" = "Alle Nachrichten dieser Person zeigen";
+"room_participants_action_set_moderator" = "Moderationsrechte vergeben";
+"room_participants_action_set_admin" = "Administrationsrechte vergeben";
"room_participants_action_start_new_chat" = "Starte neuen Chat";
"room_participants_action_start_video_call" = "Starte Video-Anruf";
"room_participants_action_mention" = "Erwähnen";
@@ -299,7 +299,7 @@
"room_participants_ago" = "her";
"room_participants_action_section_admin_tools" = "Admin-Werkzeuge";
"room_participants_action_unban" = "Entsperren";
-"room_participants_action_set_default_power_level" = "Zurück auf normale Berechtigung";
+"room_participants_action_set_default_power_level" = "Besondere Berechtigungen entziehen";
"room_participants_action_start_voice_call" = "Starte Sprach-Anruf";
"room_ongoing_conference_call" = "Laufender Konferenz-Anruf. Trete bei als %@ oder %@.";
"room_event_action_redact" = "Entfernen";
@@ -509,7 +509,7 @@
"room_action_send_photo_or_video" = "Foto oder Video senden";
"room_action_send_sticker" = "Aufkleber senden";
"settings_deactivate_account" = "DEAKTIVIERTES KONTO";
-"settings_deactivate_my_account" = "Benutzerkonto deaktiveren";
+"settings_deactivate_my_account" = "Mein Konto deaktivieren";
"widget_sticker_picker_no_stickerpacks_alert" = "Du hast aktuell keine Aufkleberpakete aktiviert.";
"widget_sticker_picker_no_stickerpacks_alert_add_now" = "Welche hinzufügen?";
// GDPR
@@ -544,12 +544,12 @@
"room_event_action_view_decrypted_source" = "Zeige entschlüsselten Quelltext";
"room_recents_server_notice_section" = "SYSTEMBENACHRICHTIGUNGEN";
"room_resource_limit_exceeded_message_contact_1" = " Bitte ";
-"room_resource_limit_exceeded_message_contact_2_link" = "kontaktiere deinen Dienst-Administrator";
+"room_resource_limit_exceeded_message_contact_2_link" = "kontaktiere deine Dienst-Administration";
"room_resource_limit_exceeded_message_contact_3" = " um diesen Dienst weiter zu nutzen.";
"homeserver_connection_lost" = "Konnte keine Verbindung zum Heimserver herstellen.";
"room_resource_usage_limit_reached_message_1_default" = "Dieser Heimserver hat eine seiner Ressourcengrenzen überschritten, sodass ";
-"room_resource_usage_limit_reached_message_1_monthly_active_user" = "Dieser Heimserver hat seine Begrenzung an monatlich aktiven Benutzern überschritten, sodass ";
-"room_resource_usage_limit_reached_message_2" = "einige Benutzer nicht in der Lage sein werden, sich anzumelden.";
+"room_resource_usage_limit_reached_message_1_monthly_active_user" = "Dieser Heimserver hat seine Grenze an monatlich aktiven Benutzenden erreicht, sodass ";
+"room_resource_usage_limit_reached_message_2" = "einige Benutzende nicht in der Lage sein werden, sich anzumelden.";
"room_resource_usage_limit_reached_message_contact_3" = " um diese Obergrenze erhöhen zu lassen.";
"auth_accept_policies" = "Bitte Regeln dieses Heimservers ansehen und akzeptieren:";
"settings_key_backup" = "SCHLÜSSEL-SICHERHEITSKOPIE";
@@ -634,13 +634,13 @@
"sign_out_existing_key_backup_alert_sign_out_action" = "Abmelden";
"sign_out_non_existing_key_backup_alert_title" = "Du verlierst den Zugriff auf deine verschlüsselten Nachrichten, wenn du dich jetzt abmeldest";
"sign_out_non_existing_key_backup_alert_setup_key_backup_action" = "Beginne Schlüsselsicherung zu nutzen";
-"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Ich möchte meine verschlüsselten Nachrichten nicht";
+"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Ich brauche meine verschlüsselten Nachrichten nicht";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_title" = "Du wirst deine verschlüsselten Nachrichten verlieren";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_message" = "Du verlierst den Zugriff auf deine verschlüsselten Nachrichten, es sei denn, du sicherst deine Schlüssel, bevor du dich abmeldest.";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_sign_out_action" = "Abmelden";
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_backup_action" = "Sicherungskopie";
"sign_out_key_backup_in_progress_alert_title" = "Schlüsselsicherung läuft. Wenn du dich jetzt abmeldest, verlierst du den Zugriff auf deine verschlüsselten Nachrichten.";
-"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Ich möchte meine verschlüsselten Nachrichten nicht";
+"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Ich brauche meine verschlüsselten Nachrichten nicht";
"sign_out_key_backup_in_progress_alert_cancel_action" = "Ich werde warten";
// Key backup wrong version
"e2e_key_backup_wrong_version_title" = "Neue Schlüsselsicherung";
@@ -734,7 +734,7 @@
"close" = "Schließen";
"auth_softlogout_signed_out" = "Du bist abgemeldet";
"auth_softlogout_sign_in" = "Anmelden";
-"auth_softlogout_reason" = "Deine Heimserver-Administrator (%1$@) hat dich von deinem Konto %2$@ (%3$@) abgemeldet.";
+"auth_softlogout_reason" = "Die Administration deines Heimservers (%1$@) hat dich von deinem Konto %2$@ (%3$@) abgemeldet.";
"auth_softlogout_recover_encryption_keys" = "Melde dich an, um ausschließlich auf diesem Gerät gespeicherte Verschlüsselungsschlüssel wiederherzustellen. Du benötigst sie, um deine verschlüsselten Nachrichten auf jedem Gerät zu lesen.";
"auth_softlogout_clear_data" = "Persönliche Daten löschen";
"auth_softlogout_clear_data_message_1" = "Warnung: Deine persönlichen Daten (einschließlich Verschlüsselungsschlüssel) sind noch auf diesem Gerät gespeichert.";
@@ -1002,10 +1002,10 @@
"security_settings_crosssigning_info_not_bootstrapped" = "Quersignierung ist bisher nicht konfiguriert.";
"room_member_power_level_admin_in" = "Admin in %@";
"room_member_power_level_moderator_in" = "Mod in %@";
-"room_member_power_level_custom_in" = "Benutzerdefiniert (%@) in %@";
+"room_member_power_level_custom_in" = "Selbstdefiniert (%@) in %@";
"room_member_power_level_short_admin" = "Admin";
"room_member_power_level_short_moderator" = "Mod";
-"room_member_power_level_short_custom" = "Benutzerdefiniert";
+"room_member_power_level_short_custom" = "Selbstdefiniert";
"security_settings_secure_backup" = "SICHERE SICHERHEITSKOPIE";
"security_settings_secure_backup_synchronise" = "Synchronisiere";
"security_settings_secure_backup_delete" = "Backup löschen";
@@ -1327,16 +1327,16 @@
"room_accessibility_video_call" = "Videoanruf";
"room_message_replying_to" = "%@ anworten";
"room_message_editing" = "Bearbeitung";
-"space_beta_announce_information" = "Spaces are a new way to group rooms and people. Bald werden sie auch auf iOS verfügbar sein, bis dahin kannst du sie schon auf %@ Web/Desktop testen.";
-"space_feature_unavailable_information" = "Wir haben Spaces entwickelt, damit ihr eure vielen Räume besser organisieren könnt.\n\nBald werden sie auch auf iOS verfügbar sein, bis dahin kannst du sie schon auf %@ Web/Desktop testen. Alle Räume die du dort betrittst, sind natürlich auch hier verfügbar.";
+"space_beta_announce_information" = "Spaces bieten neue Möglichkeiten um Räume und Personen zu gruppieren. Sie sind noch nicht auf iOS verfügbar, aber du kannst sie jetzt schon mit Web und Desktop nutzen.";
+"space_feature_unavailable_information" = "Spaces bieten neue Möglichkeiten um Räume und Personen zu gruppieren.\n\nBald werden sie auch hier verfügbar sein. Für den Moment kannst du ihnen auf einer der anderen Plattformen beitreten und hier auf alle Räume zugreifen, denen du dort beitrittst.";
"space_beta_announce_subtitle" = "Die verbesserte Version von Communities";
"space_beta_announce_title" = "Spaces sind bald verfügbar";
"space_beta_announce_badge" = "Beta (in Entwicklung)";
-"space_feature_unavailable_subtitle" = "Spaces sind auf iOS noch nicht verfügbar. Du kannst sie aber schon auf %@ Web oder Desktop ausprobieren";
+"space_feature_unavailable_subtitle" = "Spaces sind auf iOS noch nicht verfügbar. Du kannst sie aber schon auf Web oder Desktop benutzen";
// Mark: - Spaces
-"space_feature_unavailable_title" = "Spaces sind noch in der Entwicklung und werden bald verfügbar sein";
+"space_feature_unavailable_title" = "Spaces sind bald verfügbar";
"event_formatter_group_call_incoming" = "%@ in %@";
"event_formatter_group_call_leave" = "Verlassen";
"event_formatter_group_call_join" = "Beitreten";
@@ -1349,7 +1349,7 @@
"event_formatter_call_ringing" = "Läuten…";
"event_formatter_call_connecting" = "Verbinden…";
"settings_labs_enable_ringing_for_group_calls" = "Bei Gruppenanrufen klingeln";
-"room_no_privileges_to_create_group_call" = "Du musst Admin oder Mod sein, um einen Anruf zu starten.";
+"room_no_privileges_to_create_group_call" = "Du musst Administrations- oder Moderationsrechte besitzen, um einen Anruf zu starten.";
"room_join_group_call" = "Beitreten";
// Chat
@@ -1459,12 +1459,12 @@
// Mark: Avatar
"space_avatar_view_accessibility_label" = "Avatar";
-"spaces_coming_soon_detail" = "Diese Funktion wurde hier noch nicht eingebaut, kommt aber bald. So lange kannst du dafür Element am Computer nutzen.";
+"spaces_coming_soon_detail" = "Diese Funktion wurde hier noch nicht eingebaut, kommt aber bald. So lange kannst du dafür %@ am Computer nutzen.";
"spaces_invites_coming_soon_title" = "Einladungen sind bald verfügbar";
"spaces_add_rooms_coming_soon_title" = "Räume hinzufügen ist bald verfügbar";
"spaces_no_result_found_title" = "Keine Ergebnisse gefunden";
"spaces_suggested_room" = "Vorgeschlagen";
-"leave_space_message_admin_warning" = "Du bist Administrator in diesem Space, stelle vor dem Verlassen sicher, dass du die Administrator-Rechte auf ein anderes Mitglied übertragen hast.";
+"leave_space_message_admin_warning" = "Du besitzt in diesem Space Administrationsrechte, stelle vor dem Verlassen sicher, dass du die Administrationsrechte auf ein anderes Mitglied übertragen hast.";
"leave_space_message" = "Bist du dir sicher, dass du %@ verlassen möchtest? Möchtest du außerdem alle Räume und Spaces in diesem Space verlassen?";
"leave_space_title" = "%@ verlassen";
"space_avatar_view_accessibility_hint" = "Space-Avatar ändern";
@@ -1534,7 +1534,7 @@
"settings_about" = "ÜBER";
"enable" = "Aktivieren";
"analytics_prompt_message_upgrade" = "Du hast in der Vergangenheit bereits zugestimmt anonyme Nutzungsdaten mit uns zu teilen. Jetzt werden wir als Hilfe, um zu verstehen, wie Personen mehrere Geräte benutzen, eine zufällige Kennung generieren, die zwischen deinen Geräten geteilt wird.";
-"analytics_prompt_message_new_user" = "Hilf uns dabei Probleme zu identifizieren und Element zu verbessern, indem du anonyme Nutzungsdaten teilst. Um zu verstehen, wie Personen mehrere Geräte benutzen, werden wir eine zufällige Kennung generieren, die zwischen deinen Geräten geteilt wird.";
+"analytics_prompt_message_new_user" = "Hilf uns dabei Probleme zu identifizieren und %@ zu verbessern, indem du anonyme Nutzungsdaten teilst. Um zu verstehen, wie Personen mehrere Geräte benutzen, werden wir eine zufällige Kennung generieren, die zwischen deinen Geräten geteilt wird.";
"find_your_contacts_title" = "Starte mit der Auflistung deiner Kontakte";
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Du kannst unsere gesamten Bedingungen %@ nachlesen.";
@@ -1567,3 +1567,32 @@
"analytics_prompt_point_1" = "Wir erfassen und analysieren keine Accountdaten";
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_upgrade */
"analytics_prompt_terms_upgrade" = "Alle unsere Bedingungen lesen %@. Bist du damit einverstanden?";
+"ok" = "OK";
+"location_sharing_settings_toggle_title" = "Standortfreigabe aktivieren";
+"location_sharing_settings_header" = "Standortfreigabe";
+"location_sharing_open_google_maps" = "In Google Maps öffnen";
+"location_sharing_open_apple_maps" = "In Apple Karten öffnen";
+"location_sharing_invalid_authorization_settings" = "Einstellungen";
+"location_sharing_invalid_authorization_not_now" = "Nicht jetzt";
+"location_sharing_invalid_authorization_error_title" = "%@ besitzt keine Berechtigung um auf deinen Standort zuzugreifen. Du kannst den Zugriff unter Einstellungen > Standort erlauben";
+"location_sharing_locating_user_error_title" = "%@ konnte nicht auf deinen Standort zugreifen. Bitte versuche es später noch einmal.";
+"location_sharing_loading_map_error_title" = "%@ konnte die Karte nicht laden. Bitte versuche es später noch einmal.";
+"location_sharing_share_action" = "Teilen";
+"location_sharing_close_action" = "Schließen";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Standort";
+"onboarding_splash_page_4_title_no_pun" = "Nachrichtenaustausch für dein Team.";
+"onboarding_splash_page_3_title" = "Sicherer Nachrichtenaustausch.";
+"onboarding_splash_page_2_message" = "Wähle wo deine Gespräche liegen, für Kontrolle und Unabhängigkeit. Verbunden mit Matrix.";
+"onboarding_splash_page_1_title" = "Nimm deine Gespräche in die eigene Hand.";
+"onboarding_splash_login_button_title" = "Ich habe bereits ein Konto";
+"onboarding_splash_page_4_message" = "Element ist auch für die Arbeit großartig. Uns vertrauen einige der sichersten Organisationen der Welt.";
+"onboarding_splash_page_3_message" = "Ende-zu-Ende-verschlüsselt und ohne Telefonnummer nutzbar. Keine Werbung oder Datenerfassung.";
+"onboarding_splash_page_2_title" = "Du hast die Kontrolle.";
+"onboarding_splash_page_1_message" = "Sichere und unabhängige Kommunikation, die für die gleiche Vertraulichkeit sorgt, wie ein Gespräch von Angesicht zu Angesicht in deinem eigenen Zuhause.";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Konto erstellen";
+"settings_enable_room_message_bubbles" = "Nachrichtenblasen";
diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings
index bb405216d..0cc59b0e5 100644
--- a/Riot/Assets/en.lproj/Vector.strings
+++ b/Riot/Assets/en.lproj/Vector.strings
@@ -435,7 +435,7 @@ 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.";
-// MARK: Threads
+// MARK: Threads
"room_thread_title" = "Thread";
"thread_copy_link_to_thread" = "Copy link to thread";
"threads_title" = "Threads";
diff --git a/Riot/Assets/et.lproj/InfoPlist.strings b/Riot/Assets/et.lproj/InfoPlist.strings
index 25a5d9479..e556d1d6a 100644
--- a/Riot/Assets/et.lproj/InfoPlist.strings
+++ b/Riot/Assets/et.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSCalendarsUsageDescription" = "Vaata päevakavasse lisatud koosolekuid vastvast rakendusest.";
"NSContactsUsageDescription" = "Element näitab sulle tuttavaid, kellega saad alustada vestlust.";
"NSFaceIDUsageDescription" = "Ligipääsuks sinu rakendusele on kasutusel Face ID.";
+"NSLocationWhenInUseUsageDescription" = "Kui sa jagad teiste kasutajatega oma asukohta, siis Element vajab õigusi asukoha kuvamiseks kaardil.";
diff --git a/Riot/Assets/et.lproj/Localizable.strings b/Riot/Assets/et.lproj/Localizable.strings
index 6e4824651..844410852 100644
--- a/Riot/Assets/et.lproj/Localizable.strings
+++ b/Riot/Assets/et.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Teavitus";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ jagas oma asukohta";
diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings
index 2a1abaf1d..c88b9e297 100644
--- a/Riot/Assets/et.lproj/Vector.strings
+++ b/Riot/Assets/et.lproj/Vector.strings
@@ -1420,7 +1420,7 @@
"space_private_join_rule" = "Privaatne kogukond";
"space_participants_action_ban" = "Sea selles kogukonnakeskus suhtluskeeld";
"space_participants_action_remove" = "Eemalda sellest kogukonnakeskusest";
-"spaces_coming_soon_detail" = "See funktsionaalsus pole siin rakenduses hetkel veel saadaval, aga üsna varsti saab olema. Seni saad sa seda toimingut teha Element'i töölauarakenduses.";
+"spaces_coming_soon_detail" = "See funktsionaalsus pole siin rakenduses hetkel veel saadaval, aga üsna varsti saab olema. Seni saad sa seda toimingut teha %@'i töölauarakenduses.";
"spaces_invites_coming_soon_title" = "Varsti lisandub kutsete saatmine";
"spaces_add_rooms_coming_soon_title" = "Varsti on jututubade lisamine võimalik";
"spaces_coming_soon_title" = "Mõne aja pärast on meil uuendusi";
@@ -1520,10 +1520,39 @@
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Meie kasutustingimused leiad %@.";
"analytics_prompt_message_upgrade" = "Sa oled varem nõustunud meiega anonüümsete andmete jagamisega. Selleks, et mõistaksime, kuidas kasutajad erinevaid seadmeid pruugivad, me loome sinu seadmetele ühise juhusliku tunnuse.";
-"analytics_prompt_message_new_user" = "Võimalike vigade leidmiseks ja Element'i arendamiseks jaga meiega anonüümseid andmeid. Selleks, et mõistaksime, kuidas kasutajad erinevaid seadmeid pruugivad me loome sinu seadmetele ühise juhusliku tunnuse.";
+"analytics_prompt_message_new_user" = "Võimalike vigade leidmiseks ja %@'i arendamiseks jaga meiega anonüümseid andmeid. Selleks, et mõistaksime, kuidas kasutajad erinevaid seadmeid pruugivad, me loome sinu seadmetele ühise juhusliku tunnuse.";
// Analytics
"analytics_prompt_title" = "Aita arendada %@ rakendust";
"settings_analytics_and_crash_data" = "Saada rakenduse vigade ja analüütika andmeid";
"accessibility_button_label" = "nupp";
"enable" = "Võta kasutusele";
+"location_sharing_settings_toggle_title" = "Luba asukohta jagada";
+"location_sharing_settings_header" = "Asukoha jagamine";
+"location_sharing_open_google_maps" = "Ava rakendusega Google Maps";
+"location_sharing_open_apple_maps" = "Ava rakendusega Apple Maps";
+"location_sharing_invalid_authorization_settings" = "Seadistused";
+"location_sharing_invalid_authorization_not_now" = "Mitte praegu";
+"location_sharing_invalid_authorization_error_title" = "%@ vajab asukoha määramiseks õigusi, mida saad määrata Seadistused > Asukoht valikust";
+"location_sharing_locating_user_error_title" = "%@ ei saanud asukohta tuvastada. Palun proovi hiljem uuesti.";
+"location_sharing_loading_map_error_title" = "%@ ei saanud kaarti avada. Palun proovi hiljem uuesti.";
+"location_sharing_share_action" = "Jaga";
+"location_sharing_close_action" = "Sulge";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Asukoht";
+"ok" = "Sobib";
+"settings_enable_room_message_bubbles" = "Jutumullid";
+"onboarding_splash_page_4_message" = "Element sobib ideaalselt kasutamiseks töökeskkonnas. Ta on kasutusel ka mitmetes üliturvalistes organisatsioonides.";
+"onboarding_splash_page_4_title_no_pun" = "Sõnumisuhtlus sinu tiimi või kogukonna jaoks.";
+"onboarding_splash_page_3_message" = "Tagatud on andmete läbiv krüptimine ning oma telefoninumbrit ei pea sa jagama. Pole reklaame ega sinu andmete kogumist.";
+"onboarding_splash_page_3_title" = "Turvaline sõnumisuhtlus.";
+"onboarding_splash_page_2_message" = "Sa ise valid serveri, kus sinu vestlusi hoitakse ning sellega tagadki kontrolli oma andmete üle. Lahendus põhineb Matrix'i võrgul.";
+"onboarding_splash_page_2_title" = "Sul on kontroll oma andmete üle.";
+"onboarding_splash_page_1_message" = "Turvaline ja sõltumatu suhtluslahendus, mis tagab sama privaatsuse, kui omavaheline vestlus sinu kodus.";
+"onboarding_splash_page_1_title" = "Vestlused, mida sa tegelikult ka omad.";
+"onboarding_splash_login_button_title" = "Mul on kasutajakonto juba olemas";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Loo kasutajakonto";
diff --git a/Riot/Assets/fr.lproj/InfoPlist.strings b/Riot/Assets/fr.lproj/InfoPlist.strings
index 38d044ce1..c2a08df8d 100644
--- a/Riot/Assets/fr.lproj/InfoPlist.strings
+++ b/Riot/Assets/fr.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSContactsUsageDescription" = "Element affichera vos contacts pour que vous puissiez les inviter à parler.";
"NSCalendarsUsageDescription" = "Voir vos rendez-vous dans l’application.";
"NSFaceIDUsageDescription" = "Face ID est utilisé pour accéder à votre application.";
+"NSLocationWhenInUseUsageDescription" = "Element doit accéder à votre emplacement pour vous permettre de la partager aux autres utilisateurs sur une carte.";
diff --git a/Riot/Assets/fr.lproj/Vector.strings b/Riot/Assets/fr.lproj/Vector.strings
index aafd1db9a..0f012f74f 100644
--- a/Riot/Assets/fr.lproj/Vector.strings
+++ b/Riot/Assets/fr.lproj/Vector.strings
@@ -1492,7 +1492,7 @@
"space_private_join_rule" = "Espace privé";
"space_participants_action_ban" = "Supprimer de cet espace";
"space_participants_action_remove" = "Enlever de cet espace";
-"spaces_coming_soon_detail" = "Cette fonctionnalité n’a pas été implémentée ici, mais elle arrive. Pour effectuer cette action, vous pouvez utiliser Element sur votre ordinateur.";
+"spaces_coming_soon_detail" = "Cette fonctionnalité n’a pas été implémentée ici, mais elle arrive. Pour effectuer cette action, vous pouvez utiliser %@ sur votre ordinateur.";
"spaces_invites_coming_soon_title" = "Les invitations arrivent prochainement";
"spaces_add_rooms_coming_soon_title" = "L’ajout de salons arrive bientôt";
"spaces_coming_soon_title" = "Prochainement";
@@ -1581,7 +1581,7 @@
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Vous pouvez lire nos conditions d’utilisation %@.";
"analytics_prompt_message_upgrade" = "Vous aviez consenti précédemment à partager des rapports d’utilisation avec nous. Désormais, pour nous aider à comprendre comment les gens utilisent cette application sur plusieurs appareils, nous allons générer un identifiant aléatoire commun à tous vos appareils.";
-"analytics_prompt_message_new_user" = "Aidez nous à identifier les problèmes et améliorer Element en envoyant des rapports d’usage anonymes. Pour comprendre de quelle manière les gens utilisent Element sur plusieurs appareils, nous créeront un identifiant aléatoire commun à tous vos appareils.";
+"analytics_prompt_message_new_user" = "Aidez nous à identifier les problèmes et améliorer %@ en envoyant des rapports d’usage anonymes. Pour comprendre de quelle manière les gens utilisent Element sur plusieurs appareils, nous créeront un identifiant aléatoire commun à tous vos appareils.";
// Analytics
"analytics_prompt_title" = "Aidez à améliorer %@";
@@ -1604,3 +1604,32 @@
"find_your_contacts_title" = "Commencez par lister vos contacts";
"settings_contacts_enable_sync_description" = "Cette fonctionnalité utilisera votre serveur d'identité pour vous connecter avec vos contacts, ainsi que pour les aider à vous trouver.";
"settings_contacts_enable_sync" = "Trouvez vos contacts";
+"location_sharing_settings_toggle_title" = "Activer le partage de localisation";
+"location_sharing_settings_header" = "Partage de localisation";
+"location_sharing_open_google_maps" = "Ouvrir dans Google Maps";
+"location_sharing_open_apple_maps" = "Ouvrir dans Apple Plans";
+"location_sharing_invalid_authorization_settings" = "Paramètres";
+"location_sharing_invalid_authorization_not_now" = "Pas maintenant";
+"location_sharing_invalid_authorization_error_title" = "%@ n’a pas les autorisations pour accéder à votre localisation. Vous pouvez l’autoriser dans Réglages > Confidentialité";
+"location_sharing_locating_user_error_title" = "%@ n’a pas pu déterminer votre localisation. Veuillez ré-essayer plus tard.";
+"location_sharing_loading_map_error_title" = "%@ n’a pas pu charger la carte. Veuillez ré-essayer plus tard.";
+"location_sharing_share_action" = "Partager";
+"location_sharing_close_action" = "Fermer";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Localisation";
+"settings_enable_room_message_bubbles" = "Messages en bulles";
+"onboarding_splash_page_4_message" = "Element est parfaite pour le bureau. Les sociétés aux plus gros besoins de sécurité lui font confiance.";
+"onboarding_splash_page_4_title_no_pun" = "Une messagerie pour votre équipe.";
+"onboarding_splash_page_3_message" = "Chiffrée de bout en bout, aucun numéro de téléphone requis. Pas de pub ni d’exploitation de données.";
+"onboarding_splash_page_3_title" = "Messagerie sécurisée.";
+"onboarding_splash_page_2_message" = "Décidez où vos conversations sont stockées, en toute liberté et indépendance. Grâce à Matrix.";
+"onboarding_splash_page_2_title" = "C’est vous qui décidez.";
+"onboarding_splash_page_1_message" = "Une messagerie sécurisée et indépendante qui vous garantit le même niveau de confidentialité qu’une conversation en face à face chez vous.";
+"onboarding_splash_page_1_title" = "Maîtrisez vos conversations.";
+"onboarding_splash_login_button_title" = "J’ai déjà un compte";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Créer un compte";
+"ok" = "Ok";
diff --git a/Riot/Assets/hu.lproj/InfoPlist.strings b/Riot/Assets/hu.lproj/InfoPlist.strings
index 0edf4d429..75e748c58 100644
--- a/Riot/Assets/hu.lproj/InfoPlist.strings
+++ b/Riot/Assets/hu.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSContactsUsageDescription" = "Element megmutatja a névjegyzéket, hogy beszélgetésbe meghívhasd őket.";
"NSCalendarsUsageDescription" = "Nézd meg a találkozóidat az alkalmazásban.";
"NSFaceIDUsageDescription" = "Arc felismerés használata az alkalmazás eléréséhez.";
+"NSLocationWhenInUseUsageDescription" = "Ha megosztod másokkal a földrajzi helyzetedet, akkor az Elementnek hozzáférésre van szüksége a térképen való megjelenítéshez.";
diff --git a/Riot/Assets/hu.lproj/Localizable.strings b/Riot/Assets/hu.lproj/Localizable.strings
index caa2f34ad..d0ed4447e 100644
--- a/Riot/Assets/hu.lproj/Localizable.strings
+++ b/Riot/Assets/hu.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Értesítés";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ megosztotta a földrajzi helyzetét";
diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings
index 6060f16c3..29e3902c1 100644
--- a/Riot/Assets/hu.lproj/Vector.strings
+++ b/Riot/Assets/hu.lproj/Vector.strings
@@ -1483,7 +1483,7 @@
"space_private_join_rule" = "Privát tér";
"space_participants_action_ban" = "Kitiltás a térről";
"space_participants_action_remove" = "Eltávolítás a térről";
-"spaces_coming_soon_detail" = "Ez a lehetőség még nincs meg, de fejlesztés alatt van. Egyenlőre a számítógépeden Elementtel tudod ezt megtenni.";
+"spaces_coming_soon_detail" = "Ez a lehetőség még nincs meg, de fejlesztés alatt van. Egyenlőre a számítógépeden %@ alkalmazással tudod ezt megtenni.";
"spaces_invites_coming_soon_title" = "Meghívók küldése hamarosan érkezik";
"spaces_add_rooms_coming_soon_title" = "Szobák hozzáadása hamarosan érkezik";
"spaces_coming_soon_title" = "Hamarosan";
@@ -1579,7 +1579,7 @@
"analytics_prompt_terms_link_new_user" = "itt";
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Az összes feltételünket elolvashatod itt: %@.";
-"analytics_prompt_message_new_user" = "Segíts észrevennünk a hibákat, és jobbá tenni az Element-et a névtelen használati adatok küldése által. Ahhoz, hogy megértsük, hogyan használnak a felhasználók egyszerre több eszközt, egy véletlenszerű azonosítót generálunk, ami az eszközeid között meg lesz osztva.";
+"analytics_prompt_message_new_user" = "Segíts észrevennünk a hibákat, és jobbá tenni a(z) %@ alkalmazást a névtelen használati adatok küldése által. Ahhoz, hogy megértsük, hogyan használnak a felhasználók egyszerre több eszközt, egy véletlenszerű azonosítót generálunk, ami az eszközeid között meg lesz osztva.";
// Analytics
"analytics_prompt_title" = "Segíts jobbá tenni %@";
@@ -1590,3 +1590,32 @@
"accessibility_button_label" = "gomb";
"enable" = "Engedélyezés";
"analytics_prompt_message_upgrade" = "Korábban beleegyeztél, hogy velünk anonimizált adatokat osztasz meg. Most, hogy jobban megértsük, hogyan használnak több eszközt az emberek, véletlenszerű azonosítót állítunk elő amit az eszközeid használni fognak.";
+"location_sharing_settings_toggle_title" = "Földrajzi hely megosztás engedélyezése";
+"location_sharing_settings_header" = "Földrajzi hely megosztása";
+"location_sharing_open_google_maps" = "Megnyitás a Google Térképen";
+"location_sharing_open_apple_maps" = "Megnyitás az Apple Térképen";
+"location_sharing_invalid_authorization_settings" = "Beállítások";
+"location_sharing_invalid_authorization_not_now" = "Nem most";
+"location_sharing_invalid_authorization_error_title" = "%@ alkalmazásnak nincs jogosultsága a helyadatod eléréséhez. Engedélyezheted a Beállítások > Helyadatokban";
+"location_sharing_loading_map_error_title" = "%@ nem tudja betölteni a térképet. Próbáld újra később.";
+"location_sharing_locating_user_error_title" = "%@ nem fér hozzá a helyadatodhoz. Próbáld újra később.";
+"location_sharing_share_action" = "Megoszt";
+"location_sharing_close_action" = "Bezár";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Földrajzi helyzet";
+"ok" = "OK";
+"onboarding_splash_page_4_message" = "Element megállja a helyét a munkahelyen is. A világ legbiztonságosabb szervezetei bíznak meg benne.";
+"onboarding_splash_page_3_message" = "Telefonszám nélkül végpontok között titkosított. Reklámok és adatbányászat nélkül.";
+"onboarding_splash_page_2_message" = "Válaszd meg hol legyenek a beszélgetéseid tárolva, visszaadja az irányítást és függetlenné tesz. Csatlakozva a Matrixhoz.";
+"onboarding_splash_page_1_message" = "Biztonságos és független kommunikáció ami olyan biztonságos mintha valakivel négyszemközt beszélgetnél a házadban.";
+"settings_enable_room_message_bubbles" = "Üzenet buborékok";
+"onboarding_splash_page_4_title_no_pun" = "Üzenetküldés a csoportodnak.";
+"onboarding_splash_page_3_title" = "Biztonságos üzenetküldés.";
+"onboarding_splash_page_2_title" = "Te irányítasz.";
+"onboarding_splash_page_1_title" = "Az ön beszélgetései csak az öné.";
+"onboarding_splash_login_button_title" = "Már van fiókom";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Fiók létrehozása";
diff --git a/Riot/Assets/id.lproj/InfoPlist.strings b/Riot/Assets/id.lproj/InfoPlist.strings
index e74ebc244..3459f17dd 100644
--- a/Riot/Assets/id.lproj/InfoPlist.strings
+++ b/Riot/Assets/id.lproj/InfoPlist.strings
@@ -7,3 +7,4 @@
"NSCalendarsUsageDescription" = "Lihat pertemuan yang sudah dijadwalkan di aplikasi.";
"NSMicrophoneUsageDescription" = "Element membutuhkan akses ke mikrofon Anda untuk melakukan dan menerima panggilan, mengambil video, dan merekam pesan suara.";
"NSPhotoLibraryUsageDescription" = "Galeri digunakan untuk mengirim foto dan video.";
+"NSLocationWhenInUseUsageDescription" = "Ketika Anda membagikan lokasi Anda ke orang-orang, Element membutuhkan akses untuk menampilkan mereka sebuah peta.";
diff --git a/Riot/Assets/id.lproj/Localizable.strings b/Riot/Assets/id.lproj/Localizable.strings
index 679a5cbb8..dc244763c 100644
--- a/Riot/Assets/id.lproj/Localizable.strings
+++ b/Riot/Assets/id.lproj/Localizable.strings
@@ -165,3 +165,6 @@
/** General **/
"NOTIFICATION" = "Notifikasi";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ membagikan lokasinya";
diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings
index e92ace022..a4fddb9be 100644
--- a/Riot/Assets/id.lproj/Vector.strings
+++ b/Riot/Assets/id.lproj/Vector.strings
@@ -611,7 +611,7 @@
"open" = "Buka";
"version_check_banner_subtitle_deprecated" = "Kami tidak mendukung %@ di iOS %@ lagi. Untuk terus menggunakan %@ secara maksimal, kami menyarankan Anda untuk meningkatkan versi iOS Anda.";
"version_check_banner_subtitle_supported" = "Kami akan segera mengakhiri dukungan untuk %@ di iOS %@. Untuk terus menggunakan %@ secara maksimal, kami menyarankan Anda untuk meningkatkan versi iOS Anda.";
-"spaces_coming_soon_detail" = "Fitur ini belum ada di sini, tetapi sedang dalam proses. Untuk saat ini, Anda dapat melakukannya dengan Element di komputer Anda.";
+"spaces_coming_soon_detail" = "Fitur ini belum ada di sini, tetapi sedang dalam proses. Untuk saat ini, Anda dapat melakukannya dengan %@ di komputer Anda.";
"spaces_no_member_found_detail" = "Mencari seseorang yang tidak ada di %@? Untuk saat ini, Anda dapat mengundangnya di web atau desktop.";
"spaces_no_room_found_detail" = "Beberapa hasil mungkin disembunyikan karena ruangannya pribadi dan Anda memerlukan sebuah undangan untuk bergabung.";
"spaces_empty_space_detail" = "Beberapa ruangan mungkin disembunyikan karena ruangannya pribadi dan Anda memerlukan sebuah undangan.";
@@ -1699,10 +1699,39 @@
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Anda dapat membaca semua kebijakan kami %@.";
"analytics_prompt_message_upgrade" = "Anda sebelumnya setuju untuk mengirimkan data penggunaan anonim dengan kami. Sekarang, supaya kami dapat memahami bagaimana orang-orang menggunakan beberapa perangkat-perangkat, kami akan membuat pengenal acak, yang dibagikan oleh perangkat Anda.";
-"analytics_prompt_message_new_user" = "Bantu kami mengidentifikasi masalah-masalah dan membuat Element lebih baik dengan membagikan data penggunaan anonim. Untuk memahami bagaimana orang-orang menggunakan beberapa perangkat-perangkat, kami akan membuat pengenal acak, yang dibagikan oleh perangkat Anda.";
+"analytics_prompt_message_new_user" = "Bantu kami mengidentifikasi masalah-masalah dan membuat %@ lebih baik dengan membagikan data penggunaan anonim. Untuk memahami bagaimana orang-orang menggunakan beberapa perangkat-perangkat, kami akan membuat pengenal acak, yang dibagikan oleh perangkat Anda.";
// Analytics
"analytics_prompt_title" = "Bantu membuat %@ lebih baik";
"settings_analytics_and_crash_data" = "Kirim data crash dan analitik";
"accessibility_button_label" = "tombol";
"enable" = "Aktifkan";
+"location_sharing_invalid_authorization_error_title" = "%@ tidak memiliki izin untuk mengakses lokasi. Anda dapat mengaktifkan akses di Pengaturan > Lokasi";
+"location_sharing_settings_toggle_title" = "Aktifkan pembagian lokasi";
+"location_sharing_settings_header" = "Pembagian lokasi";
+"location_sharing_open_google_maps" = "Buka di Google Maps";
+"location_sharing_open_apple_maps" = "Buka di Apple Maps";
+"location_sharing_invalid_authorization_settings" = "Pengaturan";
+"location_sharing_invalid_authorization_not_now" = "Jangan sekarang";
+"location_sharing_locating_user_error_title" = "%@ tidak dapat mengakses lokasi Anda. Silakan coba lagi nanti.";
+"location_sharing_loading_map_error_title" = "%@ tidak dapat memuat peta. Silakan coba lagi nanti.";
+"location_sharing_share_action" = "Bagikan";
+"location_sharing_close_action" = "Tutup";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Lokasi";
+"ok" = "OKE";
+"settings_enable_room_message_bubbles" = "Gelembung pesan";
+"onboarding_splash_page_4_message" = "Element juga bagus untuk tempat kerja. Terpercayai oleh organisasi paling aman di dunia.";
+"onboarding_splash_page_4_title_no_pun" = "Perpesanan untuk tim Anda.";
+"onboarding_splash_page_3_message" = "Terenkripsi secara ujung-ke-ujung dan tidak memerlukan nomor telepon. Tidak ada iklan atau penambangan data.";
+"onboarding_splash_page_3_title" = "Perpesanan aman.";
+"onboarding_splash_page_2_message" = "Pilihlah di mana percakapan Anda disimpan, memberikan Anda kendali dan kebebasan. Terhubung via Matrix.";
+"onboarding_splash_page_2_title" = "Anda dalam kendali.";
+"onboarding_splash_page_1_message" = "Komunikasi aman dan independen yang memberikan tingkat privasi yang sama seperti percakapan tatap muka di rumah Anda sendiri.";
+"onboarding_splash_page_1_title" = "Miliki percakapan Anda.";
+"onboarding_splash_login_button_title" = "Saya sudah punya akun";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Buat akun";
diff --git a/Riot/Assets/it.lproj/InfoPlist.strings b/Riot/Assets/it.lproj/InfoPlist.strings
index 6382ef48e..989ac76d3 100644
--- a/Riot/Assets/it.lproj/InfoPlist.strings
+++ b/Riot/Assets/it.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSContactsUsageDescription" = "Element mostrerà i tuoi contatti così da poterli invitare in chat.";
"NSCalendarsUsageDescription" = "Vedi le tue riunioni programmate nell'app.";
"NSFaceIDUsageDescription" = "Face ID viene usato per accedere all'app.";
+"NSLocationWhenInUseUsageDescription" = "Quando condividi la tua posizione con altre persone, Element richiede l'accesso per mostrare loro una mappa.";
diff --git a/Riot/Assets/it.lproj/Localizable.strings b/Riot/Assets/it.lproj/Localizable.strings
index 25a6a0cca..d8ec6e0cd 100644
--- a/Riot/Assets/it.lproj/Localizable.strings
+++ b/Riot/Assets/it.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Notifica";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ ha condiviso la sua posizione";
diff --git a/Riot/Assets/it.lproj/Vector.strings b/Riot/Assets/it.lproj/Vector.strings
index 797589e89..26065f880 100644
--- a/Riot/Assets/it.lproj/Vector.strings
+++ b/Riot/Assets/it.lproj/Vector.strings
@@ -1454,7 +1454,7 @@
"space_private_join_rule" = "Spazio privato";
"space_participants_action_ban" = "Bandisci da questo spazio";
"space_participants_action_remove" = "Rimuovi da questo spazio";
-"spaces_coming_soon_detail" = "Questa funzionalità non è stata implementata qui, ma è in arrivo. Per adesso, puoi farlo con Element sul tuo computer.";
+"spaces_coming_soon_detail" = "Questa funzionalità non è stata implementata qui, ma è in arrivo. Per adesso, puoi farlo con %@ sul tuo computer.";
"spaces_invites_coming_soon_title" = "Inviti in arrivo";
"spaces_add_rooms_coming_soon_title" = "Aggiunta di stanze in arrivo";
"spaces_coming_soon_title" = "Prossimamente";
@@ -1554,10 +1554,39 @@
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Puoi leggere i nostri termini di servizio %@.";
"analytics_prompt_message_upgrade" = "Hai acconsentito precedentemente a condividere con noi dati di utilizzo anonimi. Ora, per capire come le persone usano diversi dispositivi, genereremo un identificativo casuale, condiviso dai tuoi dispositivi.";
-"analytics_prompt_message_new_user" = "Aiutaci a identificare problemi e a migliorare Element condividendo dati di utilizzo anonimi. Per capire come le persone usano diversi dispositivi, genereremo un identificativo casuale, condiviso dai tuoi dispositivi.";
+"analytics_prompt_message_new_user" = "Aiutaci a identificare problemi e a migliorare %@ condividendo dati di utilizzo anonimi. Per capire come le persone usano diversi dispositivi, genereremo un identificativo casuale, condiviso dai tuoi dispositivi.";
// Analytics
"analytics_prompt_title" = "Aiuta a migliorare %@";
"settings_analytics_and_crash_data" = "Invia crash e dati analitici";
"accessibility_button_label" = "pulsante";
"enable" = "Attiva";
+"location_sharing_settings_toggle_title" = "Attiva condivisione posizione";
+"location_sharing_settings_header" = "Condivisione posizione";
+"location_sharing_open_google_maps" = "Apri in Google Maps";
+"location_sharing_open_apple_maps" = "Apri in Apple Maps";
+"location_sharing_invalid_authorization_settings" = "Impostazioni";
+"location_sharing_invalid_authorization_not_now" = "Non ora";
+"location_sharing_invalid_authorization_error_title" = "%@ non ha l'autorizzazione per accedere alla tua posizione. Puoi attivarne l'accesso in Impostazioni > Localizzazione";
+"location_sharing_locating_user_error_title" = "%@ non ha potuto rilevare la tua posizione. Riprova più tardi.";
+"location_sharing_loading_map_error_title" = "%@ non ha potuto caricare la mappa. Riprova più tardi.";
+"location_sharing_share_action" = "Condividi";
+"location_sharing_close_action" = "Chiudi";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Posizione";
+"ok" = "OK";
+"settings_enable_room_message_bubbles" = "Messaggi";
+"onboarding_splash_page_4_message" = "Element è ottimo anche per i luoghi di lavoro. È considerato affidabile dalle più sicure organizzazioni del mondo.";
+"onboarding_splash_page_4_title_no_pun" = "Messaggistica per la tua squadra.";
+"onboarding_splash_page_3_message" = "Crittografia end-to-end e nessun numero di telefono richiesto. Niente pubblicità o raccolta di dati.";
+"onboarding_splash_page_3_title" = "Messaggistica sicura.";
+"onboarding_splash_page_2_message" = "Scegli dove vengono tenute le tue conversazioni, dandoti controllo e indipendenza. Connesso via Matrix.";
+"onboarding_splash_page_2_title" = "Tu hai il controllo.";
+"onboarding_splash_page_1_message" = "Comunicazioni sicure e indipendenti che ti danno lo stesso livello di riservatezza di una conversazione faccia a faccia in casa tua.";
+"onboarding_splash_page_1_title" = "Prendi il controllo delle tue conversazioni.";
+"onboarding_splash_login_button_title" = "Ho già un account";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Crea account";
diff --git a/Riot/Assets/nl.lproj/InfoPlist.strings b/Riot/Assets/nl.lproj/InfoPlist.strings
index c3c846e97..9a4450097 100644
--- a/Riot/Assets/nl.lproj/InfoPlist.strings
+++ b/Riot/Assets/nl.lproj/InfoPlist.strings
@@ -21,3 +21,4 @@
"NSContactsUsageDescription" = "Element zal uw contacten tonen zodat u ze kunt uitnodigen om te chatten.";
"NSCalendarsUsageDescription" = "Bekijk uw geplande afspraken in de app.";
"NSFaceIDUsageDescription" = "Face ID wordt gebruikt om toegang te krijgen tot uw app.";
+"NSLocationWhenInUseUsageDescription" = "Wanneer u uw locatie deelt met mensen heeft Element toegang nodig om dit op een kaart te tonen.";
diff --git a/Riot/Assets/nl.lproj/Localizable.strings b/Riot/Assets/nl.lproj/Localizable.strings
index f8c52bb83..7ff69454b 100644
--- a/Riot/Assets/nl.lproj/Localizable.strings
+++ b/Riot/Assets/nl.lproj/Localizable.strings
@@ -149,3 +149,6 @@
/** General **/
"NOTIFICATION" = "Meldingen";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ deelde hun locatie";
diff --git a/Riot/Assets/nl.lproj/Vector.strings b/Riot/Assets/nl.lproj/Vector.strings
index 65b0d41c6..b8eefab2b 100644
--- a/Riot/Assets/nl.lproj/Vector.strings
+++ b/Riot/Assets/nl.lproj/Vector.strings
@@ -1583,7 +1583,7 @@
"space_private_join_rule" = "Privé Space";
"space_participants_action_ban" = "Uit deze Space verbannen";
"space_participants_action_remove" = "Uit deze kamer verwijderen";
-"spaces_coming_soon_detail" = "Deze functies is nog niet klaar, maar er wordt aan gewerkt. Voor nu kan u dit wel doen met Element via uw computer.";
+"spaces_coming_soon_detail" = "Deze functies is nog niet klaar, maar er wordt aan gewerkt. Voor nu kan u dit wel doen met %@ via uw computer.";
"spaces_invites_coming_soon_title" = "Uitnodigen komt binnenkort";
"spaces_add_rooms_coming_soon_title" = "Kamers toevoegen komt binnenkort";
"spaces_coming_soon_title" = "Komt binnenkort";
@@ -1680,7 +1680,7 @@
"analytics_prompt_terms_new_user" = "U kunt al onze voorwaarden %@ lezen.";
"analytics_prompt_terms_link_new_user" = "hier";
"analytics_prompt_message_upgrade" = "U heeft eerder toestemming gegeven om anonieme gebruiksgegevens met ons te delen. Om beter te begrijpen hoe mensen meerdere apparaten gebruiken, genereren we nu een willekeurige identificatiecode die door uw apparaten wordt gedeeld.";
-"analytics_prompt_message_new_user" = "Help ons bij het identificeren van problemen en het verbeteren van Element door anonieme gebruiksgegevens te delen. Om te begrijpen hoe mensen meerdere apparaten gebruiken genereren we een willekeurige identificatie die we verspreiden over uw apparaten.";
+"analytics_prompt_message_new_user" = "Help ons bij het identificeren van problemen en het verbeteren van %@ door anonieme gebruiksgegevens te delen. Om te begrijpen hoe mensen meerdere apparaten gebruiken genereren we een willekeurige identificatie die we verspreiden over uw apparaten.";
// Analytics
"analytics_prompt_title" = "Help %@ verbeteren";
@@ -1690,3 +1690,32 @@
"room_event_action_remove_poll" = "Poll verwijderen";
"accessibility_button_label" = "knop";
"enable" = "Inschakelen";
+"location_sharing_settings_toggle_title" = "Locatie delen inschakelen";
+"location_sharing_settings_header" = "Locatie delen";
+"location_sharing_open_google_maps" = "In Google Maps openen";
+"location_sharing_open_apple_maps" = "In Apple Maps openen";
+"location_sharing_invalid_authorization_settings" = "Instellingen";
+"location_sharing_invalid_authorization_not_now" = "Niet nu";
+"location_sharing_invalid_authorization_error_title" = "%@ heeft geen toegang tot uw locatie. U kan dit inschakelen via Instellingen > Locatie";
+"location_sharing_locating_user_error_title" = "%@ heeft geen toegang tot uw locatie. Probeer het later opnieuw.";
+"location_sharing_loading_map_error_title" = "%@ kan de kaart niet laden. Probeer het later opnieuw.";
+"location_sharing_share_action" = "Delen";
+"location_sharing_close_action" = "Sluiten";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Locatie";
+"ok" = "OK";
+"settings_enable_room_message_bubbles" = "Bericht bubbels";
+"onboarding_splash_page_4_message" = "Element is ook zeer geschikt voor op de werkvloer. Het wordt vertrouwd door 's werelds veiligste organisaties.";
+"onboarding_splash_page_4_title_no_pun" = "Berichten voor uw team.";
+"onboarding_splash_page_3_message" = "End-to-end versleuteld en geen telefoonnummer vereist. Geen advertenties of datamining.";
+"onboarding_splash_page_3_title" = "Veilig berichtenverkeer.";
+"onboarding_splash_page_2_message" = "Kies waar u gesprekken worden gehouden, zodat u controle en onafhankelijkheid heeft. Verbonden via Matrix.";
+"onboarding_splash_page_2_title" = "U heeft de controle.";
+"onboarding_splash_page_1_message" = "Veilige en onafhankelijke communicatie die u dezelfde mate van privacy geeft als een persoonlijk gesprek in uw eigen huis.";
+"onboarding_splash_page_1_title" = "Word eigenaar van uw gesprekken.";
+"onboarding_splash_login_button_title" = "Ik heb al een account";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Account aanmaken";
diff --git a/Riot/Assets/pl.lproj/Localizable.strings b/Riot/Assets/pl.lproj/Localizable.strings
index 761802de0..3be30e2fb 100644
--- a/Riot/Assets/pl.lproj/Localizable.strings
+++ b/Riot/Assets/pl.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Powiadomienie";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ udostępnił(-a) swoją lokację";
diff --git a/Riot/Assets/pl.lproj/Vector.strings b/Riot/Assets/pl.lproj/Vector.strings
index c4445fe9b..4f027c5db 100644
--- a/Riot/Assets/pl.lproj/Vector.strings
+++ b/Riot/Assets/pl.lproj/Vector.strings
@@ -217,9 +217,9 @@
"settings_calls_settings" = "POŁĄCZENIA";
"settings_user_interface" = "INTERFEJS UŻYTKOWNIKA";
"settings_ignored_users" = "IGNOROWANI UŻYTKOWNICY";
-"settings_contacts" = "LOKALNE KONTAKTY";
+"settings_contacts" = "KONTAKTY NA URZĄDZENIU";
"settings_advanced" = "ZAAWANSOWANE";
-"settings_other" = "Pozostałe powiadomienia";
+"settings_other" = "Pozostałe ustawienia";
"settings_devices" = "SESJE";
"settings_cryptography" = "KRYPTOGRAFIA";
"settings_deactivate_account" = "DEZAKTYWUJ KONTO";
@@ -416,7 +416,7 @@
"auth_email_not_found" = "Nie udało się wysłać wiadomości e-mail: Adres e-mail nie został znaleziony";
"auth_accept_policies" = "Przeczytaj i zaakceptuj zasady tego serwera domowego:";
"room_creation_wait_for_creation" = "Pokój jest już tworzony. Proszę czekaj.";
-"room_creation_invite_another_user" = "Szukaj / zaproś przez ID Użytkownika, Nazwę lub e-mail";
+"room_creation_invite_another_user" = "ID użytkownika, nazwa lub email";
"search_people_placeholder" = "Szukaj przez ID Użytkownika, Nazwę lub e-mail";
"contacts_user_directory_offline_section" = "KATALOG UŻYTKOWNIKÓW (offline)";
"room_participants_remove_prompt_msg" = "Czy na pewno chcesz usunąć %@ z tej rozmowy?";
@@ -1265,7 +1265,7 @@
// Widget Picker
"widget_picker_title" = "Integracje";
-"widget_integration_manager_disabled" = "Musisz włączyć Menadżer Integracji w ustawieniach";
+"widget_integration_manager_disabled" = "Musisz włączyć menadżer integracji w ustawieniach";
"widget_menu_remove" = "Usuń dla wszystkich";
"widget_menu_revoke_permission" = "Odbierz mi dostęp";
"widget_menu_open_outside" = "Otwórz w przeglądarce";
@@ -1321,7 +1321,7 @@
"identity_server_settings_description" = "Obecnie używasz %@ do wyszukiwania i bycia znalezionym przez kontakty, które znasz.";
// Identity server settings
-"identity_server_settings_title" = "Serwer Tożsamości";
+"identity_server_settings_title" = "Serwer tożsamości";
// AuthenticatedSessionViewControllerFactory
"authenticated_session_flow_not_supported" = "Ta aplikacja nie obsługuje mechanizmu uwierzytelniania na Twoim serwerze domowym.";
@@ -1365,7 +1365,7 @@
"settings_discovery_terms_not_signed" = "Zaakceptuj warunki korzystania z usługi serwera tożsamości (%@), aby umożliwić innym osobom wyszukiwanie Ciebie za pomocą adresu e-mail lub numeru telefonu.";
"settings_discovery_no_identity_server" = "Obecnie nie używasz serwera tożsamości. Pomyśl o tym, aby go dodać by móc być odnalezionym przez osoby, które znasz.";
"settings_devices_description" = "Publiczna nazwa sesji jest widoczna dla osób, z którymi się komunikujesz";
-"settings_integrations_allow_description" = "Użyj Menedżera Integracji (%@) do zarządzania botami, mostami, widżetami i pakietami naklejek.\n\nMenedżerowie integracji otrzymują dane konfiguracyjne i mogą modyfikować widżety, wysyłać zaproszenia do pokojów i ustawiać poziomy mocy w Twoim imieniu.";
+"settings_integrations_allow_description" = "Użyj menedżera integracji (%@) do zarządzania botami, mostami, widżetami i pakietami naklejek.\n\nMenedżerowie integracji otrzymują dane konfiguracyjne i mogą modyfikować widżety, wysyłać zaproszenia do pokojów i ustawiać poziomy mocy w Twoim imieniu.";
"settings_calls_stun_server_fallback_description" = "Zezwalaj na użycie rezerwowego serwera połączeń %@ w przypadku, gdy Twój serwer domowy go nie oferuje (Twój adres IP będzie udostępniany podczas połączenia).";
"settings_three_pids_management_information_part1" = "Wybierz, które adresy e-mail lub numery telefonów chcesz wykorzystać do logowania się lub odzyskiwania konta. Kontroluj, kto może Cię dzięki nim znaleźć przechodząc do ";
"room_multiple_typing_notification" = "%@ i inni";
@@ -1535,7 +1535,58 @@
"settings_default" = "Powiadomienia dotyczące wiadomości";
"settings_notifications" = "POWIADOMIENIA";
"settings_show_url_previews_description" = "Podgląd URL będzie wyświetlany tylko w niezaszyfrowanych pokojach.";
-"settings_show_url_previews" = "Pokaż podgląd adresów URL";
+"settings_show_url_previews" = "Pokaż podgląd stron";
"settings_confirm_media_size_description" = "Gdy ta opcja jest włączona, zostaniesz poproszony o potwierdzenie, w jakim rozmiarze obrazy i filmy będą wysyłane.";
"settings_confirm_media_size" = "Potwierdź rozmiar podczas wysyłania";
"settings_sending_media" = "WYSYŁANIE ZDJĘĆ I WIDEO";
+"service_terms_modal_table_header_integration_manager" = "WARUNKI KORZYSTANIA Z MENEDŻERA INTEGRACJI";
+"service_terms_modal_table_header_identity_server" = "WARUNKI KORZYSTANIA Z SERWERA TOŻSAMOŚCI";
+"service_terms_modal_footer" = "To może być wyłączone później w ustawieniach.";
+
+// Service terms
+"service_terms_modal_title_message" = "Aby kontynuować, wyraź zgodę na poniższe warunki użytkowania";
+"share_extension_send_now" = "Udostępnij teraz";
+"share_extension_low_quality_video_message" = "Udostępnij w %@ by uzyskać lepszą jakość, lub udostępnij w niskiej jakości poniżej.";
+"share_extension_low_quality_video_title" = "Video będzie udostępnianie w niskiej jakości";
+"analytics_prompt_stop" = "Przestań udostępniać";
+"analytics_prompt_yes" = "Tak, to jest w porządku";
+"analytics_prompt_not_now" = "Nie teraz";
+"analytics_prompt_point_3" = "Możesz to wyłączyć w dowolnym momencie w ustawieniach";
+/* Note: The word "don't" is formatted in bold */
+"analytics_prompt_point_2" = "Nie dzielimy się informacjami z żadnymi firmami zewnętrznymi";
+/* Note: The word "don't" is formatted in bold */
+"analytics_prompt_point_1" = "Nie gromadzimy ani profilujemy żadnych danych na temat kont";
+"analytics_prompt_terms_link_upgrade" = "tutaj";
+/* Note: The placeholder is for the contents of analytics_prompt_terms_link_upgrade */
+"analytics_prompt_terms_upgrade" = "Przeczytaj nasze warunki użytkowania %@. Czy odpowiadają one Tobie?";
+"analytics_prompt_terms_link_new_user" = "tutaj";
+/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
+"analytics_prompt_terms_new_user" = "Tutaj możesz przeczytać nasze warunki użytkowania %@.";
+"analytics_prompt_message_upgrade" = "Wcześniej dostaliśmy Twoją zgodę na używanie zanonimizowanych danych na temat użytkowania. Teraz, by zrozumieć jak użytkownicy korzystają z wielu urządzeń, wygenerujemy identyfikator używany przez nie wszystkie.";
+"analytics_prompt_message_new_user" = "Pomóż nam zidentyfikować problemy i poprawić @% udostępniając zanonimizowane dane o użytkowaniu. W celu zrozumienia jak użytkownicy korzystają z wielu urządzeń wygenerujemy identyfikator używany przez nie wszystkie.";
+
+// Analytics
+"analytics_prompt_title" = "Pomóż ulepszyć %@";
+"settings_discovery_accept_terms" = "Zaakceptuj warunki używania serwera tożsamości";
+"settings_analytics_and_crash_data" = "Wysyłaj dane analityczne i o zawieszeniu aplikacji";
+"settings_labs_enabled_polls" = "Ankiety";
+"settings_contacts_enable_sync" = "Znajdź swoje kontakty";
+"settings_phone_contacts" = "KONTAKTY TELEFONICZNE";
+"settings_links" = "LINKI";
+"room_event_action_forward" = "Przekaż dalej";
+"room_event_action_end_poll" = "Zakończ ankietę";
+"room_event_action_remove_poll" = "Usuń ankietę";
+"find_your_contacts_identity_service_error" = "Nie można połączyć się s serwerem tożsamości.";
+"contacts_address_book_permission_denied_alert_message" = "Aby włączyć kontakty, wejdź do ustawień Twojego urządzenia.";
+"contacts_address_book_permission_denied_alert_title" = "Kontakty wyłączone";
+"room_recents_suggested_rooms_section" = "SUGEROWANE POKOJE";
+"onboarding_splash_page_1_message" = "Bezpieczna i niezależna komunikacja dająca Tobie ten sam poziom prywatności jak rozmowa twarzą w twarz w Twoim domu.";
+"onboarding_splash_login_button_title" = "Mam już konto";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Stwórz konto";
+"accessibility_button_label" = "przycisk";
+"done" = "Gotowe";
+"open" = "Otwórz";
+"enable" = "Włącz";
+"ok" = "OK";
diff --git a/Riot/Assets/pt_BR.lproj/InfoPlist.strings b/Riot/Assets/pt_BR.lproj/InfoPlist.strings
index bb44cdb98..28cf8e2b8 100644
--- a/Riot/Assets/pt_BR.lproj/InfoPlist.strings
+++ b/Riot/Assets/pt_BR.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSContactsUsageDescription" = "Element vai mostrar seus contatos para que você possa convidá-los a conversar.";
"NSCalendarsUsageDescription" = "Ver suas reuniões agendadas no app.";
"NSFaceIDUsageDescription" = "Face ID é usada para acessar seu app.";
+"NSLocationWhenInUseUsageDescription" = "Quando você compartilha sua localização para pessoas, Element precisa de acesso para mostrar-lhes um mapa.";
diff --git a/Riot/Assets/pt_BR.lproj/Localizable.strings b/Riot/Assets/pt_BR.lproj/Localizable.strings
index 165ee183e..51f9faf5f 100644
--- a/Riot/Assets/pt_BR.lproj/Localizable.strings
+++ b/Riot/Assets/pt_BR.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Notificação";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ compartilhou a localização dela(e)";
diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings
index 7820fc1f4..8e6dbc79e 100644
--- a/Riot/Assets/pt_BR.lproj/Vector.strings
+++ b/Riot/Assets/pt_BR.lproj/Vector.strings
@@ -87,7 +87,7 @@
"auth_reset_password_error_unauthorized" = "Falha para verificar endereço de email: assegure que você clicou no link no email";
"auth_reset_password_error_not_found" = "Seu endereço de email não parece estar associado com uma ID Matrix neste servidorcasa.";
"auth_reset_password_success_message" = "Sua senha tem sido resettada.\n\nVocê tem sido feito logout de todas as sessões e não vai mais receber notificações push. Para re-habilitar notificações, refaça login em cada dispositivo.";
-"auth_add_email_and_phone_warning" = "Registro com email e número de telefone ao mesmo tempo não é suportado ainda até que a api exista. Somente o número de telefone vai ser levado em conta. Você pode adicionar seu email a seu perfil em configurações.";
+"auth_add_email_and_phone_warning" = "Registro com email e número de telefone ao mesmo tempo não é suportado ainda até que a api exista. Somente o número de telefone vai ser levado em conta. Você pode adicionar seu email a seu perfil em ajustes.";
"room_creation_appearance" = "Aparência";
"room_creation_appearance_name" = "Nome";
"room_creation_appearance_picture" = "Imagem de Chat (opcional)";
@@ -275,7 +275,7 @@
"room_preview_try_join_an_unknown_room" = "Você está tentando acessar %@. Você gostaria de se juntar para participar na discussão?";
"room_preview_try_join_an_unknown_room_default" = "uma sala";
// Settings
-"settings_title" = "Configurações";
+"settings_title" = "Ajustes";
"account_logout_all" = "Fazer logout de todas as contas";
"settings_config_no_build_info" = "Nenhuma info de build";
"settings_mark_all_as_read" = "Marcar todas as mensagens como lidas";
@@ -283,7 +283,7 @@
"settings_config_home_server" = "Servidorcasa é %@";
"settings_config_identity_server" = "Servidor de identidade é %@";
"settings_config_user_id" = "Feito login como %@";
-"settings_user_settings" = "CONFIGURAÇÕES DE USUÁRIA(O)";
+"settings_user_settings" = "AJUSTES DE USUÁRIA(O)";
"settings_notifications_settings" = "CONFIGURAÇÕES DE NOTIFICAÇÃO";
"settings_calls_settings" = "CHAMADAS";
"settings_user_interface" = "INTERFACE DE USUÁRIA(O)";
@@ -316,7 +316,7 @@
"settings_fail_to_update_profile" = "Falha para atualizar perfil";
"settings_enable_push_notif" = "Notificações neste dispositivo";
"settings_show_decrypted_content" = "Mostrar conteúdo decriptado";
-"settings_global_settings_info" = "Configurações de notificação globais estão disponíveis em seu cliente web %@";
+"settings_global_settings_info" = "Ajustes de notificação globais estão disponíveis em seu cliente web %@";
"settings_enable_callkit" = "Chamamento integrado";
"settings_callkit_info" = "Receba chamadas entrantes em sua tela de bloqueio. Veja suas chamadas %@ no histórico de chamadas do sistema. Se iCloud está habilitado, este histórico de chamadas vai ser compartilhado com Apple.";
"settings_ui_language" = "Língua";
@@ -361,7 +361,7 @@
"settings_deactivate_my_account" = "Desativar minha conta";
"room_details_people" = "Membros";
"room_details_files" = "Uploads";
-"room_details_settings" = "Configurações";
+"room_details_settings" = "Ajustes";
"room_details_photo" = "Foto de Sala";
"room_details_room_name" = "Nome de Sala";
"room_details_topic" = "Tópico";
@@ -482,7 +482,7 @@
"bug_report_prompt" = "O aplicativo tem crashado da última vez. Você gostaria de submeter um reporte de crash?";
"rage_shake_prompt" = "Você parece estar agitando o telefone em frustração. Você gostaria de submeter um reporte de bug?";
"do_not_ask_again" = "Não perguntar de novo";
-"camera_access_not_granted" = "%@ não tem permissão para usar Câmera, por favor mude configurações de privacidade";
+"camera_access_not_granted" = "%@ não tem permissão para usar Câmera, por favor mude ajustes de privacidade";
"large_badge_value_k_format" = "%.1fK";
// Call
"call_incoming_voice_prompt" = "Chamada de voz entrante de %@";
@@ -497,7 +497,7 @@
// Crash report
"google_analytics_use_prompt" = "Você gostaria de ajudar a melhorar %@ ao reportar automaticamente reportes de crash e dados de uso anônimos?";
// Crypto
-"e2e_enabling_on_app_update" = "%@ agora suporta encriptação ponta-a-ponta mas você precisa fazer login de novo para habilitá-la.\n\nVocê pode fazê-lo agora ou mais tarde desde as configurações do aplicativo.";
+"e2e_enabling_on_app_update" = "%@ agora suporta encriptação ponta-a-ponta mas você precisa fazer login de novo para habilitá-la.\n\nVocê pode fazê-lo agora ou mais tarde desde os ajustes do aplicativo.";
"e2e_need_log_in_again" = "Você precisa fazer login de volta para gerar chaves de encriptação ponta-a-ponta para esta sessão e submeter a chave pública a seu servidorcasa.\nIsto é só desta vez; desculpe pela inconveniência.";
// Bug report
"bug_report_title" = "Report de Bug";
@@ -528,7 +528,7 @@
"widget_integration_room_not_visible" = "Sala %@ não está visível.";
// Share extension
"share_extension_auth_prompt" = "Faça login no app principal para compartilhar conteúdo";
-"share_extension_failed_to_encrypt" = "Falha para enviar. Cheque no app principal as configurações de encriptação para esta sala";
+"share_extension_failed_to_encrypt" = "Falha para enviar. Cheque no app principal os ajustes de encriptação para esta sala";
// Room key request dialog
"e2e_room_key_request_title" = "Requisição de chave de encriptação";
"e2e_room_key_request_message_new_device" = "Você adicionou uma nova sessão '%@', que está requisitando chaves de encriptação.";
@@ -586,8 +586,8 @@
"room_does_not_exist" = "%@ não existe";
// Key backup wrong version
"e2e_key_backup_wrong_version_title" = "Novo Backup de Chave";
-"e2e_key_backup_wrong_version" = "Um novo backup de chave de mensagem segura tem sido detectado.\n\nSe isto não foi você, defina uma nova Frase de Segurança em Configurações.";
-"e2e_key_backup_wrong_version_button_settings" = "Configurações";
+"e2e_key_backup_wrong_version" = "Um novo backup de chave de mensagem segura tem sido detectado.\n\nSe isto não foi você, defina uma nova Frase de Segurança em Ajustes.";
+"e2e_key_backup_wrong_version_button_settings" = "Ajustes";
"e2e_key_backup_wrong_version_button_wasme" = "Foi eu";
"key_backup_setup_title" = "Backup de Chave";
"key_backup_setup_skip_alert_title" = "Você tem certeza?";
@@ -625,7 +625,7 @@
"key_backup_recover_title" = "Mensagens Seguras";
"key_backup_recover_invalid_passphrase_title" = "Frase de Segurança Incorreta";
"key_backup_recover_invalid_passphrase" = "Backup não pôde ser decriptado com esta frase: por favor verifique que você entrou a Frase de Segurança correta.";
-"key_backup_recover_invalid_recovery_key_title" = "Disparidade de Chave de Segurança";
+"key_backup_recover_invalid_recovery_key_title" = "Correspondência Errada de Chave de Segurança";
"key_backup_recover_invalid_recovery_key" = "Backup não pôde ser decriptografado com esta chave: por favor verifique que você entrou a Chave de Segurança correta.";
"key_backup_recover_from_passphrase_info" = "Use sua Frase de Segurança para destrancar seu histórico de mensagens seguras";
"key_backup_recover_from_passphrase_passphrase_title" = "Entrar";
@@ -638,7 +638,7 @@
"key_backup_recover_from_recovery_key_recovery_key_title" = "Entrar";
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Entrar Chave de Segurança";
"key_backup_recover_from_recovery_key_recover_action" = "Destrancar Histórico";
-"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Perdeu sua Chave de Segurança? Você pode configurar uma nova em configurações.";
+"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Perdeu sua Chave de Segurança? Você pode configurar uma nova em ajustes.";
"key_backup_recover_success_info" = "Backup Restaurado!";
"key_backup_recover_done_action" = "Feito";
"key_backup_setup_banner_title" = "Nunca perca mensagens criptografadas";
@@ -677,7 +677,7 @@
"secure_key_backup_setup_existing_backup_error_unlock_it" = "Destrancá-lo";
"secure_key_backup_setup_existing_backup_error_delete_it" = "Deletá-lo";
"secure_key_backup_setup_cancel_alert_title" = "Você tem certeza?";
-"secure_key_backup_setup_cancel_alert_message" = "Se você cancelar agora, você pode perder mensagens & dados encriptados se você perder acesso a seus logins.\n\nVocê também pode configurar Backup Seguro & gerenciar suas chaves em Configurações.";
+"secure_key_backup_setup_cancel_alert_message" = "Se você cancelar agora, você pode perder mensagens & dados encriptados se você perder acesso a seus logins.\n\nVocê também pode configurar Backup Seguro & gerenciar suas chaves em Ajustes.";
"secure_backup_setup_banner_title" = "Backup Seguro";
"secure_backup_setup_banner_subtitle" = "Salvaguardar-se contra perda de acesso a mensagens & dados encriptados";
// Recover from private key
@@ -722,7 +722,7 @@
"settings_integrations_allow_button" = "Gerenciar integrações";
"settings_integrations_allow_description" = "Use um gerenciador de integrações (%@) para gerenciar bots, bridges, widgets e pacotes de stickers.\n\nGerenciadores de integrações recebem dados de configuração, e podem modificar widgets, enviar convites de sala e definir níveis de poder em seu nome.";
"settings_add_3pid_password_title_email" = "Adicionar endereço de email";
-"settings_discovery_three_pids_management_information_part2" = "Configurações de Usuária(o)";
+"settings_discovery_three_pids_management_information_part2" = "Ajustes de Usuária(o)";
"settings_discovery_three_pids_management_information_part3" = ".";
"settings_discovery_three_pid_details_share_action" = "Compartilhar";
"settings_discovery_three_pid_details_revoke_action" = "Revogar";
@@ -747,7 +747,7 @@
// Media picker
"media_picker_title" = "Biblioteca de mídia";
"image_picker_action_library" = "Escolher de biblioteca";
-"photo_library_access_not_granted" = "%@ não tem permissão para acessar biblioteca de fotos, por favor mude configurações de privacidade";
+"photo_library_access_not_granted" = "%@ não tem permissão para acessar biblioteca de fotos, por favor mude ajustes de privacidade";
"room_widget_permission_display_name_permission" = "Seu nome de exibição";
"device_verification_security_advice_emoji" = "Compare os emoji únicos, garantindo que eles aparecem na mesma ordem.";
"device_verification_self_verify_alert_message" = "Verifique o novo login acessando sua conta: %@";
@@ -794,14 +794,14 @@
"identity_server_settings_disconnect_info" = "Desconectar-se de seu servidor de identidade vai significar que você não vai ser descobertável por outras(os) usuárias(os) e ser capaz de convidar outras(os) por email ou telefone.";
"identity_server_settings_alert_disconnect_still_sharing_3pid" = "Você ainda está compartilhando seus dados pessoais no servidor de identidade %@.\n\nNós recomendamos que você remova seus endereços de email e números de telefone do servidor de identidade antes de se desconectar.";
"call_no_stun_server_error_title" = "Chamada falhou devido a servidor malconfigurado";
-"widget_integration_manager_disabled" = "Você precisa habilitar gerenciador de integrações em configurações";
+"widget_integration_manager_disabled" = "Você precisa habilitar gerenciador de integrações em ajustes";
"service_terms_modal_description_for_identity_server_1" = "Encontrar outras(os) por telefone ou email";
"service_terms_modal_description_for_identity_server_2" = "Ser encontrada(o) por telefone ou email";
"device_verification_self_verify_wait_additional_information" = "Isto funciona com %@ e outros clientes Matrix capazes de assinatura cruzada.";
"key_verification_verified_user_information" = "Mensagens com esta(e) usuária(o) são encriptadas ponta-a-ponta e não podem ser lidas por terceiros.";
"device_verification_emoji_smiley" = "Smiley";
// Generic errors
-"error_invite_3pid_with_no_identity_server" = "Adicione um servidor de identidade em suas configurações para convidar por email.";
+"error_invite_3pid_with_no_identity_server" = "Adicione um servidor de identidade em seus ajustes para convidar por email.";
"key_verification_bootstrap_not_setup_message" = "Você precisa fazer bootstrap de assinatura cruzada primeiro.";
"user_verification_sessions_list_user_trust_level_warning_title" = "Aviso";
"user_verification_sessions_list_information" = "Mensagens com esta(e) usuária(o) nesta sala são encriptadas ponta-a-ponta e não podem ser lidas por terceiros.";
@@ -907,7 +907,7 @@
"event_formatter_widget_added_by_you" = "Você adicionou o widget: %@";
"event_formatter_widget_removed_by_you" = "Você removeu o widget: %@";
"camera_unavailable" = "A câmera está indisponível em seu dispositivo";
-"call_no_stun_server_error_message_2" = "Alternativamente, você pode tentar usar o servidor público em %@, mas isto não vai ser tão confiável, e vai compartilhar seu endereço de IP com esse servidor. Você também pode gerenciar isto em Configurações";
+"call_no_stun_server_error_message_2" = "Alternativamente, você pode tentar usar o servidor público em %@, mas isto não vai ser tão confiável, e vai compartilhar seu endereço de IP com esse servidor. Você também pode gerenciar isto em Ajustes";
"call_no_stun_server_error_use_fallback_button" = "Tentar usar %@";
// Widget
"widget_no_integrations_server_configured" = "Nenhum servidor de integrações configurado";
@@ -974,7 +974,7 @@
"key_verification_verify_sas_cancel_action" = "Eles não correspondem";
"key_verification_verify_sas_validate_action" = "Eles correspondem";
"key_verification_verify_sas_additional_information" = "Para segurança ótima, use um outro meio de comunicação confiado ou faça isto em pessoa.";
-"key_verification_manually_verify_device_instruction" = "Confirme ao comparar o seguinte com as Configurações de Usuária(o) em sua outra sessão:";
+"key_verification_manually_verify_device_instruction" = "Confirme ao comparar o seguinte com os Ajustes de Usuária(o) em sua outra sessão:";
"key_verification_manually_verify_device_name_title" = "Nome de sessão";
"key_verification_manually_verify_device_id_title" = "ID de sessão";
"key_verification_manually_verify_device_key_title" = "Chave de sessão";
@@ -1350,7 +1350,7 @@
"side_menu_app_version" = "Versão %@";
"side_menu_action_feedback" = "Feedback";
"side_menu_action_help" = "Ajuda";
-"side_menu_action_settings" = "Configurações";
+"side_menu_action_settings" = "Ajustes";
"side_menu_action_invite_friends" = "Convidar amigas(os)";
// Mark: - Side menu
@@ -1370,13 +1370,13 @@
"security_settings_secure_backup_reset" = "Resettar";
"security_settings_secure_backup_info_valid" = "Esta sessão está fazendo backup de suas chaves.";
"security_settings_secure_backup_info_checking" = "Checando…";
-"settings_ui_theme_picker_message_match_system_theme" = "\"Auto\" corresponde ao tema de sistema de seu dispositivo";
-"settings_ui_theme_picker_message_invert_colours" = "\"Auto\" usa as configurações \"Inverter Cores\" de seu dispositivo";
+"settings_ui_theme_picker_message_match_system_theme" = "\"Auto\" corresponde com o tema de sistema de seu dispositivo";
+"settings_ui_theme_picker_message_invert_colours" = "\"Auto\" usa os ajustes \"Inverter Cores\" de seu dispositivo";
"room_recents_unknown_room_error_message" = "Não dá para encontrar esta sala. Assegure que ela existe";
"room_creation_dm_error" = "Nós não conseguimos criar sua DM. Por favor cheque as/os usuárias(os) que você quer convidar e tente de novo.";
"key_verification_verify_qr_code_scan_code_other_device_action" = "Scannar com este dispositivo";
"room_notifs_settings_encrypted_room_notice" = "Por favor note que notificações de menções & palavrachave não estão disponíveis em salas encriptadas no celular.";
-"room_notifs_settings_account_settings" = "Configurações de conta";
+"room_notifs_settings_account_settings" = "Ajustes de conta";
"room_notifs_settings_manage_notifications" = "Você pode gerenciar notificações em %@";
"room_notifs_settings_cancel_action" = "Cancelar";
"room_notifs_settings_done_action" = "Feito";
@@ -1395,7 +1395,7 @@
"voice_message_release_to_send" = "Segure para gravar, solte para enviar";
"settings_labs_voice_messages" = "Mensagens de voz";
"settings_notifications_disabled_alert_title" = "Notificações desabilitadas";
-"settings_notifications_disabled_alert_message" = "Para habilitar notificações, vá para suas configurações de dispositivo.";
+"settings_notifications_disabled_alert_message" = "Para habilitar notificações, vá para os ajustes de seu dispositivo.";
"settings_device_notifications" = "Notificações de dispositivo";
"event_formatter_call_incoming_video" = "Chamada de vídeo entrante";
"event_formatter_call_incoming_voice" = "Chamada de voz entrante";
@@ -1451,7 +1451,7 @@
"space_private_join_rule" = "Espaço privado";
"space_participants_action_ban" = "Banir deste espaço";
"space_participants_action_remove" = "Remover deste espaço";
-"spaces_coming_soon_detail" = "Esta funcionalidade não tem sido implementada ainda, mas está a caminho. Por enquanto, você pode fazer isso com Element em seu computador.";
+"spaces_coming_soon_detail" = "Esta funcionalidade não tem sido implementada ainda, mas está a caminho. Por enquanto, você pode fazer isso com %@ em seu computador.";
"spaces_invites_coming_soon_title" = "Convites chegando em breve";
"spaces_add_rooms_coming_soon_title" = "Adicionar salas chegando em breve";
"spaces_coming_soon_title" = "Chegando em breve";
@@ -1484,7 +1484,7 @@
"service_terms_modal_description_identity_server" = "Isto vai permitir alguém encontrar você se ela/ele tem seu número de telefone ou email salvo nos contatos de telefone dela/dele.";
"service_terms_modal_table_header_integration_manager" = "TERMOS DE GERENCIADOR DE INTEGRAÇÕES";
"service_terms_modal_table_header_identity_server" = "TERMOS DE SERVIDOR DE IDENTIDADE";
-"service_terms_modal_footer" = "Isto pode ser desabilitado a qualquer hora em configurações.";
+"service_terms_modal_footer" = "Isto pode ser desabilitado a qualquer hora em ajustes.";
// Service terms
"service_terms_modal_title_message" = "Para continuar, aceite os termos e condições abaixo";
@@ -1492,11 +1492,11 @@
"settings_contacts_enable_sync" = "Encontre seus contatos";
"settings_phone_contacts" = "CONTATOS DE TELEFONE";
"find_your_contacts_identity_service_error" = "Incapaz de se conectar ao servidor de identidade.";
-"find_your_contacts_footer" = "Isto pode ser desabilitado a qualquer hora a partir de configurações.";
+"find_your_contacts_footer" = "Isto pode ser desabilitado a qualquer hora a partir de ajustes.";
"find_your_contacts_button_title" = "Encontre seus contatos";
"find_your_contacts_message" = "Deixe %@ mostrar seus contatos para que você possa rapidamente começar a conversar com aqueles que você conhece melhor.";
"find_your_contacts_title" = "Comece por listar seus contatos";
-"contacts_address_book_permission_denied_alert_message" = "Para habilitar contatos, vá para as configurações de seu dispositivo.";
+"contacts_address_book_permission_denied_alert_message" = "Para habilitar contatos, vá para os ajustes de seu dispositivo.";
"contacts_address_book_permission_denied_alert_title" = "Contatos desabilitados";
"space_home_show_all_rooms" = "Mostrar todas as salas";
"room_event_action_forward" = "Encaminhar";
@@ -1539,7 +1539,7 @@
"analytics_prompt_stop" = "Parar de compartilhar";
"analytics_prompt_yes" = "Sim, pode ser";
"analytics_prompt_not_now" = "Não agora";
-"analytics_prompt_point_3" = "Você pode desativar isto a qualquer hora em configurações";
+"analytics_prompt_point_3" = "Você pode desativar isto a qualquer hora em ajustes";
/* Note: The word "don't" is formatted in bold */
"analytics_prompt_point_2" = "Nós não compartilhamos informação com terceiros";
/* Note: The word "don't" is formatted in bold */
@@ -1551,10 +1551,39 @@
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Você pode ler todos os nossos termos %@.";
"analytics_prompt_message_upgrade" = "Você previamente consentiu a compartilhar dados de uso anônimos conosco. Agora, para ajudar a entender como pessoas usam múltiplos dispositivos, nós vamos gerar um identificador aleatório, compartilhado por seus dispositivos.";
-"analytics_prompt_message_new_user" = "Ajude-nos a identificar problemas e melhorar Element ao compartilhar dados de uso anônimos. Para entender como pessoas usam múltiplos dispositivos, nós geramos um identificador aleatório, compartilhado por seus dispositivos.";
+"analytics_prompt_message_new_user" = "Ajude-nos a identificar problemas e melhorar %@ ao compartilhar dados de uso anônimos. Para entender como pessoas usam múltiplos dispositivos, nós geramos um identificador aleatório, compartilhado por seus dispositivos.";
// Analytics
-"analytics_prompt_title" = "Ajudar a melhorar %@";
+"analytics_prompt_title" = "Ajude a melhorar %@";
"settings_analytics_and_crash_data" = "Enviar dados de crash e analítica";
"accessibility_button_label" = "botão";
"enable" = "Habilitar";
+"location_sharing_settings_toggle_title" = "Habilitar compartilhamento de local";
+"location_sharing_settings_header" = "Compartilhamento de local";
+"location_sharing_invalid_authorization_error_title" = "%@ não tem permissão para acessar seu local. Você pode habilitar acesso em Ajustes > Local";
+"location_sharing_locating_user_error_title" = "%@ não pôde acessar seu local. Por favor tente de novo mais tarde.";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Local";
+"location_sharing_open_google_maps" = "Abrir em Google Maps";
+"location_sharing_open_apple_maps" = "Abrir em Apple Mapas";
+"location_sharing_invalid_authorization_settings" = "Ajustes";
+"location_sharing_invalid_authorization_not_now" = "Não agora";
+"location_sharing_loading_map_error_title" = "%@ não pôde carregar o mapa. Por favor tente de novo mais tarde.";
+"location_sharing_share_action" = "Compartilhar";
+"location_sharing_close_action" = "Fechar";
+"ok" = "OK";
+"onboarding_splash_page_1_message" = "Comunicação segura e independente que lhe dá o mesmo nível de privacidade que uma conversa face-a-face em sua própria casa.";
+"settings_enable_room_message_bubbles" = "Bolhas de mensagem";
+"onboarding_splash_page_4_message" = "Elemente também é ótimo para o lugar de trabalho. É confiado pelas organizações mais seguras do mundo.";
+"onboarding_splash_page_4_title_no_pun" = "Mensageria para seu time.";
+"onboarding_splash_page_3_message" = "Encriptado ponta-a-ponta e nenhum número de telefone requerido. Sem publicidade ou datamining.";
+"onboarding_splash_page_3_title" = "Mensageria segura.";
+"onboarding_splash_page_2_message" = "Escolha onde suas conversas são mantidas, dando-lhe controle e independência. Conectado via Matrix.";
+"onboarding_splash_page_2_title" = "Você está em controle.";
+"onboarding_splash_page_1_title" = "Tenha posse de suas conversas.";
+"onboarding_splash_login_button_title" = "Eu já tenho uma conta";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Criar conta";
diff --git a/Riot/Assets/sk.lproj/InfoPlist.strings b/Riot/Assets/sk.lproj/InfoPlist.strings
index 9d8892825..704899a7f 100644
--- a/Riot/Assets/sk.lproj/InfoPlist.strings
+++ b/Riot/Assets/sk.lproj/InfoPlist.strings
@@ -7,3 +7,4 @@
"NSPhotoLibraryUsageDescription" = "Knižnica fotografií sa používa na odosielanie fotografií a videí.";
// Permissions usage explanations
"NSCameraUsageDescription" = "Fotoaparát sa používa na snímanie fotografií a videí, uskutočňovanie videohovorov.";
+"NSLocationWhenInUseUsageDescription" = "Keď zdieľate svoju polohu s ľuďmi, Element potrebuje prístup, aby im mohol zobraziť mapu.";
diff --git a/Riot/Assets/sk.lproj/Localizable.strings b/Riot/Assets/sk.lproj/Localizable.strings
index 0ba5126ce..fffb34696 100644
--- a/Riot/Assets/sk.lproj/Localizable.strings
+++ b/Riot/Assets/sk.lproj/Localizable.strings
@@ -165,3 +165,6 @@
/* New message reply from a specific person in a named room. */
"REPLY_FROM_USER_IN_ROOM_TITLE" = "%@ odpovedal/a v %@";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ zdieľal/a svoju polohu";
diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings
index ded23fa74..b86434589 100644
--- a/Riot/Assets/sk.lproj/Vector.strings
+++ b/Riot/Assets/sk.lproj/Vector.strings
@@ -753,7 +753,7 @@
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Nie je možné získať prístup k tajnému úložisku";
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "použiť váš bezpečnostný kľúč";
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Neviete svoju bezpečnostnú frázu? Môžete ";
-"secrets_recovery_with_passphrase_passphrase_placeholder" = "Vložiť bezpečnostnú frázu";
+"secrets_recovery_with_passphrase_passphrase_placeholder" = "Zadajte bezpečnostnú frázu";
"secrets_recovery_with_passphrase_information_verify_device" = "Na overenie tohto zariadenia použite bezpečnostnú frázu.";
"user_verification_session_details_information_untrusted_current_user" = "Overte túto reláciu, aby ste ju označili za dôveryhodnú a udelili jej prístup k zašifrovaným správam:";
"user_verification_session_details_information_trusted_other_user_part2" = " ste ju overili:";
@@ -1186,7 +1186,7 @@
"space_home_show_all_rooms" = "Zobraziť všetky miestnosti";
"space_participants_action_ban" = "Vylúčiť z tohto priestoru";
"space_participants_action_remove" = "Odstrániť z tohto priestoru";
-"spaces_coming_soon_detail" = "Táto funkcia tu ešte nebola zapracovaná, ale je na ceste k jej zapracovaniu. Zatiaľ to môžete urobiť pomocou aplikácie Element v počítači.";
+"spaces_coming_soon_detail" = "Táto funkcia tu ešte nebola zapracovaná, ale je na ceste k jej zapracovaniu. Zatiaľ to môžete urobiť pomocou %@ na vašom počítači.";
"spaces_invites_coming_soon_title" = "Pozvánky už čoskoro";
"spaces_add_rooms_coming_soon_title" = "Pridávanie miestností už čoskoro";
"spaces_no_member_found_detail" = "Hľadáte niekoho, kto nie je v %@? Zatiaľ ich môžete pozvať na webe alebo na počítači.";
@@ -1502,7 +1502,7 @@
"analytics_prompt_stop" = "Zastaviť zdieľanie";
"analytics_prompt_yes" = "Áno, je to v poriadku";
"analytics_prompt_message_upgrade" = "Predtým ste nám udelili súhlas so zdieľaním anonymných údajov o používaní. Teraz, aby sme pomohli pochopiť, ako ľudia používajú viacero zariadení, vygenerujeme náhodný identifikátor zdieľaný vašimi zariadeniami.";
-"analytics_prompt_message_new_user" = "Pomôžte nám identifikovať problémy a zlepšiť Element zdieľaním anonymných údajov o používaní. Aby sme pochopili, ako ľudia používajú viacero zariadení, vygenerujeme náhodný identifikátor, ktorý zdieľajú vaše zariadenia.";
+"analytics_prompt_message_new_user" = "Pomôžte nám identifikovať problémy a zlepšiť %@ zdieľaním anonymných údajov o používaní. Aby sme pochopili, ako ľudia používajú viacero zariadení, vygenerujeme náhodný identifikátor zdieľaný vašimi zariadeniami.";
// Analytics
"analytics_prompt_title" = "Pomôžte zlepšiť %@";
@@ -1619,3 +1619,48 @@
// Recover from recovery key
"key_backup_recover_from_recovery_key_info" = "Použite svoju bezpečnostný kľúč na odomknutie histórie zabezpečených správ";
+"widget_sticker_picker_no_stickerpacks_alert" = "Momentálne nemáte aktívne žiadne balíčky s nálepkami.";
+"widget_integrations_server_failed_to_connect" = "Nepodarilo sa pripojiť k integračnému serveru";
+"no_voip" = "%@ vám volá, ale %@ zatiaľ nepodporuje hovory.\nToto oznámenie môžete ignorovať a prijať hovor z iného zariadenia alebo ho môžete odmietnuť.";
+"call_actions_unhold" = "Pokračovať";
+"call_jitsi_error" = "Nepodarilo sa pripojiť ku konferenčnému hovoru.";
+"rage_shake_prompt" = "Zdá sa, že rozčúlene trasiete telefónom. Chceli by ste odoslať hlásenie o chybe?";
+"room_details_addresses_disable_main_address_prompt_msg" = "Nebudete mať zadanú žiadnu hlavnú adresu. Predvolená hlavná adresa pre túto miestnosť sa vyberie náhodne";
+"settings_enable_rageshake" = "Zúrivo potraste pre nahlásenie chyby";
+"settings_ui_theme_picker_message_match_system_theme" = "\"Auto\" zodpovedá systémovej téme vášho zariadenia";
+"settings_pin_rooms_with_unread" = "Pripnúť miestnosti s neprečítanými správami";
+"settings_pin_rooms_with_missed_notif" = "Pripnúť miestnosti so zmeškanými oznámeniami";
+"settings_confirm_media_size" = "Potvrdiť veľkosť pri odosielaní";
+"ok" = "OK";
+"poll_edit_form_question_or_topic" = "Otázka alebo téma";
+"poll_timeline_vote_not_registered_title" = "Hlas nebol zaznamenaný";
+"poll_timeline_vote_not_registered_subtitle" = "Je nám ľúto, váš hlas nebol zaznamenaný. Skúste to prosím znova";
+"poll_timeline_not_closed_title" = "Nepodarilo sa ukončiť anketu";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Poloha";
+"location_sharing_close_action" = "Zavrieť";
+"location_sharing_share_action" = "Zdieľať";
+"location_sharing_loading_map_error_title" = "%@ sa nepodarilo načítať mapu. Skúste to prosím neskôr.";
+"location_sharing_locating_user_error_title" = "%@ sa nepodarilo získať prístup k vašej polohe. Skúste to prosím neskôr.";
+"location_sharing_invalid_authorization_error_title" = "%@ nemá povolenie na prístup k vašej polohe. Prístup môžete povoliť v ponuke Nastavenia > Poloha";
+"location_sharing_invalid_authorization_not_now" = "Teraz nie";
+"location_sharing_invalid_authorization_settings" = "Nastavenia";
+"location_sharing_open_apple_maps" = "Otvoriť v službe Apple Mapy";
+"location_sharing_open_google_maps" = "Otvoriť v službe Mapy Google";
+"location_sharing_settings_header" = "Zdieľanie polohy";
+"location_sharing_settings_toggle_title" = "Povoliť zdieľanie polohy";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Vytvoriť účet";
+"onboarding_splash_login_button_title" = "Už mám účet";
+"onboarding_splash_page_1_title" = "Vlastnite svoje konverzácie.";
+"onboarding_splash_page_1_message" = "Bezpečná a nezávislá komunikácia, ktorá vám poskytuje rovnakú úroveň súkromia ako rozhovor zoči-voči vo vašom vlastnom dome.";
+"onboarding_splash_page_2_title" = "Vy máte všetko pod kontrolou.";
+"onboarding_splash_page_2_message" = "Vyberte si, kde budú vaše rozhovory uložené, a získajte tak kontrolu a nezávislosť. Pripojené cez Matrix.";
+"onboarding_splash_page_3_title" = "Zabezpečené zasielanie správ.";
+"onboarding_splash_page_3_message" = "End-to-end šifrovanie a bez potreby telefónneho čísla. Žiadne reklamy ani zneužívanie údajov.";
+"onboarding_splash_page_4_title_no_pun" = "Zasielanie správ pre váš tím.";
+"onboarding_splash_page_4_message" = "Element je skvelý aj na pracovisku. Dôverujú mu najbezpečnejšie organizácie na svete.";
+"settings_enable_room_message_bubbles" = "Správy v bublinách";
diff --git a/Riot/Assets/sq.lproj/InfoPlist.strings b/Riot/Assets/sq.lproj/InfoPlist.strings
index ee2f2697a..bfeef7694 100644
--- a/Riot/Assets/sq.lproj/InfoPlist.strings
+++ b/Riot/Assets/sq.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSContactsUsageDescription" = "Element-i do të shfaqë kontaktet tuaja, që kështu të mund t’i ftoni për të biseduar.";
"NSCalendarsUsageDescription" = "Shihini te aplikacioni takimet tuaja të planifikuara.";
"NSFaceIDUsageDescription" = "Face ID përdoret që të hyni në aplikacionin tuaj.";
+"NSLocationWhenInUseUsageDescription" = "Kur ndani vendndodhjen tuaj me persona, Element-i ka nevojë për hyrje në të, që t’u trgojë atyre një hartë.";
diff --git a/Riot/Assets/sq.lproj/Localizable.strings b/Riot/Assets/sq.lproj/Localizable.strings
index 6bec05eba..ad7a81203 100644
--- a/Riot/Assets/sq.lproj/Localizable.strings
+++ b/Riot/Assets/sq.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Njoftim";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ tregoi vendndodhjen e vet";
diff --git a/Riot/Assets/sq.lproj/Vector.strings b/Riot/Assets/sq.lproj/Vector.strings
index bca45030c..9c8151004 100644
--- a/Riot/Assets/sq.lproj/Vector.strings
+++ b/Riot/Assets/sq.lproj/Vector.strings
@@ -1471,7 +1471,7 @@
"space_private_join_rule" = "Hapësirë private";
"space_participants_action_ban" = "Dëboje prej kësaj hapësire";
"space_participants_action_remove" = "Hiqe prej kësaj hapësire";
-"spaces_coming_soon_detail" = "Kjo veçori s’është sendërtuar këtu, por po bëhet. Tani për tani, mund ta bëni këtë me Element-in në kompjuterin tuaj.";
+"spaces_coming_soon_detail" = "Kjo veçori s’është sendërtuar këtu, por po bëhet. Tani për tani, mund ta bëni këtë me %@-in në kompjuterin tuaj.";
"spaces_invites_coming_soon_title" = "Ftesat vijnë së shpejti";
"spaces_add_rooms_coming_soon_title" = "Shtimi i dhomave vjen së shpejti";
"spaces_coming_soon_title" = "S’afërmi";
@@ -1565,7 +1565,7 @@
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Mund të lexoni krejt kushtet tona %@.";
"analytics_prompt_message_upgrade" = "Keni pranuar më herët të ndani me ne të dhëna anonime përdorimi. Tani, që të na ndihmoni të kuptojmë se si njerëzit përdorin pajisje të shumta, do të prodhojmë një identifikues kuturu, të përbashkët për pajisjet tuaja.";
-"analytics_prompt_message_new_user" = "Ndihmonani të identifikojmë probleme dhe të përmirësojmë Element-in, duke ndarë me ne të dhëna anonime përdorimi. Për të kuptuar se si i përdorin njerëzit disa pajisje njëherësh, do të prodhojmë një identifikues kuturu, të përbashkët për pajisjet tuaja.";
+"analytics_prompt_message_new_user" = "Ndihmonani të identifikojmë probleme dhe të përmirësojmë %@-in, duke ndarë me ne të dhëna anonime përdorimi. Për të kuptuar se si i përdorin njerëzit disa pajisje njëherësh, do të prodhojmë një identifikues kuturu, të përbashkët për pajisjet tuaja.";
// Analytics
"analytics_prompt_title" = "Ndihmoni të përmirësohet %@";
@@ -1579,3 +1579,32 @@
"accessibility_button_label" = "kopsë";
"open" = "Hapur";
"enable" = "Aktivizoje";
+"location_sharing_settings_toggle_title" = "Aktivizoni tregim vendndodhjeje";
+"location_sharing_settings_header" = "Tregim vendndodhjeje";
+"location_sharing_open_google_maps" = "Hape në Google Maps";
+"location_sharing_open_apple_maps" = "Hape në Apple Maps";
+"location_sharing_invalid_authorization_settings" = "Rregullime";
+"location_sharing_invalid_authorization_not_now" = "Jo tani";
+"location_sharing_locating_user_error_title" = "%@ s’njohu dot vendndodhjen tuaj. Ju lutemi, riprovoni më vonë.";
+"location_sharing_invalid_authorization_error_title" = "%@ s’ka leje të njohë vendndodhjen tuaj. Njohjen mund ta lejoni që nga Rregullime > Vendndodhje";
+"location_sharing_loading_map_error_title" = "%@ s’ngarkoi dot hartën. Ju lutemi, riprovoni më vonë.";
+"location_sharing_share_action" = "Ndajeni me të tjerë";
+"location_sharing_close_action" = "Mbylle";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Vendndodhje";
+"ok" = "OK";
+"settings_enable_room_message_bubbles" = "Flluska mesazhesh";
+"onboarding_splash_page_4_message" = "Element-i është gjithashtu i goditur për në punë. Është i besuar nga entet më të sigurta të botës.";
+"onboarding_splash_page_4_title_no_pun" = "Shkëmbim mesazhesh për ekipin tuaj.";
+"onboarding_splash_page_3_message" = "I fshehtëzuar skaj më skaj dhe pa u dashur numër telefoni. Pa reklama, apo shfrytëzim të dhënash.";
+"onboarding_splash_page_3_title" = "Shkëmbim i sigurt mesazhesh.";
+"onboarding_splash_page_2_message" = "Zgjidhni ku mbahen bisedat tuaja, duke ju dhënë kontroll dhe pavarësi. Të lidhur përmes Matrix-i.";
+"onboarding_splash_page_2_title" = "Kontrollin e keni ju.";
+"onboarding_splash_page_1_message" = "Komunikim i sigurt dhe i pavarur, që ju jep të njëjtën shkallë privatësie si biseda kokë më kokë, në shtëpinë tuaj.";
+"onboarding_splash_page_1_title" = "Jini zot i bisedave tuaja.";
+"onboarding_splash_login_button_title" = "Kam tashmë një llogari";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Krijoni llogari";
diff --git a/Riot/Assets/sv.lproj/InfoPlist.strings b/Riot/Assets/sv.lproj/InfoPlist.strings
index 45ccee26b..4d03e8e0c 100644
--- a/Riot/Assets/sv.lproj/InfoPlist.strings
+++ b/Riot/Assets/sv.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSMicrophoneUsageDescription" = "Element behöver åtkomst till din mikrofon för att kunna ringa och ta emot samtal samt spela in video och röstmeddelanden.";
"NSContactsUsageDescription" = "Element kommer att visa dina kontakter så du kan bjuda in dem att chatta.";
"NSFaceIDUsageDescription" = "Face ID används för att komma åt appen.";
+"NSLocationWhenInUseUsageDescription" = "När du delar din plats med folk så behöver Element åtkomst för att visa dem en karta.";
diff --git a/Riot/Assets/sv.lproj/Localizable.strings b/Riot/Assets/sv.lproj/Localizable.strings
index 4883fb894..9c4df7f81 100644
--- a/Riot/Assets/sv.lproj/Localizable.strings
+++ b/Riot/Assets/sv.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Avisering";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ delade sin plats";
diff --git a/Riot/Assets/uk.lproj/InfoPlist.strings b/Riot/Assets/uk.lproj/InfoPlist.strings
index 1923cbcbc..35a02253f 100644
--- a/Riot/Assets/uk.lproj/InfoPlist.strings
+++ b/Riot/Assets/uk.lproj/InfoPlist.strings
@@ -5,3 +5,4 @@
"NSContactsUsageDescription" = "Element покаже ваші контакти, щоб ви могли запросити їх до бесіди.";
"NSCalendarsUsageDescription" = "Переглядайте свої заплановані зустрічі в додатку.";
"NSFaceIDUsageDescription" = "Face ID використовується для доступу до вашого додатку.";
+"NSLocationWhenInUseUsageDescription" = "Коли ви надсилаєте комусь дані про своє місцеперебування, Element потребує дозволу, щоб показати їм карту.";
diff --git a/Riot/Assets/uk.lproj/Localizable.strings b/Riot/Assets/uk.lproj/Localizable.strings
index 01f01d7ac..0ad0b3aa3 100644
--- a/Riot/Assets/uk.lproj/Localizable.strings
+++ b/Riot/Assets/uk.lproj/Localizable.strings
@@ -116,3 +116,6 @@
/** General **/
"NOTIFICATION" = "Сповіщення";
+
+/* New file message from a specific person, not referencing a room. */
+"LOCATION_FROM_USER" = "%@ надсилає дані про своє місцеперебування";
diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings
index 7694f2d5e..e85515b74 100644
--- a/Riot/Assets/uk.lproj/Vector.strings
+++ b/Riot/Assets/uk.lproj/Vector.strings
@@ -1414,7 +1414,7 @@
"spaces_no_room_found_detail" = "Деяких результатів може бути не видно, бо вони закриті й потребують запрошення.";
"spaces_no_member_found_detail" = "Шукаєте когось, хто ще не в %@? Запросіть їх вебпереглядачем або комп'ютером.";
"spaces_invites_coming_soon_title" = "Запрошення ще в розробці";
-"spaces_coming_soon_detail" = "Ця можливість тут іще не втілена, але скоро буде. Поки що можете зробити це в Element на комп'ютері.";
+"spaces_coming_soon_detail" = "Ця можливість ще не втілена, але скоро буде. Поки що можете зробити це в %@ на комп'ютері.";
"space_participants_action_remove" = "Вилучити з цього простору";
"space_participants_action_ban" = "Заблокувати в цьому просторі";
@@ -1476,7 +1476,7 @@
/* Note: The placeholder is for the contents of analytics_prompt_terms_link_new_user */
"analytics_prompt_terms_new_user" = "Можете прочитати всі наші умови %@.";
"analytics_prompt_message_upgrade" = "Раніше ви погодилися надсилати нам анонімні дані про використання. Тепер, щоб розуміти, як люди використовують кілька пристроїв, ми створимо спільний для ваших пристроїв випадковий ідентифікатор.";
-"analytics_prompt_message_new_user" = "Допомагайте нам визначати проблеми й удосконалювати Element, надсилаючи анонімні дані про використання. Щоб розуміти, як люди використовують кілька пристроїв, ми створимо спільний для ваших пристроїв випадковий ідентифікатор.";
+"analytics_prompt_message_new_user" = "Допомагайте нам визначати проблеми й удосконалювати %@, надсилаючи анонімні дані про використання. Щоб розуміти, як люди використовують кілька пристроїв, ми створимо спільний для ваших пристроїв випадковий ідентифікатор.";
// Analytics
"analytics_prompt_title" = "Допоможіть удосконалити %@";
@@ -1702,3 +1702,32 @@
"room_details_flair_section" = "Показувати значки для спільнот";
"settings_flair" = "Показувати значок, де це дозволено";
"room_warning_about_encryption" = "Наскрізне шифрування ще на етапі бета-тестування й може бути ненадійним.\n\nПоки що не варто довіряти йому захист даних.\n\nПристрої ще не зможуть розшифрувати історію до того, як з них приєдналися до кімнати.\n\nЗашифровані повідомлення не буде показано у клієнтах, які ще не використовують шифрування.";
+"location_sharing_settings_toggle_title" = "Увімкнути надсилання місцеперебування";
+"location_sharing_settings_header" = "Надсилання місцеперебування";
+"location_sharing_open_google_maps" = "Відкрити в Картах Google";
+"location_sharing_open_apple_maps" = "Відкрити в Apple Maps";
+"location_sharing_invalid_authorization_settings" = "Налаштування";
+"location_sharing_invalid_authorization_not_now" = "Не зараз";
+"location_sharing_invalid_authorization_error_title" = "%@ не має дозволу на доступ до вашого місцеперебування. Ви можете увімкнути доступ у Налаштування > Місцеперебування";
+"location_sharing_locating_user_error_title" = "%@ не може отримати доступ до вашого місцеперебування. Повторіть спробу пізніше.";
+"location_sharing_loading_map_error_title" = "%@ не може завантажити карту. Повторіть спробу пізніше.";
+"location_sharing_share_action" = "Поділиться";
+"location_sharing_close_action" = "Закрити";
+
+// MARK: - Location sharing
+
+"location_sharing_title" = "Місцеперебування";
+"ok" = "Гаразд";
+"settings_enable_room_message_bubbles" = "Бульбашки повідомлень";
+"onboarding_splash_page_4_message" = "Елемент також чудово підходить для роботи. Йому довіряють найбезпечніші організації світу.";
+"onboarding_splash_page_4_title_no_pun" = "Спілкування зі своєю командою.";
+"onboarding_splash_page_3_message" = "Наскрізне шифрування та відсутність потреби у телефонному номері. Без реклами чи аналізу даних.";
+"onboarding_splash_page_3_title" = "Безпечне спілкування.";
+"onboarding_splash_page_2_message" = "Оберіть, де зберігати ваші бесіди, що дасть вам контроль і незалежність. Спілкуйтеся через Matrix.";
+"onboarding_splash_page_2_title" = "Ви контролюєте все.";
+"onboarding_splash_page_1_message" = "Безпечне та незалежне спілкування, яке дає вам такий же рівень приватності як особиста розмова у вашому власному домі.";
+"onboarding_splash_page_1_title" = "Будьте господарем свого спілкування.";
+"onboarding_splash_login_button_title" = "У мене вже є обліковий запис";
+
+// Onboarding
+"onboarding_splash_register_button_title" = "Створити обліковий запис";
diff --git a/Riot/Categories/MXKRoomBubbleCellData+Riot.swift b/Riot/Categories/MXKRoomBubbleCellData+Riot.swift
new file mode 100644
index 000000000..b7e7eaa9c
--- /dev/null
+++ b/Riot/Categories/MXKRoomBubbleCellData+Riot.swift
@@ -0,0 +1,33 @@
+//
+// Copyright 2021 New Vector Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+import Foundation
+
+extension MXKRoomBubbleCellData {
+
+ /// Indicate true if the sender is the session user
+ var isSenderCurrentUser: Bool {
+ if let senderId = self.senderId, let currentUserId = self.mxSession.myUserId, senderId == currentUserId {
+ return true
+ }
+ return false
+ }
+
+ // Indicate true if the cell data is collapsable and collapsed
+ var isCollapsableAndCollapsed: Bool {
+ return self.collapsable && self.collapsed
+ }
+}
diff --git a/Riot/Categories/UIView+Toast.swift b/Riot/Categories/UIView+Toast.swift
index b8d2db9aa..e395578e3 100644
--- a/Riot/Categories/UIView+Toast.swift
+++ b/Riot/Categories/UIView+Toast.swift
@@ -232,7 +232,7 @@ private class ToastView: UIView, Themable {
private lazy var messageLabel: UILabel = {
let label = UILabel()
- label.font = .systemFont(ofSize: 15)
+ label.font = ThemeService.shared().theme.fonts.body
label.backgroundColor = .clear
label.numberOfLines = 0
label.textAlignment = .left
@@ -305,6 +305,7 @@ private class ToastView: UIView, Themable {
backgroundColor = theme.colors.quinaryContent
imageView.tintColor = theme.colors.tertiaryContent
messageLabel.textColor = theme.colors.primaryContent
+ messageLabel.font = theme.fonts.body
}
}
diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift
index 9b18bec6d..3f1eec4d6 100644
--- a/Riot/Managers/Settings/RiotSettings.swift
+++ b/Riot/Managers/Settings/RiotSettings.swift
@@ -198,6 +198,10 @@ final class RiotSettings: NSObject {
@UserDefault(key: "roomScreenEnableMessageBubbles", defaultValue: BuildSettings.roomScreenEnableMessageBubblesByDefault, storage: defaults)
var roomScreenEnableMessageBubbles
+ var roomTimelineStyleIdentifier: RoomTimelineStyleIdentifier {
+ return self.roomScreenEnableMessageBubbles ? .bubble : .plain
+ }
+
// MARK: - Room Contextual Menu
@UserDefault(key: "roomContextualMenuShowMoreOptionForMessages", defaultValue: BuildSettings.roomContextualMenuShowMoreOptionForMessages, storage: defaults)
diff --git a/Riot/Managers/Theme/ThemeService.m b/Riot/Managers/Theme/ThemeService.m
index b205bbb6d..7adcadd7c 100644
--- a/Riot/Managers/Theme/ThemeService.m
+++ b/Riot/Managers/Theme/ThemeService.m
@@ -52,7 +52,7 @@ NSString *const kThemeServiceDidChangeThemeNotification = @"kThemeServiceDidChan
[self updateAppearance];
- [[NSNotificationCenter defaultCenter] postNotificationName:kThemeServiceDidChangeThemeNotification object:nil];
+ [[NSNotificationCenter defaultCenter] postNotificationName:kThemeServiceDidChangeThemeNotification object:self];
}
}
diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift
index 6a48f5c6c..3f6147c6a 100644
--- a/Riot/Modules/Analytics/Analytics.swift
+++ b/Riot/Modules/Analytics/Analytics.swift
@@ -23,11 +23,14 @@ import AnalyticsEvents
/// ## Creating Analytics Events
///
/// Events are managed in a shared repo for all Element clients https://github.com/matrix-org/matrix-analytics-events
-/// To add a new event create a PR to that repo with the new/updated schema.
+/// To add a new event create a PR to that repo with the new/updated schema. Element's Podfile has
+/// a local version of the pod (commented out) for development purposes.
/// Once merged into `main`, follow the steps below to integrate the changes into the project:
-/// 1. Merge `main` into the `release/swift` branch.
-/// 2. Run `bundle exec pod update AnalyticsEvents` to update the pod.
-/// 3. Make sure to commit `Podfile.lock` with the new commit hash.
+/// 1. Check if `main` contains any source breaking changes to the events. If so, please
+/// wait until you are ready to merge your work into element-ios.
+/// 2. Merge `main` into the `release/swift` branch.
+/// 3. Run `bundle exec pod update AnalyticsEvents` to update the pod.
+/// 4. Make sure to commit `Podfile.lock` with the new commit hash.
///
@objcMembers class Analytics: NSObject {
diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m
index 9c2dd5c00..5658be6a3 100644
--- a/Riot/Modules/Application/LegacyAppDelegate.m
+++ b/Riot/Modules/Application/LegacyAppDelegate.m
@@ -1425,9 +1425,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
else
{
void(^findRoom)(void) = ^{
- if ([_masterTabBarController.selectedViewController isKindOfClass:MXKActivityHandlingViewController.class])
+ if ([_masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)])
{
- MXKActivityHandlingViewController *homeViewController = (MXKActivityHandlingViewController*)_masterTabBarController.selectedViewController;
+ UIViewController *homeViewController = (UIViewController*)_masterTabBarController.selectedViewController;
[homeViewController startActivityIndicator];
@@ -1704,11 +1704,13 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Try to get more information about the room before opening its preview
[roomPreviewData peekInRoom:^(BOOL succeeded) {
MXStrongifyAndReturnIfNil(self);
-
- MXKViewController *homeViewController = (MXKViewController*)self.masterTabBarController.selectedViewController;
+ if ([self.masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)])
+ {
+ UIViewController *homeViewController = (UIViewController*)self.masterTabBarController.selectedViewController;
- // Note: the activity indicator will not disappear if the session is not ready
- [homeViewController stopActivityIndicator];
+ // Note: the activity indicator will not disappear if the session is not ready
+ [homeViewController stopActivityIndicator];
+ }
// If no data is available for this room, we name it with the known room alias (if any).
if (!succeeded && self->universalLinkFragmentPendingRoomAlias[roomIdOrAlias])
@@ -2946,7 +2948,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:mxSession
- threadParameters:nil
+ threadParameters:nil
presentationParameters:presentationParameters];
[self showRoomWithParameters:parameters];
diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m
index 67b2a9e8b..3a859b7d5 100644
--- a/Riot/Modules/Authentication/AuthenticationViewController.m
+++ b/Riot/Modules/Authentication/AuthenticationViewController.m
@@ -482,7 +482,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0;
// Hide input view when there is only social login actions to present
if ((self.authType == MXKAuthenticationTypeLogin || self.authType == MXKAuthenticationTypeRegister)
&& self.currentLoginSSOFlow
- && !self.isAuthSessionContainsPasswordFlow)
+ && !self.isAuthSessionContainsPasswordFlow
+ && BuildSettings.authScreenShowSocialLoginSection)
{
hideAuthInputView = YES;
}
@@ -1735,8 +1736,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0;
- (void)updateSocialLoginViewVisibility
{
SocialLoginButtonMode socialLoginButtonMode = SocialLoginButtonModeContinue;
-
- BOOL showSocialLoginView = self.currentLoginSSOFlow ? YES : NO;
+
+ BOOL showSocialLoginView = BuildSettings.authScreenShowSocialLoginSection && (self.currentLoginSSOFlow ? YES : NO);
switch (self.authType)
{
diff --git a/Riot/Modules/Common/CollectionView/CollectionViewRightAlignFlowLayout.swift b/Riot/Modules/Common/CollectionView/CollectionViewRightAlignFlowLayout.swift
new file mode 100644
index 000000000..946388de3
--- /dev/null
+++ b/Riot/Modules/Common/CollectionView/CollectionViewRightAlignFlowLayout.swift
@@ -0,0 +1,29 @@
+//
+// Copyright 2021 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
+
+/// UICollectionViewFlowLayout with right align behavior
+class CollectionViewRightAlignFlowLayout: UICollectionViewFlowLayout {
+
+ override var flipsHorizontallyInOppositeLayoutDirection: Bool {
+ return true
+ }
+
+ override var developmentLayoutDirection: UIUserInterfaceLayoutDirection {
+ return UIUserInterfaceLayoutDirection.rightToLeft
+ }
+}
diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m
index 259058f8a..41cfa0b0a 100644
--- a/Riot/Modules/Common/Recents/RecentsViewController.m
+++ b/Riot/Modules/Common/Recents/RecentsViewController.m
@@ -875,7 +875,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:nil
mxSession:matrixSession
- threadParameters:nil
+ threadParameters:nil
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters completion:^{
@@ -1026,6 +1026,12 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
{
[super dataSource:dataSource didCellChange:changes];
}
+ else
+ {
+ // Since we've enabled room list pagination, `refreshRecentsTable` not called in this case.
+ // Refresh tab bar badges separately.
+ [[AppDelegate theDelegate].masterTabBarController refreshTabBarBadges];
+ }
if (changes == nil)
{
diff --git a/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m b/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m
index 535d48d93..d9274d8be 100644
--- a/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m
+++ b/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m
@@ -157,7 +157,7 @@
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:session
- threadParameters:nil
+ threadParameters:nil
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
diff --git a/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m b/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m
index d22375113..1de9381ce 100644
--- a/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m
+++ b/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m
@@ -148,57 +148,62 @@
// Display date for each message
[bubbleCell addDateLabel];
- RoomBubbleCellData *cellData = (RoomBubbleCellData*)[self cellDataAtIndex:indexPath.row];
- MXEvent *event = cellData.events.firstObject;
-
- if (event)
+ if (RiotSettings.shared.enableThreads)
{
- if (cellData.hasThreadRoot)
+ RoomBubbleCellData *cellData = (RoomBubbleCellData*)[self cellDataAtIndex:indexPath.row];
+ MXEvent *event = cellData.events.firstObject;
+
+ if (event)
{
- MXThread *thread = cellData.bubbleComponents.firstObject.thread;
- ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
- [bubbleCell.tmpSubviews addObject:threadSummaryView];
+ if (cellData.hasThreadRoot)
+ {
+ MXThread *thread = cellData.bubbleComponents.firstObject.thread;
+ ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
+ [bubbleCell.tmpSubviews addObject:threadSummaryView];
- threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
- [bubbleCell.contentView addSubview:threadSummaryView];
+ threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
+ [bubbleCell.contentView addSubview:threadSummaryView];
- CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth];
- CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
- CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
+ CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
+ CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
- // Set constraints for the summary view
- [NSLayoutConstraint activateConstraints: @[
- [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
- constant:leftMargin],
- [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
+ // Set constraints for the summary view
+ [NSLayoutConstraint activateConstraints: @[
+ [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
+ constant:leftMargin],
+ [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin],
- [threadSummaryView.heightAnchor constraintEqualToConstant:[ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth]],
- [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
- ]];
- }
- else if (event.isInThread)
- {
- FromThreadView *fromThreadView = [FromThreadView instantiate];
- [bubbleCell.tmpSubviews addObject:fromThreadView];
+ [threadSummaryView.heightAnchor constraintEqualToConstant:height],
+ [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
+ ]];
+ }
+ else if (event.isInThread)
+ {
+ FromAThreadView *fromAThreadView = [FromAThreadView instantiate];
+ [bubbleCell.tmpSubviews addObject:fromAThreadView];
- fromThreadView.translatesAutoresizingMaskIntoConstraints = NO;
- [bubbleCell.contentView addSubview:fromThreadView];
+ fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO;
+ [bubbleCell.contentView addSubview:fromAThreadView];
+
+ CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth];
- CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
+ CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
- CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
- CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
-
- // Set constraints for the summary view
- [NSLayoutConstraint activateConstraints: @[
- [fromThreadView.leadingAnchor constraintEqualToAnchor:fromThreadView.superview.leadingAnchor
- constant:leftMargin],
- [fromThreadView.topAnchor constraintEqualToAnchor:fromThreadView.superview.topAnchor
- constant:bottomPositionY + RoomBubbleCellLayout.fromThreadViewTopMargin],
- [fromThreadView.heightAnchor constraintEqualToConstant:[FromThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth]],
- [fromThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
- ]];
+ // Set constraints for the summary view
+ [NSLayoutConstraint activateConstraints: @[
+ [fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor
+ constant:leftMargin],
+ [fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor
+ constant:bottomPositionY + RoomBubbleCellLayout.fromAThreadViewTopMargin],
+ [fromAThreadView.heightAnchor constraintEqualToConstant:height],
+ [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
+ ]];
+ }
}
}
}
diff --git a/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m b/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m
index beeb90385..be2904f17 100644
--- a/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m
+++ b/Riot/Modules/GlobalSearch/Rooms/DirectoryViewController.m
@@ -248,7 +248,7 @@
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:nil
mxSession:mxSession
- threadParameters:nil
+ threadParameters:nil
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
}
diff --git a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift
index 85abec4d1..764dc2d59 100644
--- a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift
+++ b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift
@@ -16,7 +16,7 @@
import Foundation
-class HomeViewControllerWithBannerWrapperViewController: MXKActivityHandlingViewController, BannerPresentationProtocol {
+class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKViewControllerActivityHandling, BannerPresentationProtocol {
@objc let homeViewController: HomeViewController
private var bannerContainerView: UIView!
@@ -85,4 +85,22 @@ class HomeViewControllerWithBannerWrapperViewController: MXKActivityHandlingView
bannerView.removeFromSuperview()
}
}
+
+ // MARK: - MXKViewControllerActivityHandling
+ var activityIndicator: UIActivityIndicatorView! {
+ get {
+ return homeViewController.activityIndicator
+ }
+ set {
+ homeViewController.activityIndicator = newValue
+ }
+ }
+
+ func startActivityIndicator() {
+ homeViewController.startActivityIndicator()
+ }
+
+ func stopActivityIndicator() {
+ homeViewController.stopActivityIndicator()
+ }
}
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings
index 295ea3259..dfa373dc7 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings
@@ -504,3 +504,5 @@
"attachment_unsupported_preview_message" = "Dieser Dateityp wird nicht unterstützt.";
"attachment_unsupported_preview_title" = "Vorschau kann nicht angezeigt werden";
"auth_reset_password_error_unauthorized" = "Nicht Authorisiert";
+"message_reply_to_sender_sent_their_location" = "hat den eigenen Standort geteilt.";
+"room_displayname_all_other_members_left" = "%@ (Verlassen)";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/et.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/et.lproj/MatrixKit.strings
index 997cb7964..458efee70 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/et.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/et.lproj/MatrixKit.strings
@@ -270,7 +270,7 @@
// Language picker
"language_picker_title" = "Vali keel";
"language_picker_default_language" = "Vaikimisi (%@)";
-"notice_room_invite" = "%@ kutsus kasutajat %@";
+"notice_room_invite" = "%@ saatis kutse kasutajale %@";
"notice_room_third_party_invite" = "%@ saatis kasutajale %@ kutse jututoaga liitumiseks";
"notice_room_third_party_registered_invite" = "%@ võttis vastu kutse %@ nimel";
"notice_room_third_party_revoked_invite" = "%@ võttis tagasi jututoaga liitumise kutse kasutajalt %@";
@@ -433,7 +433,7 @@
"notice_room_history_visible_to_members_from_invited_point_for_dm" = "%@ määras, et jututoa tulevane ajalugu on nähtav kõikidele selle liikmetele liitumiskutse saatmise hetkest.";
"notice_room_history_visible_to_members_from_joined_point_for_dm" = "%@ määras, et jututoa tulevane ajalugu on nähtav kõikidele selle liikmetele nende liitumise hetkest.";
"room_left_for_dm" = "Sina lahkusid";
-"notice_room_third_party_invite_for_dm" = "%@ kutsus kasutajat %@";
+"notice_room_third_party_invite_for_dm" = "%@ saatis kutse kasutajale %@";
"notice_room_third_party_revoked_invite_for_dm" = "%@ võttis tagasi kasutaja %@ kutse";
"notice_room_name_changed_for_dm" = "%@ muutis jututoa uueks nimeks %@.";
"notice_room_third_party_invite_by_you_for_dm" = "Sina kutsusid kasutajat %@";
@@ -478,3 +478,4 @@
"room_displayname_all_other_members_left" = "%@ (lahkus(id))";
"attachment_unsupported_preview_message" = "See failitüüp ei ole toetatud.";
"attachment_unsupported_preview_title" = "Eelvaate kuvamine ei õnnestu";
+"message_reply_to_sender_sent_their_location" = "on jaganud oma asukohta.";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/fr.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/fr.lproj/MatrixKit.strings
index 61a64b321..03688dc76 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/fr.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/fr.lproj/MatrixKit.strings
@@ -275,7 +275,7 @@
"notice_conference_call_started" = "Téléconférence en VoIP démarrée";
"notice_conference_call_finished" = "Téléconférence en VoIP terminée";
// button names
-"ok" = "OK";
+"ok" = "Ok";
"send" = "Envoyer";
"copy_button_name" = "Copier";
"resend" = "Renvoyer";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/hu.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/hu.lproj/MatrixKit.strings
index d99934823..d1c2ec520 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/hu.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/hu.lproj/MatrixKit.strings
@@ -283,7 +283,7 @@
"notice_conference_call_started" = "VoIP konferencia indult";
"notice_conference_call_finished" = "VoIP konferencia befejeződött";
// button names
-"ok" = "Rendben";
+"ok" = "OK";
"cancel" = "Mégse";
"save" = "Ment";
"send" = "Küld";
@@ -479,3 +479,4 @@
"room_displayname_all_other_members_left" = "%@ (Bal)";
"attachment_unsupported_preview_message" = "Ez a fájl típus nem támogatott.";
"attachment_unsupported_preview_title" = "Az előnézetet nem lehet megjeleníteni";
+"message_reply_to_sender_sent_their_location" = "megosztotta a földrajzi helyzetét.";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/id.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/id.lproj/MatrixKit.strings
index ef186655b..65682850d 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/id.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/id.lproj/MatrixKit.strings
@@ -249,7 +249,7 @@
// titles
// button names
-"ok" = "OK";
+"ok" = "OKE";
"notice_room_history_visible_to_members_from_joined_point_by_you_for_dm" = "Anda membuat sejarah pesan di masa mendatang dapat dilihat oleh semuanya, sejak mereka bergabung.";
"notice_room_history_visible_to_members_from_joined_point_by_you" = "Anda membuat sejarah ruangan di masa mendatang dapat dilihat oleh semua anggota ruang, sejak mereka bergabung.";
"notice_encryption_enabled_unknown_algorithm_by_you" = "Anda mengaktifkan enkripsi ujung-ke-ujung (algoritma %@ tidak dikenal).";
@@ -557,3 +557,4 @@
"notice_room_power_level_acting_requirement" = "Tingkat daya minimum yang harus dimiliki pengguna sebelum bertindak adalah:";
"attachment_unsupported_preview_title" = "Tidak dapat ditampilkan";
"attachment_unsupported_preview_message" = "Tipe file ini tidak didukung.";
+"message_reply_to_sender_sent_their_location" = "telah membagikan lokasinya.";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/it.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/it.lproj/MatrixKit.strings
index 6049a7351..fb679dc2b 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/it.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/it.lproj/MatrixKit.strings
@@ -478,3 +478,4 @@
"rename" = "Rinomina";
"attachment_unsupported_preview_message" = "Questo tipo di file non è supportato.";
"attachment_unsupported_preview_title" = "Anteprima non disponibile";
+"message_reply_to_sender_sent_their_location" = "ha condiviso la sua posizione.";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/nl.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/nl.lproj/MatrixKit.strings
index 8c6e58224..da52635ac 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/nl.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/nl.lproj/MatrixKit.strings
@@ -311,7 +311,7 @@
// titles
// button names
-"ok" = "Oké";
+"ok" = "OK";
"cancel" = "Annuleren";
"save" = "Opslaan";
"leave" = "Verlaten";
@@ -540,3 +540,4 @@
"room_displayname_all_other_members_left" = "%@ (Vertrok)";
"auth_username_in_use" = "Inlognaam al in gebruik";
"rename" = "Hernoemen";
+"message_reply_to_sender_sent_their_location" = "deelde hun locatie.";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pl.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pl.lproj/MatrixKit.strings
index d90ed3c37..1f9c919dd 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pl.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pl.lproj/MatrixKit.strings
@@ -496,3 +496,12 @@
"attachment_small_with_resolution" = "Mały %@ (~%@)";
"attachment_size_prompt_message" = "Możesz to wyłączyć w ustawieniach.";
"attachment_size_prompt_title" = "Potwierdź rozmiar, który chcesz wysłać";
+"auth_reset_password_error_not_found" = "Nie znaleziono";
+"auth_reset_password_error_unauthorized" = "Brak autoryzacji";
+"auth_invalid_user_name" = "Niepoprawna nazwa użytkownika";
+"attachment_unsupported_preview_message" = "Ten format pliku nie jest obsługiwany.";
+"attachment_unsupported_preview_title" = "Brak podglądu";
+"message_reply_to_sender_sent_their_location" = "udostępnił(-a) swoją lokację.";
+"room_displayname_all_other_members_left" = "%@ (Opuścił-a)";
+"auth_username_in_use" = "Nazwa użytkownika jest już używana";
+"rename" = "Zmień nazwę";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings
index f3dba6590..9ddeb7793 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings
@@ -121,7 +121,7 @@
"room_displayname_two_members" = "%@ e %@";
"room_displayname_more_than_two_members" = "%@ e %@ outros";
// Settings
-"settings" = "Configurações";
+"settings" = "Ajustes";
"settings_enable_inapp_notifications" = "Habilitar notificações Em-App";
"settings_enable_push_notifications" = "Habilitar notificações push";
"settings_enter_validation_token_for" = "Entrar token de validação para %@:";
@@ -157,7 +157,7 @@
"room_event_encryption_info_block" = "Adicionar à lista negra";
"room_event_encryption_info_unblock" = "Remover da lista negra";
"room_event_encryption_verify_title" = "Verificar sessão\n\n";
-"room_event_encryption_verify_message" = "Para verificar que esta sessão pode ser confiada, por favor contacte a/o dona(o) dela usando alguma outro meio (e.g. em pessoa ou uma chamada de telefone) e pergunte-lhe se a chave que ela/ele vê em suas Configurações de Usuária(o) para esta sessão bate com a chave abaixo:\n\n\tNome de sessão: %@\n\tID de sessão: %@\n\tChave de sessão: %@\n\nSe ela bate, pressione o botão verificar abaixo. Se não bate, então alguma outra pessoa está interceptando esa sessão e você provavelmente quer pressionar o botão adicionar à lista negra em vez disso.\n\nNo futuro este processo de verificação vai ser mais sofisticado.";
+"room_event_encryption_verify_message" = "Para verificar que esta sessão pode ser confiada, por favor contacte a/o dona(o) dela usando alguma outro meio (e.g. em pessoa ou uma chamada de telefone) e pergunte-lhe se a chave que ela/ele vê em seus Ajustes de Usuária(o) para esta sessão corresponde com a chave abaixo:\n\n\tNome de sessão: %@\n\tID de sessão: %@\n\tChave de sessão: %@\n\nSe ela corresponde, pressione o botão verificar abaixo. Se não corresponde, então alguma outra pessoa está interceptando esa sessão e você provavelmente quer pressionar o botão adicionar à lista negra em vez disso.\n\nNo futuro este processo de verificação vai ser mais sofisticado.";
"room_event_encryption_verify_ok" = "Verificar";
// Account
"account_save_changes" = "Salvar mudanças";
@@ -331,9 +331,9 @@
"notification_settings_disable_all" = "Desabilitar todas as notificações";
"notification_settings_enable_notifications" = "Habilitar notificações";
"notification_settings_enable_notifications_warning" = "Todas as notificações estão atualmente desabilitadas para todos os dispositivos.";
-"notification_settings_global_info" = "Configurações de notificação são salvas em sua conta de usuária(o) e são compartilhadas entre todos os clientes que as suportam (incluindo notificações de desktop).\n\nRegras são aplicadas em ordem; a primeira regra que corresponde define o resultado da mensagem.\nEntão: Notificações per-palavra são mais importantes que notificações per-sala que são mais importantes que notificações per-enviador(a).\nPara múltiplas regras do mesmo tipo, a primeira na lista que corresponde leva prioridade.";
+"notification_settings_global_info" = "Ajustes de notificação são salvas em sua conta de usuária(o) e são compartilhadas entre todos os clientes que as suportam (incluindo notificações de desktop).\n\nRegras são aplicadas em ordem; a primeira regra que corresponde define o resultado da mensagem.\nEntão: Notificações per-palavra são mais importantes que notificações per-sala que são mais importantes que notificações per-enviador(a).\nPara múltiplas regras do mesmo tipo, a primeira na lista que corresponde leva prioridade.";
"notification_settings_per_word_notifications" = "Notificações per-palavra";
-"notification_settings_per_word_info" = "Palavras correspondem insensivelmente a maiúsculas e minúsculas, e podem incluir um wildcard *. Então:\nfoo corresponde a string foo rodeado por delimitadores de palavras (e.g., pontuação e whitespace ou início/fim de linha).\nfoo* corresponde a qualquer palavra que começa foo.\n*foo* corresponde a qualquer palavra que inclui as 3 letras foo.";
+"notification_settings_per_word_info" = "Palavras correspondem insensivelmente com maiúsculas e minúsculas, e podem incluir um wildcard *. Então:\nfoo corresponde com string foo rodeado por delimitadores de palavras (e.g., pontuação e whitespace ou início/fim de linha).\nfoo* corresponde com qualquer palavra que começa foo.\n*foo* corresponde com qualquer palavra que inclui as 3 letras foo.";
"notification_settings_always_notify" = "Sempre notificar";
"notification_settings_never_notify" = "Nunca notificar";
"notification_settings_word_to_match" = "palavra para corresponder";
@@ -372,10 +372,10 @@
"ssl_fingerprint_hash" = "Impressão digital (%@):";
"ssl_could_not_verify" = "Não foi possível verificar identidade de servidor remoto.";
"ssl_cert_not_trust" = "Isto pode significar que alguém está interceptando maliciosamente seu tráfico, ou que seu telefone não confia no certificado provido pelo servidor remoto.";
-"ssl_cert_new_account_expl" = "Se o/a administrador(a) do servidor tem dito que isto é esperado, assegure-se que a impressão digital abaixo bate com a impressão digital provida por ele(a).";
+"ssl_cert_new_account_expl" = "Se o/a administrador(a) do servidor tem dito que isto é esperado, assegure-se que a impressão digital abaixo corresponde com a impressão digital provida por ele(a).";
"ssl_unexpected_existing_expl" = "O certificado tem mudado de um que esta confiado por seu telefone. Isto é ALTAMENTE INCOMUM. É recomendado que você NÃO ACEITE este novo certificado.";
"ssl_expected_existing_expl" = "O certificado tem sido mudado de um previamente confiado para um que não é confiado. O servidor pode ter renovado o certificado dele. Contacte o/a administrador(a) do servidor a impressão digital esperada.";
-"ssl_only_accept" = "SOMENTE aceite o certificado se o/a administrador(a) do servidor tem publicado uma impressão digital que corresponde à acima.";
+"ssl_only_accept" = "SOMENTE aceite o certificado se o/a administrador(a) do servidor tem publicado uma impressão digital que corresponde com a acima.";
"notice_encryption_enabled_ok" = "%@ ativou encriptação ponta-a-ponta.";
"notice_encryption_enabled_unknown_algorithm" = "%1$@ ativou encriptação ponta-a-ponta (algoritmo não-reconhecido %2$@).";
"device_details_rename_prompt_title" = "Nome da Sessão";
@@ -468,7 +468,7 @@
"attachment_large_with_resolution" = "Grande %@ (~%@)";
"attachment_medium_with_resolution" = "Médio %@ (~%@)";
"attachment_small_with_resolution" = "Pequeno %@ (~%@)";
-"attachment_size_prompt_message" = "Você pode desligar isto em configurações.";
+"attachment_size_prompt_message" = "Você pode desligar isto em ajustes.";
"attachment_size_prompt_title" = "Confirmar tamanho para enviar";
"room_displayname_all_other_participants_left" = "%@ (Saiu)";
"auth_reset_password_error_not_found" = "Não encontrado";
@@ -479,3 +479,4 @@
"room_displayname_all_other_members_left" = "%@ (Saiu)";
"attachment_unsupported_preview_message" = "Este tipo de arquivo não é suportado.";
"attachment_unsupported_preview_title" = "Incapaz de previsualizar";
+"message_reply_to_sender_sent_their_location" = "tem compartilhado a localização dela(e).";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings
index 1efe28839..fec99d96b 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings
@@ -543,3 +543,7 @@
"notice_feedback" = "Udalosť spätnej väzby (id: %@): %@";
"resume_call" = "Pokračovať";
"answer_call" = "Prijať hovor";
+"message_reply_to_sender_sent_their_location" = "zdieľal/a svoju polohu.";
+"account_link_email" = "Prepojený email";
+"account_linked_emails" = "Prepojené e-maily";
+"room_event_encryption_info_event_fingerprint_key" = "Deklarovaný kľúč odtlačkov prstov Ed25519\n";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sq.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sq.lproj/MatrixKit.strings
index 888cbed6b..4e7256707 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sq.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sq.lproj/MatrixKit.strings
@@ -478,3 +478,4 @@
"attachment_unsupported_preview_message" = "Ky lloj kartele nuk mbulohet.";
"attachment_unsupported_preview_title" = "S’arrihet të bëhet paraparje";
"room_displayname_all_other_members_left" = "%@ (Iku)";
+"message_reply_to_sender_sent_their_location" = "ka dhënë vendndodhjen e vet.";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings
index 2dba03f74..d030f2d6e 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings
@@ -478,3 +478,4 @@
"attachment_unsupported_preview_message" = "Den här filtypen stöds inte.";
"attachment_unsupported_preview_title" = "Kunde inte förhandsgranska";
"room_displayname_all_other_members_left" = "%@ (Kvar)";
+"message_reply_to_sender_sent_their_location" = "har delat sin plats.";
diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/uk.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/uk.lproj/MatrixKit.strings
index 955e8fd1a..69eec8107 100644
--- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/uk.lproj/MatrixKit.strings
+++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/uk.lproj/MatrixKit.strings
@@ -558,3 +558,4 @@
"local_contacts_access_not_granted" = "Для пошуку користувачів серед локальних контактів потрібен доступ до ваших контактів, але %@ не має такого дозволу";
"e2e_export_prompt" = "Це дає змогу експортувати в локальний файл ключі до повідомлень, отриманих вами в зашифрованих кімнатах. Тоді ви зможете імпортувати файл до іншого клієнта Matrix у майбутньому, і той клієнт також зможе розшифрувати ці повідомлення.\nЕкспортований файл дасть змогу всім, хто його прочитає, розшифрувати всі видимі вам зашифровані повідомлення.";
"e2e_import_prompt" = "Це дає змогу імпортувати ключі шифрування, які ви раніше експортували з іншого клієнта Matrix. Тоді ви зможете розшифрувати всі повідомлення, які міг розшифрувати той клієнт.\nФайл експорту захищений парольною фразою. Введіть парольну фразу сюди, щоб розшифрувати файл.";
+"message_reply_to_sender_sent_their_location" = "надсилає дані про своє місцеперебування.";
diff --git a/Riot/Modules/MatrixKit/MatrixKit-Bridging-Header.h b/Riot/Modules/MatrixKit/MatrixKit-Bridging-Header.h
index 1653472db..64b8a348e 100644
--- a/Riot/Modules/MatrixKit/MatrixKit-Bridging-Header.h
+++ b/Riot/Modules/MatrixKit/MatrixKit-Bridging-Header.h
@@ -14,3 +14,4 @@
#import "MXKRoomInputToolbarView.h"
#import "MXKImageView.h"
+#import "MXKRoomBubbleCellData.h"
diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h
index cd76e39f8..eba99595c 100644
--- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h
+++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h
@@ -169,4 +169,11 @@
*/
- (MXKRoomBubbleComponent*)getFirstBubbleComponentWithDisplay;
+/**
+ Get the last visible component.
+
+ @return Last visible component or nil.
+ */
+- (MXKRoomBubbleComponent*)getLastBubbleComponentWithDisplay;
+
@end
diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m
index 0fe6bf0e0..a455996ef 100644
--- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m
+++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m
@@ -306,16 +306,15 @@
return first;
}
-- (MXKRoomBubbleComponent*) getFirstBubbleComponentWithDisplay
+- (MXKRoomBubbleComponent*)getFirstBubbleComponentWithDisplay
{
// Look for the first component which is actually displayed (some event are ignored in room history display).
MXKRoomBubbleComponent* first = nil;
@synchronized(bubbleComponents)
{
- for (NSInteger index = 0; index < bubbleComponents.count; index++)
+ for (MXKRoomBubbleComponent *component in bubbleComponents)
{
- MXKRoomBubbleComponent *component = bubbleComponents[index];
if (component.attributedTextMessage)
{
first = component;
@@ -327,6 +326,26 @@
return first;
}
+- (MXKRoomBubbleComponent*)getLastBubbleComponentWithDisplay
+{
+ // Look for the first component which is actually displayed (some event are ignored in room history display).
+ MXKRoomBubbleComponent* lastVisibleComponent = nil;
+
+ @synchronized(bubbleComponents)
+ {
+ for (MXKRoomBubbleComponent *component in bubbleComponents.reverseObjectEnumerator)
+ {
+ if (component.attributedTextMessage)
+ {
+ lastVisibleComponent = component;
+ break;
+ }
+ }
+ }
+
+ return lastVisibleComponent;
+}
+
- (NSAttributedString*)attributedTextMessageWithHighlightedEvent:(NSString*)eventId tintColor:(UIColor*)tintColor
{
NSAttributedString *customAttributedTextMsg;
diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h
index ab1d4f689..70bfe77d2 100644
--- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h
+++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h
@@ -274,7 +274,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param roomId the id of the room to get data from.
@param initialEventId the id of the event where to start the timeline.
- @param threadId the id of the thread to load.
+ @param threadId the id of the thread to load. If provided, thread data source will be loaded from the room specified with `roomId`.
@param mxSession the Matrix session to get data from.
@param onComplete a block providing the newly created instance.
*/
@@ -316,7 +316,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param roomId the id of the room to get data from.
@param initialEventId the id of the event where to start the timeline.
- @param threadId the id of the thread to initialize.
+ @param threadId the id of the thread to initialize. If provided, thread data source will be initialized from the room specified with `roomId`.
@param mxSession the Matrix session to get data from.
@return the newly created instance.
*/
diff --git a/Riot/Modules/Room/BubbleReactions/BubbleReactionsView.swift b/Riot/Modules/Room/BubbleReactions/BubbleReactionsView.swift
index a5dcb54ac..8248786a5 100644
--- a/Riot/Modules/Room/BubbleReactions/BubbleReactionsView.swift
+++ b/Riot/Modules/Room/BubbleReactions/BubbleReactionsView.swift
@@ -18,6 +18,13 @@ import Foundation
import MatrixSDK
import Reusable
import DGCollectionViewLeftAlignFlowLayout
+import UIKit
+
+/// BubbleReactionsView items alignment
+enum BubbleReactionsViewAlignment {
+ case left
+ case right
+}
@objcMembers
final class BubbleReactionsView: UIView, NibOwnerLoadable {
@@ -51,6 +58,12 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
}
}
+ var alignment: BubbleReactionsViewAlignment = .left {
+ didSet {
+ self.updateCollectionViewLayout(for: alignment)
+ }
+ }
+
// MARK: - Setup
private func commonInit() {
@@ -87,7 +100,18 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
self.collectionView.isScrollEnabled = false
self.collectionView.delegate = self
self.collectionView.dataSource = self
- self.collectionView.collectionViewLayout = DGCollectionViewLeftAlignFlowLayout()
+ self.alignment = .left
+
+ self.collectionView.register(cellType: BubbleReactionViewCell.self)
+ self.collectionView.register(cellType: BubbleReactionActionViewCell.self)
+ self.collectionView.reloadData()
+ }
+
+ private func updateCollectionViewLayout(for alignment: BubbleReactionsViewAlignment) {
+
+ let collectionViewLayout = self.collectionViewLayout(for: alignment)
+
+ self.collectionView.collectionViewLayout = collectionViewLayout
if let collectionViewFlowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
collectionViewFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
@@ -95,9 +119,22 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
collectionViewFlowLayout.minimumLineSpacing = Constants.minimumLineSpacing
}
- self.collectionView.register(cellType: BubbleReactionViewCell.self)
- self.collectionView.register(cellType: BubbleReactionActionViewCell.self)
self.collectionView.reloadData()
+ self.collectionView.collectionViewLayout.invalidateLayout()
+ }
+
+ private func collectionViewLayout(for alignment: BubbleReactionsViewAlignment) -> UICollectionViewLayout {
+
+ let collectionViewLayout: UICollectionViewLayout
+
+ switch alignment {
+ case .left:
+ collectionViewLayout = DGCollectionViewLeftAlignFlowLayout()
+ case .right:
+ collectionViewLayout = CollectionViewRightAlignFlowLayout()
+ }
+
+ return collectionViewLayout
}
private func setupLongPressGestureRecognizer() {
diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m
index 6da0487ae..c58e14554 100644
--- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m
+++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m
@@ -584,7 +584,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
// Add vertical whitespace in case of a thread root
additionalVerticalHeight+= [self threadSummaryViewHeightForEventId:eventId];
// Add vertical whitespace in case of from a thread
- additionalVerticalHeight+= [self fromThreadViewHeightForEventId:eventId];
+ additionalVerticalHeight+= [self fromAThreadViewHeightForEventId:eventId];
// Add vertical whitespace in case of read receipts.
additionalVerticalHeight+= [self readReceiptHeightForEventId:eventId];
@@ -605,7 +605,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
height+= [self urlPreviewHeightForEventId:eventId];
height+= [self reactionHeightForEventId:eventId];
height+= [self threadSummaryViewHeightForEventId:eventId];
- height+= [self fromThreadViewHeightForEventId:eventId];
+ height+= [self fromAThreadViewHeightForEventId:eventId];
height+= [self readReceiptHeightForEventId:eventId];
}
@@ -671,16 +671,16 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
[ThreadSummaryView contentViewHeightForThread:component.thread fitting:self.maxTextViewWidth];
}
-- (CGFloat)fromThreadViewHeightForEventId:(NSString*)eventId
+- (CGFloat)fromAThreadViewHeightForEventId:(NSString*)eventId
{
if (!RiotSettings.shared.enableThreads)
{
- // do not show from thread view if threads not enabled
+ // do not show from a thread view if threads not enabled
return 0;
}
if (roomDataSource.threadId)
{
- // do not show from thread view on threads
+ // do not show from a thread view on threads
return 0;
}
NSInteger index = [self bubbleComponentIndexForEventId:eventId];
@@ -694,8 +694,8 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
// event is not in a thread
return 0;
}
- return RoomBubbleCellLayout.fromThreadViewTopMargin +
- [FromThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth];
+ return RoomBubbleCellLayout.fromAThreadViewTopMargin +
+ [FromAThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth];
}
- (CGFloat)urlPreviewHeightForEventId:(NSString*)eventId
@@ -907,6 +907,12 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
- (BOOL)addEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState
{
+ RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
+
+ if (NO == [timelineConfiguration.currentStyle canAddEvent:event and:roomState to:self]) {
+ return NO;
+ }
+
BOOL shouldAddEvent = YES;
switch (self.tag)
diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.h b/Riot/Modules/Room/DataSources/RoomDataSource.h
index 9f3032e20..76d55375e 100644
--- a/Riot/Modules/Room/DataSources/RoomDataSource.h
+++ b/Riot/Modules/Room/DataSources/RoomDataSource.h
@@ -118,14 +118,14 @@
@protocol RoomDataSourceDelegate
/**
- Called when the room's encryption trust level did updated.
+ Called when the room's encryption trust level did update.
@param roomDataSource room data source instance
*/
- (void)roomDataSourceDidUpdateEncryptionTrustLevel:(RoomDataSource * _Nonnull)roomDataSource;
/**
- Called when a thread summary view
+ Called when a thread summary view is tapped.
@param roomDataSource room data source instance
*/
diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m
index cebd2d2b7..b068e6285 100644
--- a/Riot/Modules/Room/DataSources/RoomDataSource.m
+++ b/Riot/Modules/Room/DataSources/RoomDataSource.m
@@ -383,6 +383,8 @@ const CGFloat kTypingCellHeight = 24;
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
+ id cellDecorator = [RoomTimelineConfiguration shared].currentStyle.cellDecorator;
+
// Finalize cell view customization here
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class])
{
@@ -394,11 +396,8 @@ const CGFloat kTypingCellHeight = 24;
BOOL isCollapsableCellCollapsed = cellData.collapsable && cellData.collapsed;
- // Display timestamp of the last message
- if (cellData.containsLastMessage && !isCollapsableCellCollapsed)
- {
- [bubbleCell addTimestampLabelForComponent:cellData.mostRecentComponentIndex];
- }
+ // Display timestamp of the message if needed
+ [cellDecorator addTimestampLabelIfNeededToCell:bubbleCell cellData:cellData];
NSMutableArray *temporaryViews = [NSMutableArray new];
@@ -442,23 +441,8 @@ const CGFloat kTypingCellHeight = 24;
urlPreviewView.tag = index;
[temporaryViews addObject:urlPreviewView];
- [bubbleCell.tmpSubviews addObject:urlPreviewView];
-
- urlPreviewView.translatesAutoresizingMaskIntoConstraints = NO;
- urlPreviewView.availableWidth = cellData.maxTextViewWidth;
- [bubbleCell.contentView addSubview:urlPreviewView];
-
- CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
- if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
- {
- leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
- }
-
- // Set the preview view's origin
- [NSLayoutConstraint activateConstraints: @[
- [urlPreviewView.leadingAnchor constraintEqualToAnchor:urlPreviewView.superview.leadingAnchor constant:leftMargin],
- [urlPreviewView.topAnchor constraintEqualToAnchor:urlPreviewView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin],
- ]];
+ [cellDecorator addURLPreviewView:urlPreviewView
+ toCell:bubbleCell cellData:cellData contentViewPositionY:bottomPositionY];
}
MXAggregatedReactions* reactions = cellData.reactions[componentEventId].aggregatedReactionsWithNonZeroCount;
@@ -480,44 +464,8 @@ const CGFloat kTypingCellHeight = 24;
bubbleReactionsViewModel.viewModelDelegate = self;
[temporaryViews addObject:reactionsView];
- [bubbleCell.tmpSubviews addObject:reactionsView];
-
- if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReactionsDisplayable)])
- {
- id reactionsDisplayable = (id)bubbleCell;
- [reactionsDisplayable addReactionsView:reactionsView];
- }
- else
- {
- reactionsView.translatesAutoresizingMaskIntoConstraints = NO;
- [bubbleCell.contentView addSubview:reactionsView];
-
- CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
-
- if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
- {
- leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
- }
-
- // The top constraint may need to include the URL preview view
- NSLayoutConstraint *topConstraint;
- if (urlPreviewView)
- {
- topConstraint = [reactionsView.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor constant:RoomBubbleCellLayout.reactionsViewTopMargin];
- }
- else
- {
- topConstraint = [reactionsView.topAnchor constraintEqualToAnchor:reactionsView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.reactionsViewTopMargin];
- }
-
- // Force receipts container size
- [NSLayoutConstraint activateConstraints:
- @[
- [reactionsView.leadingAnchor constraintEqualToAnchor:reactionsView.superview.leadingAnchor constant:leftMargin],
- [reactionsView.trailingAnchor constraintEqualToAnchor:reactionsView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin],
- topConstraint
- ]];
- }
+ [cellDecorator addReactionView:reactionsView toCell:bubbleCell
+ cellData:cellData contentViewPositionY:bottomPositionY upperDecorationView:urlPreviewView];
}
ThreadSummaryView *threadSummaryView;
@@ -527,55 +475,16 @@ const CGFloat kTypingCellHeight = 24;
{
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread];
threadSummaryView.delegate = self;
-
+ threadSummaryView.tag = index;
+
[temporaryViews addObject:threadSummaryView];
- [bubbleCell.tmpSubviews addObject:threadSummaryView];
+ UIView *upperDecorationView = reactionsView ?: urlPreviewView;
- threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
-
- if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellThreadSummaryDisplayable)])
- {
- id threadSummaryDisplayable = (id)bubbleCell;
-
- [threadSummaryDisplayable addThreadSummaryView:threadSummaryView];
- }
- else
- {
- [bubbleCell.contentView addSubview:threadSummaryView];
-
- CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
- if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
- {
- leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
- }
-
- // The top constraint may need to include the URL preview view or reactions view
- NSLayoutConstraint *topConstraint;
- if (reactionsView)
- {
- topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor
- constant:RoomBubbleCellLayout.threadSummaryViewTopMargin];
- }
- else if (urlPreviewView)
- {
- topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor
- constant:RoomBubbleCellLayout.threadSummaryViewTopMargin];
- }
- else
- {
- topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
- constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin];
- }
-
- // Set constraints for the summary view
- [NSLayoutConstraint activateConstraints: @[
- [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
- constant:leftMargin],
- topConstraint,
- [threadSummaryView.heightAnchor constraintEqualToConstant:[ThreadSummaryView contentViewHeightForThread:component.thread fitting:cellData.maxTextViewWidth]],
- [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
- ]];
- }
+ [cellDecorator addThreadSummaryView:threadSummaryView
+ toCell:bubbleCell
+ cellData:cellData
+ contentViewPositionY:bottomPositionY
+ upperDecorationView:upperDecorationView];
}
MXKReceiptSendersContainer* avatarsContainer;
@@ -633,67 +542,13 @@ const CGFloat kTypingCellHeight = 24;
avatarsContainer.accessibilityIdentifier = @"readReceiptsContainer";
[temporaryViews addObject:avatarsContainer];
- // Add this read receipts container in the content view
- [bubbleCell.tmpSubviews addObject:avatarsContainer];
+ UIView *upperDecorationView = threadSummaryView ?: (reactionsView ?: urlPreviewView);
- if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReadReceiptsDisplayable)])
- {
- id readReceiptsDisplayable = (id)bubbleCell;
-
- [readReceiptsDisplayable addReadReceiptsView:avatarsContainer];
- }
- else
- {
- [bubbleCell.contentView addSubview:avatarsContainer];
-
- // Force receipts container size
- NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
- attribute:NSLayoutAttributeWidth
- relatedBy:NSLayoutRelationEqual
- toItem:nil
- attribute:NSLayoutAttributeNotAnAttribute
- multiplier:1.0
- constant:RoomBubbleCellLayout.readReceiptsViewWidth];
- NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
- attribute:NSLayoutAttributeHeight
- relatedBy:NSLayoutRelationEqual
- toItem:nil
- attribute:NSLayoutAttributeNotAnAttribute
- multiplier:1.0
- constant:RoomBubbleCellLayout.readReceiptsViewHeight];
-
- // Force receipts container position
- NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
- attribute:NSLayoutAttributeTrailing
- relatedBy:NSLayoutRelationEqual
- toItem:avatarsContainer.superview
- attribute:NSLayoutAttributeTrailing
- multiplier:1.0
- constant:-RoomBubbleCellLayout.readReceiptsViewRightMargin];
-
- // At the bottom, we either have a thread summary, a reactions, a URL preview or nothing
- NSLayoutConstraint *topConstraint;
- if (threadSummaryView)
- {
- topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:threadSummaryView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
- }
- else if (reactionsView)
- {
- topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
- }
- else if (urlPreviewView)
- {
- topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
- }
- else
- {
- topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:avatarsContainer.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.readReceiptsViewTopMargin];
- }
-
-
- // Available on iOS 8 and later
- [NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, trailingConstraint]];
- }
+ [cellDecorator addReadReceiptsView:avatarsContainer
+ toCell:bubbleCell
+ cellData:cellData
+ contentViewPositionY:bottomPositionY
+ upperDecorationView:upperDecorationView];
}
}
@@ -776,16 +631,7 @@ const CGFloat kTypingCellHeight = 24;
// Check whether an event is currently selected: the other messages are then blurred
if (_selectedEventId)
{
- // Check whether the selected event belongs to this bubble
- NSInteger selectedComponentIndex = cellData.selectedComponentIndex;
- if (selectedComponentIndex != NSNotFound)
- {
- [bubbleCell selectComponent:cellData.selectedComponentIndex showEditButton:NO showTimestamp:cellData.showTimestampForSelectedComponent];
- }
- else
- {
- bubbleCell.blurred = YES;
- }
+ [[RoomTimelineConfiguration shared].currentStyle applySelectedStyleIfNeededToCell:bubbleCell cellData:cellData];
}
// Reset the marker if any
@@ -822,13 +668,24 @@ const CGFloat kTypingCellHeight = 24;
// We are interested only by outgoing messages
if ([cellData.senderId isEqualToString: self.mxSession.credentials.userId])
{
- [bubbleCell updateTickViewWithFailedEventIds:self.failedEventIds];
+ [cellDecorator addSendStatusViewToCell:bubbleCell
+ withFailedEventIds:self.failedEventIds];
}
+
+ // Make extra cell layout updates if needed
+ [self updateCellLayoutIfNeeded:bubbleCell withCellData:cellData];
}
return cell;
}
+- (void)updateCellLayoutIfNeeded:(MXKRoomBubbleTableViewCell*)cell withCellData:(MXKRoomBubbleCellData*)cellData {
+
+ RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
+
+ [timelineConfiguration.currentStyle.cellLayoutUpdater updateLayoutIfNeededFor:cell andCellData:cellData];
+}
+
- (RoomBubbleCellData*)roomBubbleCellDataForEventId:(NSString*)eventId
{
id cellData = [self cellDataOfEventWithEventId:eventId];
diff --git a/Riot/Modules/Room/Location/LocationUserMarkerView.swift b/Riot/Modules/Room/Location/LocationMarkerView.swift
similarity index 93%
rename from Riot/Modules/Room/Location/LocationUserMarkerView.swift
rename to Riot/Modules/Room/Location/LocationMarkerView.swift
index 995d1ae56..caf101a1b 100644
--- a/Riot/Modules/Room/Location/LocationUserMarkerView.swift
+++ b/Riot/Modules/Room/Location/LocationMarkerView.swift
@@ -18,7 +18,7 @@ import UIKit
import Reusable
import Mapbox
-class LocationUserMarkerView: MGLAnnotationView, NibLoadable {
+class LocationMarkerView: MGLAnnotationView, NibLoadable {
@IBOutlet private var avatarView: UserAvatarView!
diff --git a/Riot/Modules/Room/Location/LocationMarkerView.xib b/Riot/Modules/Room/Location/LocationMarkerView.xib
new file mode 100644
index 000000000..837db5503
--- /dev/null
+++ b/Riot/Modules/Room/Location/LocationMarkerView.xib
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Riot/Modules/Room/Location/LocationUserMarkerView.xib b/Riot/Modules/Room/Location/LocationUserMarkerView.xib
deleted file mode 100644
index 26495f925..000000000
--- a/Riot/Modules/Room/Location/LocationUserMarkerView.xib
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Riot/Modules/Room/Location/RoomTimelineLocationView.swift b/Riot/Modules/Room/Location/RoomTimelineLocationView.swift
index 82cebe7cd..17ee83b4c 100644
--- a/Riot/Modules/Room/Location/RoomTimelineLocationView.swift
+++ b/Riot/Modules/Room/Location/RoomTimelineLocationView.swift
@@ -17,7 +17,6 @@
import UIKit
import Reusable
import Mapbox
-import Keys
class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegate {
@@ -25,7 +24,6 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
private struct Constants {
static let mapHeight: CGFloat = 300.0
- static let mapTilerKey = RiotKeys().mapTilerAPIKey
static let mapZoomLevel = 15.0
static let cellBorderRadius: CGFloat = 1.0
static let cellCornerRadius: CGFloat = 8.0
@@ -36,9 +34,10 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
@IBOutlet private var descriptionContainerView: UIView!
@IBOutlet private var descriptionLabel: UILabel!
+ @IBOutlet private var descriptionIcon: UIImageView!
private var mapView: MGLMapView!
- private var annotationView: LocationUserMarkerView?
+ private var annotationView: LocationMarkerView?
// MARK: Public
@@ -73,19 +72,13 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
// MARK: - Public
- public func displayLocation(_ location: CLLocationCoordinate2D,
- userIdentifier: String,
- userDisplayName: String,
- userAvatarURLString: String?,
- mediaManager: MXMediaManager) {
-
- annotationView = LocationUserMarkerView.loadFromNib()
+ public func displayLocation(_ location: CLLocationCoordinate2D, userAvatarData: AvatarViewData? = nil) {
- annotationView?.setAvatarData(AvatarViewData(matrixItemId: userIdentifier,
- displayName: userDisplayName,
- avatarUrl: userAvatarURLString,
- mediaManager: mediaManager,
- fallbackImage: .matrixItem(userIdentifier, userDisplayName)))
+ annotationView = LocationMarkerView.loadFromNib()
+
+ if let userAvatarData = userAvatarData {
+ annotationView?.setAvatarData(userAvatarData)
+ }
if let annotations = mapView.annotations {
mapView.removeAnnotations(annotations)
@@ -103,6 +96,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
func update(theme: Theme) {
descriptionLabel.textColor = theme.colors.primaryContent
descriptionLabel.font = theme.fonts.footnote
+ descriptionIcon.tintColor = theme.colors.accent
layer.borderColor = theme.colors.quinaryContent.cgColor
}
diff --git a/Riot/Modules/Room/Location/RoomTimelineLocationView.xib b/Riot/Modules/Room/Location/RoomTimelineLocationView.xib
index 8beacacbe..acc469b74 100644
--- a/Riot/Modules/Room/Location/RoomTimelineLocationView.xib
+++ b/Riot/Modules/Room/Location/RoomTimelineLocationView.xib
@@ -58,6 +58,7 @@
+
diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomViewController.h b/Riot/Modules/Room/MXKRoomViewController.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Controllers/MXKRoomViewController.h
rename to Riot/Modules/Room/MXKRoomViewController.h
diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomViewController.m b/Riot/Modules/Room/MXKRoomViewController.m
similarity index 97%
rename from Riot/Modules/MatrixKit/Controllers/MXKRoomViewController.m
rename to Riot/Modules/Room/MXKRoomViewController.m
index 942eeec58..0028f45f3 100644
--- a/Riot/Modules/MatrixKit/Controllers/MXKRoomViewController.m
+++ b/Riot/Modules/Room/MXKRoomViewController.m
@@ -36,16 +36,6 @@
#import "MXKRoomBubbleCellData.h"
-#import "MXKRoomIncomingTextMsgBubbleCell.h"
-#import "MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
-#import "MXKRoomIncomingAttachmentBubbleCell.h"
-#import "MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
-
-#import "MXKRoomOutgoingTextMsgBubbleCell.h"
-#import "MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
-#import "MXKRoomOutgoingAttachmentBubbleCell.h"
-#import "MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
-
#import "MXKEncryptionKeysImportView.h"
#import "NSBundle+MatrixKit.h"
@@ -616,17 +606,6 @@
_bubblesTableView.delegate = self;
_bubblesTableView.dataSource = roomDataSource; // Note: data source may be nil here, it will be set during [displayRoom:] call.
- // Set up default classes to use for cells
- [_bubblesTableView registerClass:MXKRoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
- [_bubblesTableView registerClass:MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [_bubblesTableView registerClass:MXKRoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
- [_bubblesTableView registerClass:MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
-
- [_bubblesTableView registerClass:MXKRoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
- [_bubblesTableView registerClass:MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [_bubblesTableView registerClass:MXKRoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
- [_bubblesTableView registerClass:MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
-
// Observe kMXSessionWillLeaveRoomNotification to be notified if the user leaves the current room.
MXWeakify(self);
_mxSessionWillLeaveRoomNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionWillLeaveRoomNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
@@ -2477,64 +2456,7 @@
- (Class)cellViewClassForCellData:(MXKCellData*)cellData
{
- Class cellViewClass = nil;
-
- // Sanity check
- if ([cellData conformsToProtocol:@protocol(MXKRoomBubbleCellDataStoring)])
- {
- id bubbleData = (id)cellData;
-
- // Select the suitable table view cell class
- if (bubbleData.isIncoming)
- {
- if (bubbleData.isAttachmentWithThumbnail)
- {
- if (bubbleData.shouldHideSenderInformation)
- {
- cellViewClass = MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.class;
- }
- else
- {
- cellViewClass = MXKRoomIncomingAttachmentBubbleCell.class;
- }
- }
- else
- {
- if (bubbleData.shouldHideSenderInformation)
- {
- cellViewClass = MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.class;
- }
- else
- {
- cellViewClass = MXKRoomIncomingTextMsgBubbleCell.class;
- }
- }
- }
- else if (bubbleData.isAttachmentWithThumbnail)
- {
- if (bubbleData.shouldHideSenderInformation)
- {
- cellViewClass = MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class;
- }
- else
- {
- cellViewClass = MXKRoomOutgoingAttachmentBubbleCell.class;
- }
- }
- else
- {
- if (bubbleData.shouldHideSenderInformation)
- {
- cellViewClass = MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class;
- }
- else
- {
- cellViewClass = MXKRoomOutgoingTextMsgBubbleCell.class;
- }
- }
- }
-
- return cellViewClass;
+ return nil;
}
- (NSString *)cellReuseIdentifierForCellData:(MXKCellData*)cellData
diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomViewController.xib b/Riot/Modules/Room/MXKRoomViewController.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Controllers/MXKRoomViewController.xib
rename to Riot/Modules/Room/MXKRoomViewController.xib
diff --git a/Riot/Modules/Room/RoomCoordinator.swift b/Riot/Modules/Room/RoomCoordinator.swift
index 7d71e1cb7..53f1a2202 100644
--- a/Riot/Modules/Room/RoomCoordinator.swift
+++ b/Riot/Modules/Room/RoomCoordinator.swift
@@ -134,7 +134,7 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
self.selectedEventId = eventId
if self.hasStartedOnce {
- self.roomViewController.highlightEvent(eventId, completion: completion)
+ self.roomViewController.highlightAndDisplayEvent(eventId, completion: completion)
} else {
self.start(withCompletion: completion)
}
diff --git a/Riot/Modules/Room/RoomViewController.h b/Riot/Modules/Room/RoomViewController.h
index 49adefb8f..c47948655 100644
--- a/Riot/Modules/Room/RoomViewController.h
+++ b/Riot/Modules/Room/RoomViewController.h
@@ -106,7 +106,7 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification;
@param eventId Identifier of the event to be highlighted.
@param completion Completion block to be called at the end of process. Optional.
*/
-- (void)highlightEvent:(NSString *)eventId completion:(nullable void (^)(void))completion;
+- (void)highlightAndDisplayEvent:(NSString *)eventId completion:(nullable void (^)(void))completion;
/**
Creates and returns a new `RoomViewController` object.
diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m
index f11675450..2acf9f1a2 100644
--- a/Riot/Modules/Room/RoomViewController.m
+++ b/Riot/Modules/Room/RoomViewController.m
@@ -54,55 +54,7 @@
#import "JitsiViewController.h"
#import "RoomEmptyBubbleCell.h"
-
-#import "RoomIncomingTextMsgBubbleCell.h"
-#import "RoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
-#import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h"
-#import "RoomIncomingTextMsgWithoutSenderNameBubbleCell.h"
-#import "RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
-#import "RoomIncomingAttachmentBubbleCell.h"
-#import "RoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
-#import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h"
-
-#import "RoomIncomingEncryptedTextMsgBubbleCell.h"
-#import "RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
-#import "RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
-#import "RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
-#import "RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
-#import "RoomIncomingEncryptedAttachmentBubbleCell.h"
-#import "RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
-#import "RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
-
-#import "RoomOutgoingTextMsgBubbleCell.h"
-#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
-#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
-#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
-#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
-#import "RoomOutgoingAttachmentBubbleCell.h"
-#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
-#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
-
-#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
-#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
-#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
-#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
-#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
-#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
-#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
-#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
-
-#import "RoomMembershipBubbleCell.h"
-#import "RoomMembershipWithPaginationTitleBubbleCell.h"
-#import "RoomMembershipCollapsedBubbleCell.h"
-#import "RoomMembershipCollapsedWithPaginationTitleBubbleCell.h"
#import "RoomMembershipExpandedBubbleCell.h"
-#import "RoomMembershipExpandedWithPaginationTitleBubbleCell.h"
-#import "RoomCreationWithPaginationCollapsedBubbleCell.h"
-#import "RoomCreationCollapsedBubbleCell.h"
-
-#import "RoomSelectedStickerBubbleCell.h"
-#import "RoomPredecessorBubbleCell.h"
-
#import "MXKRoomBubbleTableViewCell+Riot.h"
#import "AvatarGenerator.h"
@@ -130,6 +82,8 @@
#import "MXSDKOptions.h"
+#import "RoomTimelineCellProvider.h"
+
#import "GeneratedInterface-Swift.h"
NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNotification";
@@ -139,7 +93,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
@interface RoomViewController ()
+ RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate>
{
// The preview header
@@ -246,9 +200,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
@property (nonatomic, strong) RoomMessageURLParser *roomMessageURLParser;
@property (nonatomic, strong) RoomCreationModalCoordinatorBridgePresenter *roomCreationModalCoordinatorBridgePresenter;
@property (nonatomic, strong) RoomInfoCoordinatorBridgePresenter *roomInfoCoordinatorBridgePresenter;
-@property (nonatomic, strong) RoomCoordinatorBridgePresenter *threadBridgePresenter;
@property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController;
-@property (nonatomic, strong) ThreadsCoordinatorBridgePresenter *threadsCoordinatorBridgePresenter;
+@property (nonatomic, strong) ThreadsCoordinatorBridgePresenter *threadsBridgePresenter;
@property (nonatomic, getter=isActivitiesViewExpanded) BOOL activitiesViewExpanded;
@property (nonatomic, getter=isScrollToBottomHidden) BOOL scrollToBottomHidden;
@property (nonatomic, getter=isMissedDiscussionsBadgeHidden) BOOL missedDiscussionsBadgeHidden;
@@ -372,83 +325,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[super viewDidLoad];
// Register first customized cell view classes used to render bubbles
- [self.bubblesTableView registerClass:RoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomEmptyBubbleCell.class forCellReuseIdentifier:RoomEmptyBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomMembershipBubbleCell.class forCellReuseIdentifier:RoomMembershipBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomMembershipWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomMembershipCollapsedBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomMembershipCollapsedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomMembershipExpandedBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomMembershipExpandedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomSelectedStickerBubbleCell.class forCellReuseIdentifier:RoomSelectedStickerBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:KeyVerificationConclusionWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionWithPaginationTitleBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomCreationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationCollapsedBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomCreationWithPaginationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationWithPaginationCollapsedBubbleCell.defaultReuseIdentifier];
-
- // call cells
- [self.bubblesTableView registerClass:RoomDirectCallStatusBubbleCell.class forCellReuseIdentifier:RoomDirectCallStatusBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:RoomGroupCallStatusBubbleCell.class forCellReuseIdentifier:RoomGroupCallStatusBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:RoomCreationIntroCell.class forCellReuseIdentifier:RoomCreationIntroCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerNib:RoomTypingBubbleCell.nib forCellReuseIdentifier:RoomTypingBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:VoiceMessageBubbleCell.class forCellReuseIdentifier:VoiceMessageBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:VoiceMessageWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:VoiceMessageWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageWithPaginationTitleBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:PollBubbleCell.class forCellReuseIdentifier:PollBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:PollWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:PollWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:PollWithPaginationTitleBubbleCell.class forCellReuseIdentifier:PollWithPaginationTitleBubbleCell.defaultReuseIdentifier];
-
- [self.bubblesTableView registerClass:LocationBubbleCell.class forCellReuseIdentifier:LocationBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:LocationWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
- [self.bubblesTableView registerClass:LocationWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [[RoomTimelineConfiguration shared].currentStyle.cellProvider registerCellsForTableView:self.bubblesTableView];
[self vc_removeBackTitle];
@@ -2271,6 +2148,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[MXSDKOptions sharedInstance].videoConversionPresetName = presetName;
[roomInputToolbarView sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:isPhotoLibraryAsset];
}];
+ compressionPrompt.popoverPresentationController.sourceView = roomInputToolbarView.attachMediaButton;
+ compressionPrompt.popoverPresentationController.sourceRect = roomInputToolbarView.attachMediaButton.bounds;
[self presentViewController:compressionPrompt animated:YES completion:nil];
}
@@ -2733,14 +2612,23 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (Class)cellViewClassForCellData:(MXKCellData*)cellData
{
- Class cellViewClass = nil;
- BOOL showEncryptionBadge = NO;
+ RoomTimelineCellIdentifier cellIdentifier = [self cellIdentifierForCellData:cellData andRoomDataSource:customizedRoomDataSource];
+ RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
+
+ return [timelineConfiguration.currentStyle.cellProvider cellViewClassForCellIdentifier:cellIdentifier];;
+}
+
+- (RoomTimelineCellIdentifier)cellIdentifierForCellData:(MXKCellData*)cellData andRoomDataSource:(RoomDataSource *)customizedRoomDataSource;
+{
// Sanity check
if (![cellData conformsToProtocol:@protocol(MXKRoomBubbleCellDataStoring)])
{
- return nil;
+ return RoomTimelineCellIdentifierUnknown;
}
+
+ BOOL showEncryptionBadge = NO;
+ RoomTimelineCellIdentifier cellIdentifier;
id bubbleData = (id)cellData;
@@ -2755,27 +2643,27 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Select the suitable table view cell class, by considering first the empty bubble cell.
if (bubbleData.hasNoDisplay)
{
- cellViewClass = RoomEmptyBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierEmpty;
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreationIntro)
{
- cellViewClass = RoomCreationIntroCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierRoomCreationIntro;
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor)
{
- cellViewClass = RoomPredecessorBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierRoomPredecessor;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval)
{
- cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class : KeyVerificationIncomingRequestApprovalBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequest)
{
- cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class : KeyVerificationRequestStatusBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationRequestStatus;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationConclusion)
{
- cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationConclusionWithPaginationTitleBubbleCell.class : KeyVerificationConclusionBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationConclusion;
}
else if (bubbleData.tag == RoomBubbleCellDataTagMembership)
{
@@ -2783,80 +2671,80 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.nextCollapsableCellData)
{
- cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipCollapsedWithPaginationTitleBubbleCell.class : RoomMembershipCollapsedBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle : RoomTimelineCellIdentifierMembershipCollapsed;
}
else
{
// Use a normal membership cell for a single membership event
- cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipWithPaginationTitleBubbleCell.class : RoomMembershipBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipWithPaginationTitle : RoomTimelineCellIdentifierMembership;
}
}
else if (bubbleData.collapsedAttributedTextMessage)
{
// The cell (and its series) is not collapsed but this cell is the first
// of the series. So, use the cell with the "collapse" button.
- cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipExpandedWithPaginationTitleBubbleCell.class : RoomMembershipExpandedBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle : RoomTimelineCellIdentifierMembershipExpanded;
}
else
{
- cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipWithPaginationTitleBubbleCell.class : RoomMembershipBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipWithPaginationTitle : RoomTimelineCellIdentifierMembership;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreateConfiguration)
{
- cellViewClass = bubbleData.isPaginationFirstBubble ? RoomCreationWithPaginationCollapsedBubbleCell.class : RoomCreationCollapsedBubbleCell.class;
+ cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle : RoomTimelineCellIdentifierRoomCreationCollapsed;
}
else if (bubbleData.tag == RoomBubbleCellDataTagCall)
{
- cellViewClass = RoomDirectCallStatusBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierDirectCallStatus;
}
else if (bubbleData.tag == RoomBubbleCellDataTagGroupCall)
{
- cellViewClass = RoomGroupCallStatusBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierGroupCallStatus;
}
else if (bubbleData.attachment.type == MXKAttachmentTypeVoiceMessage || bubbleData.attachment.type == MXKAttachmentTypeAudio)
{
if (bubbleData.isPaginationFirstBubble)
{
- cellViewClass = VoiceMessageWithPaginationTitleBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
- cellViewClass = VoiceMessageWithoutSenderInfoBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo;
}
else
{
- cellViewClass = VoiceMessageBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierVoiceMessage;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagPoll)
{
if (bubbleData.isPaginationFirstBubble)
{
- cellViewClass = PollWithPaginationTitleBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierPollWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
- cellViewClass = PollWithoutSenderInfoBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierPollWithoutSenderInfo;
}
else
{
- cellViewClass = PollBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierPoll;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagLocation)
{
if (bubbleData.isPaginationFirstBubble)
{
- cellViewClass = LocationWithPaginationTitleBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierLocationWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
- cellViewClass = LocationWithoutSenderInfoBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierLocationWithoutSenderInfo;
}
else
{
- cellViewClass = LocationBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierLocation;
}
}
else if (bubbleData.isIncoming)
@@ -2866,19 +2754,19 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Check whether the provided celldata corresponds to a selected sticker
if (customizedRoomDataSource.selectedEventId && (bubbleData.attachment.type == MXKAttachmentTypeSticker) && [bubbleData.attachment.eventId isEqualToString:customizedRoomDataSource.selectedEventId])
{
- cellViewClass = RoomSelectedStickerBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierSelectedSticker;
}
else if (bubbleData.isPaginationFirstBubble)
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo;
}
else
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentBubbleCell.class : RoomIncomingAttachmentBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncrypted : RoomTimelineCellIdentifierIncomingAttachment;
}
}
else
@@ -2887,24 +2775,24 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.shouldHideSenderName)
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class : RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName;
}
else
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class : RoomIncomingTextMsgWithPaginationTitleBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class : RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class : RoomIncomingTextMsgWithoutSenderNameBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName : RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName;
}
else
{
- cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgBubbleCell.class : RoomIncomingTextMsgBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncrypted : RoomTimelineCellIdentifierIncomingTextMessage;
}
}
}
@@ -2916,19 +2804,19 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Check whether the provided celldata corresponds to a selected sticker
if (customizedRoomDataSource.selectedEventId && (bubbleData.attachment.type == MXKAttachmentTypeSticker) && [bubbleData.attachment.eventId isEqualToString:customizedRoomDataSource.selectedEventId])
{
- cellViewClass = RoomSelectedStickerBubbleCell.class;
+ cellIdentifier = RoomTimelineCellIdentifierSelectedSticker;
}
else if (bubbleData.isPaginationFirstBubble)
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class :RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo;
}
else
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentBubbleCell.class : RoomOutgoingAttachmentBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncrypted : RoomTimelineCellIdentifierOutgoingAttachment;
}
}
else
@@ -2937,29 +2825,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.shouldHideSenderName)
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName;
}
else
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class : RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class :RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName : RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName;
}
else
{
- cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgBubbleCell.class : RoomOutgoingTextMsgBubbleCell.class;
+ cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncrypted : RoomTimelineCellIdentifierOutgoingTextMessage;
}
}
}
- return cellViewClass;
+ return cellIdentifier;
}
#pragma mark - MXKDataSource delegate
@@ -3426,6 +3314,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
+
+ [self cancelEventSelection];
+
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
}]];
}
@@ -3455,6 +3346,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
+
+ [self cancelEventSelection];
+
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
}]];
}
@@ -3496,6 +3390,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
+
+ [self cancelEventSelection];
+
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
}]];
}
@@ -3657,10 +3554,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Create a matrix.to permalink that is common to all matrix clients
NSString *permalink = [MXTools permalinkToEvent:selectedEvent.eventId inRoom:selectedEvent.roomId];
+ NSURL *url = [NSURL URLWithString:permalink];
- if (permalink)
+ if (url)
{
- MXKPasteboardManager.shared.pasteboard.string = permalink;
+ MXKPasteboardManager.shared.pasteboard.URL = url;
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
image:[UIImage imageNamed:@"link_icon"]
duration:2.0
@@ -3711,24 +3609,21 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
if (selectedEvent.eventType != MXEventTypeRoomEncryption)
{
NSString *title;
- UIAlertActionStyle style;
EventMenuItemType itemType;
if (selectedEvent.eventType == MXEventTypePollStart)
{
title = [VectorL10n roomEventActionRemovePoll];
- style = UIAlertActionStyleDefault;
itemType = EventMenuItemTypeRemovePoll;
}
else
{
title = [VectorL10n roomEventActionRedact];
- style = UIAlertActionStyleDestructive;
itemType = EventMenuItemTypeRemove;
}
[self.eventMenuBuilder addItemWithType:itemType
action:[UIAlertAction actionWithTitle:title
- style:style
+ style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
@@ -4545,10 +4440,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (IBAction)onThreadListTapped:(id)sender
{
- self.threadsCoordinatorBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
- roomId:self.roomDataSource.roomId];
- self.threadsCoordinatorBridgePresenter.delegate = self;
- [self.threadsCoordinatorBridgePresenter pushFrom:self.navigationController animated:YES];
+ self.threadsBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
+ roomId:self.roomDataSource.roomId
+ threadId:nil];
+ self.threadsBridgePresenter.delegate = self;
+ [self.threadsBridgePresenter pushFrom:self.navigationController animated:YES];
}
- (IBAction)onIntegrationsPressed:(id)sender
@@ -6571,25 +6467,20 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (void)openThreadWithId:(NSString *)threadId
{
- if (self.threadBridgePresenter)
+ if (self.threadsBridgePresenter)
{
- [self.threadBridgePresenter dismissWithAnimated:YES completion:nil];
- self.threadBridgePresenter = nil;
+ [self.threadsBridgePresenter dismissWithAnimated:YES completion:nil];
+ self.threadsBridgePresenter = nil;
}
-
- RoomDisplayConfiguration *configuration = RoomDisplayConfiguration.forThreads;
- RoomCoordinatorBridgePresenterParameters *parameters = [[RoomCoordinatorBridgePresenterParameters alloc] initWithSession:self.mainSession
- roomId:self.roomDataSource.roomId
- eventId:nil
- threadId:threadId
- displayConfiguration:configuration
- previewData:nil];
- self.threadBridgePresenter = [[RoomCoordinatorBridgePresenter alloc] initWithParameters:parameters];
- self.threadBridgePresenter.delegate = self;
- [self.threadBridgePresenter pushFrom:self.navigationController animated:YES];
+
+ self.threadsBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
+ roomId:self.roomDataSource.roomId
+ threadId:threadId];
+ self.threadsBridgePresenter.delegate = self;
+ [self.threadsBridgePresenter pushFrom:self.navigationController animated:YES];
}
-- (void)highlightEvent:(NSString *)eventId completion:(void (^)(void))completion
+- (void)highlightAndDisplayEvent:(NSString *)eventId completion:(void (^)(void))completion
{
NSInteger row = [self.roomDataSource indexOfCellDataWithEventId:eventId];
if (row == NSNotFound)
@@ -7100,66 +6991,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[self mention:member];
}
-#pragma mark - RoomCoordinatorBridgePresenterDelegate
-
-- (void)roomCoordinatorBridgePresenterDidLeaveRoom:(RoomCoordinatorBridgePresenter *)bridgePresenter
-{
-
-}
-
-- (void)roomCoordinatorBridgePresenterDidCancelRoomPreview:(RoomCoordinatorBridgePresenter *)bridgePresenter
-{
-
-}
-
-- (void)roomCoordinatorBridgePresenter:(RoomCoordinatorBridgePresenter *)bridgePresenter
- didSelectRoomWithId:(NSString *)roomId
- eventId:(NSString*)eventId
-{
- if (bridgePresenter == self.threadBridgePresenter && [roomId isEqualToString:self.roomDataSource.roomId] && eventId)
- {
- // thread view wants to highlight an event in the timeline
- // dismiss thread view first
- MXWeakify(self);
- [self.threadBridgePresenter dismissWithAnimated:YES completion:^{
- MXStrongifyAndReturnIfNil(self);
-
- [self highlightEvent:eventId completion:nil];
- }];
- }
-}
-
-- (void)roomCoordinatorBridgePresenterDidDismissInteractively:(RoomCoordinatorBridgePresenter *)bridgePresenter
-{
- if (bridgePresenter == self.threadBridgePresenter)
- {
- self.threadBridgePresenter = nil;
- }
-}
-
#pragma mark - ThreadsCoordinatorBridgePresenterDelegate
- (void)threadsCoordinatorBridgePresenterDelegateDidComplete:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
- self.threadsCoordinatorBridgePresenter = nil;
+ self.threadsBridgePresenter = nil;
}
- (void)threadsCoordinatorBridgePresenterDelegateDidSelect:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter roomId:(NSString *)roomId eventId:(NSString *)eventId
{
MXWeakify(self);
- [self.threadsCoordinatorBridgePresenter dismissWithAnimated:YES completion:^{
+ [self.threadsBridgePresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
if (eventId)
{
- [self highlightEvent:eventId completion:nil];
+ [self highlightAndDisplayEvent:eventId completion:nil];
}
}];
}
- (void)threadsCoordinatorBridgePresenterDidDismissInteractively:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
- self.threadsCoordinatorBridgePresenter = nil;
+ self.threadsBridgePresenter = nil;
}
#pragma mark - MXThreadingServiceDelegate
diff --git a/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m b/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m
index 8e5b651f7..fb526a9fb 100644
--- a/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m
+++ b/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m
@@ -127,57 +127,62 @@
// Display date for each message
[bubbleCell addDateLabel];
- RoomBubbleCellData *cellData = (RoomBubbleCellData*)[self cellDataAtIndex:indexPath.row];
- MXEvent *event = cellData.events.firstObject;
-
- if (event)
+ if (RiotSettings.shared.enableThreads)
{
- if (cellData.hasThreadRoot)
+ RoomBubbleCellData *cellData = (RoomBubbleCellData*)[self cellDataAtIndex:indexPath.row];
+ MXEvent *event = cellData.events.firstObject;
+
+ if (event)
{
- MXThread *thread = cellData.bubbleComponents.firstObject.thread;
- ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
- [bubbleCell.tmpSubviews addObject:threadSummaryView];
+ if (cellData.hasThreadRoot)
+ {
+ MXThread *thread = cellData.bubbleComponents.firstObject.thread;
+ ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
+ [bubbleCell.tmpSubviews addObject:threadSummaryView];
- threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
- [bubbleCell.contentView addSubview:threadSummaryView];
+ threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
+ [bubbleCell.contentView addSubview:threadSummaryView];
- CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth];
- CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
- CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
+ CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
+ CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
- // Set constraints for the summary view
- [NSLayoutConstraint activateConstraints: @[
- [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
- constant:leftMargin],
- [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
+ // Set constraints for the summary view
+ [NSLayoutConstraint activateConstraints: @[
+ [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
+ constant:leftMargin],
+ [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin],
- [threadSummaryView.heightAnchor constraintEqualToConstant:[ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth]],
- [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
- ]];
- }
- else if (event.isInThread)
- {
- FromThreadView *fromThreadView = [FromThreadView instantiate];
- [bubbleCell.tmpSubviews addObject:fromThreadView];
+ [threadSummaryView.heightAnchor constraintEqualToConstant:height],
+ [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
+ ]];
+ }
+ else if (event.isInThread)
+ {
+ FromAThreadView *fromAThreadView = [FromAThreadView instantiate];
+ [bubbleCell.tmpSubviews addObject:fromAThreadView];
+
+ fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO;
+ [bubbleCell.contentView addSubview:fromAThreadView];
- fromThreadView.translatesAutoresizingMaskIntoConstraints = NO;
- [bubbleCell.contentView addSubview:fromThreadView];
+ CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth];
- CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
+ CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
+ CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
- CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
- CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
-
- // Set constraints for the summary view
- [NSLayoutConstraint activateConstraints: @[
- [fromThreadView.leadingAnchor constraintEqualToAnchor:fromThreadView.superview.leadingAnchor
- constant:leftMargin],
- [fromThreadView.topAnchor constraintEqualToAnchor:fromThreadView.superview.topAnchor
- constant:bottomPositionY + RoomBubbleCellLayout.fromThreadViewTopMargin],
- [fromThreadView.heightAnchor constraintEqualToConstant:[FromThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth]],
- [fromThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
- ]];
+ // Set constraints for the summary view
+ [NSLayoutConstraint activateConstraints: @[
+ [fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor
+ constant:leftMargin],
+ [fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor
+ constant:bottomPositionY + RoomBubbleCellLayout.fromAThreadViewTopMargin],
+ [fromAThreadView.heightAnchor constraintEqualToConstant:height],
+ [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
+ ]];
+ }
}
}
}
diff --git a/Riot/Modules/Room/Settings/RoomSettingsViewController.m b/Riot/Modules/Room/Settings/RoomSettingsViewController.m
index 1f77beb9a..aba02068d 100644
--- a/Riot/Modules/Room/Settings/RoomSettingsViewController.m
+++ b/Riot/Modules/Room/Settings/RoomSettingsViewController.m
@@ -1041,10 +1041,11 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
// Create a matrix.to permalink to the room
NSString *permalink = [MXTools permalinkToRoom:roomAliasLabel.text];
-
- if (permalink)
+ NSURL *url = [NSURL URLWithString:permalink];
+
+ if (url)
{
- MXKPasteboardManager.shared.pasteboard.string = permalink;
+ MXKPasteboardManager.shared.pasteboard.URL = url;
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
image:[UIImage imageNamed:@"link_icon"]
duration:2.0
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomBubbleTableViewCell.h b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomBubbleTableViewCell.h
similarity index 98%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomBubbleTableViewCell.h
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomBubbleTableViewCell.h
index 733d98141..b9fa3dd33 100644
--- a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomBubbleTableViewCell.h
+++ b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomBubbleTableViewCell.h
@@ -216,6 +216,7 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewMinHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewBottomConstraint;
+@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewLeadingConstraint;
/**
The constraints which defines the relationship between bubbleInfoContainer and its superview
@@ -325,4 +326,7 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
*/
- (void)setupViews;
+/// Add temporary subview to `tmpSubviews` property.
+- (void)addTemporarySubview:(UIView*)subview;
+
@end
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomBubbleTableViewCell.m b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomBubbleTableViewCell.m
similarity index 99%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomBubbleTableViewCell.m
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomBubbleTableViewCell.m
index 173606b09..b337d2c0f 100644
--- a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomBubbleTableViewCell.m
+++ b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomBubbleTableViewCell.m
@@ -1128,6 +1128,16 @@ static BOOL _disableLongPressGestureOnEvent;
[self resetAttachmentViewBottomConstraintConstant];
}
+- (void)addTemporarySubview:(UIView*)subview
+{
+ if (!self.tmpSubviews)
+ {
+ self.tmpSubviews = [NSMutableArray new];
+ }
+
+ [self.tmpSubviews addObject:subview];
+}
+
#pragma mark - Attachment progress handling
- (void)updateProgressUI:(NSDictionary*)statisticsDict
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSBubbleTableViewCell.h b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSBubbleTableViewCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSBubbleTableViewCell.h
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSBubbleTableViewCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSBubbleTableViewCell.m b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSBubbleTableViewCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSBubbleTableViewCell.m
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSBubbleTableViewCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSOutgoingBubbleTableViewCell.h b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSOutgoingBubbleTableViewCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSOutgoingBubbleTableViewCell.h
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSOutgoingBubbleTableViewCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSOutgoingBubbleTableViewCell.m b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSOutgoingBubbleTableViewCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSOutgoingBubbleTableViewCell.m
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSOutgoingBubbleTableViewCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSOutgoingBubbleTableViewCell.xib b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSOutgoingBubbleTableViewCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIOSOutgoingBubbleTableViewCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIOSOutgoingBubbleTableViewCell.xib
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingBubbleTableViewCell.h b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIncomingBubbleTableViewCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingBubbleTableViewCell.h
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIncomingBubbleTableViewCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingBubbleTableViewCell.m b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIncomingBubbleTableViewCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingBubbleTableViewCell.m
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomIncomingBubbleTableViewCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingBubbleTableViewCell.h b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomOutgoingBubbleTableViewCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingBubbleTableViewCell.h
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomOutgoingBubbleTableViewCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingBubbleTableViewCell.m b/Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomOutgoingBubbleTableViewCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingBubbleTableViewCell.m
rename to Riot/Modules/Room/Views/BubbleCells/Common/MXKRoomOutgoingBubbleTableViewCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomEmptyBubbleTableViewCell.h b/Riot/Modules/Room/Views/BubbleCells/EmptyContent/MXKRoomEmptyBubbleTableViewCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomEmptyBubbleTableViewCell.h
rename to Riot/Modules/Room/Views/BubbleCells/EmptyContent/MXKRoomEmptyBubbleTableViewCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomEmptyBubbleTableViewCell.m b/Riot/Modules/Room/Views/BubbleCells/EmptyContent/MXKRoomEmptyBubbleTableViewCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomEmptyBubbleTableViewCell.m
rename to Riot/Modules/Room/Views/BubbleCells/EmptyContent/MXKRoomEmptyBubbleTableViewCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomEmptyBubbleTableViewCell.xib b/Riot/Modules/Room/Views/BubbleCells/EmptyContent/MXKRoomEmptyBubbleTableViewCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomEmptyBubbleTableViewCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/EmptyContent/MXKRoomEmptyBubbleTableViewCell.xib
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentBubbleCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentBubbleCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentBubbleCell.xib
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Incoming/Common/MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.xib
diff --git a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.xib
index 7d8f2e78f..bdc4ee247 100644
--- a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.xib
+++ b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -128,6 +128,7 @@
+
diff --git a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib
index c6d5de460..c09b26ed2 100644
--- a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib
+++ b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -161,6 +161,7 @@
+
diff --git a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h
new file mode 100644
index 000000000..24c064505
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h
@@ -0,0 +1,24 @@
+/*
+ Copyright 2015 OpenMarket 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 "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
+
+/**
+ `RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell` displays outgoing attachment bubbles and pagination title but no sender name.
+ */
+@interface RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell : RoomOutgoingAttachmentWithPaginationTitleBubbleCell
+
+@end
diff --git a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.m
new file mode 100644
index 000000000..46ea41861
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.m
@@ -0,0 +1,32 @@
+/*
+ Copyright 2015 OpenMarket Ltd
+ Copyright 2017 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.
+ */
+
+#import "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
+
+#import "ThemeService.h"
+#import "GeneratedInterface-Swift.h"
+
+@implementation RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell
+
+- (void)customizeTableViewCellRendering
+{
+ [super customizeTableViewCellRendering];
+
+ self.messageTextView.tintColor = ThemeService.shared.theme.tintColor;
+}
+
+@end
diff --git a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.xib
new file mode 100644
index 000000000..cae2140da
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.xib
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib
index e31cd5257..73ca69699 100644
--- a/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib
+++ b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -95,6 +95,7 @@
+
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentBubbleCell.m
similarity index 93%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentBubbleCell.m
index 9a3e1cfe1..84c05d49a 100644
--- a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentBubbleCell.m
+++ b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentBubbleCell.m
@@ -23,6 +23,8 @@
#import "MXKImageView.h"
#import "MXKPieChartView.h"
+#import "GeneratedInterface-Swift.h"
+
@implementation MXKRoomOutgoingAttachmentBubbleCell
- (void)dealloc
@@ -30,6 +32,15 @@
[self stopAnimating];
}
+- (void)setupViews
+{
+ [super setupViews];
+
+ RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
+
+ [timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForOutgoingFileAttachmentCell:self];
+}
+
- (void)render:(MXKCellData *)cellData
{
[super render:cellData];
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentBubbleCell.xib
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/FileAttachment/Outgoing/Common/MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.xib
diff --git a/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift
index 2795d2647..cb56e7839 100644
--- a/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift
+++ b/Riot/Modules/Room/Views/BubbleCells/Location/LocationBubbleCell.swift
@@ -37,11 +37,17 @@ class LocationBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable
let location = CLLocationCoordinate2D(latitude: locationContent.latitude, longitude: locationContent.longitude)
- locationView.displayLocation(location,
- userIdentifier: bubbleData.senderId,
- userDisplayName: bubbleData.senderDisplayName,
- userAvatarURLString: bubbleData.senderAvatarUrl,
- mediaManager: bubbleData.mxSession.mediaManager)
+ if locationContent.assetType == .user {
+ let avatarViewData = AvatarViewData(matrixItemId: bubbleData.senderId,
+ displayName: bubbleData.senderDisplayName,
+ avatarUrl: bubbleData.senderAvatarUrl,
+ mediaManager: bubbleData.mxSession.mediaManager,
+ fallbackImage: .matrixItem(bubbleData.senderId, bubbleData.senderDisplayName))
+
+ locationView.displayLocation(location, userAvatarData: avatarViewData)
+ } else {
+ locationView.displayLocation(location)
+ }
}
override func setupViews() {
diff --git a/Riot/Modules/Room/Views/BubbleCells/Encryption/RoomBubbleCellLayout.swift b/Riot/Modules/Room/Views/BubbleCells/RoomBubbleCellLayout.swift
similarity index 96%
rename from Riot/Modules/Room/Views/BubbleCells/Encryption/RoomBubbleCellLayout.swift
rename to Riot/Modules/Room/Views/BubbleCells/RoomBubbleCellLayout.swift
index 461da960b..641bc0677 100644
--- a/Riot/Modules/Room/Views/BubbleCells/Encryption/RoomBubbleCellLayout.swift
+++ b/Riot/Modules/Room/Views/BubbleCells/RoomBubbleCellLayout.swift
@@ -51,5 +51,5 @@ final class RoomBubbleCellLayout: NSObject {
static let threadSummaryViewTopMargin: CGFloat = 8.0
static let threadSummaryViewHeight: CGFloat = 40.0
- static let fromThreadViewTopMargin: CGFloat = 8.0
+ static let fromAThreadViewTopMargin: CGFloat = 8.0
}
diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomTimelineCellIdentifier.h b/Riot/Modules/Room/Views/BubbleCells/RoomTimelineCellIdentifier.h
new file mode 100644
index 000000000..35a3b500a
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/RoomTimelineCellIdentifier.h
@@ -0,0 +1,115 @@
+//
+// Copyright 2021 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.
+//
+
+/// RoomTimelineCellIdentifier represents room timeline cell identifiers.
+typedef NS_ENUM(NSUInteger, RoomTimelineCellIdentifier) {
+
+ RoomTimelineCellIdentifierUnknown,
+
+ // - Text message
+ // -- Incoming
+ // --- Clear
+ RoomTimelineCellIdentifierIncomingTextMessage,
+ RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo,
+ RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle,
+ RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName,
+ RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName,
+ // --- Encrypted
+ RoomTimelineCellIdentifierIncomingTextMessageEncrypted,
+ RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo,
+ RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle,
+ RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName,
+ RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName,
+ // -- Outgoing
+ // --- Clear
+ RoomTimelineCellIdentifierOutgoingTextMessage,
+ RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo,
+ RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle,
+ RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName,
+ RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName,
+ // --- Encrypted
+ RoomTimelineCellIdentifierOutgoingTextMessageEncrypted,
+ RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo,
+ RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle,
+ RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName,
+ RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName,
+
+ // - Attachment
+ // -- Incoming
+ // --- Clear
+ RoomTimelineCellIdentifierIncomingAttachment,
+ RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo,
+ RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle,
+ // --- Encrypted
+ RoomTimelineCellIdentifierIncomingAttachmentEncrypted,
+ RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo,
+ RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle,
+ // -- Outgoing
+ // --- Clear
+ RoomTimelineCellIdentifierOutgoingAttachment,
+ RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo,
+ RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle,
+ // --- Encrypted
+ RoomTimelineCellIdentifierOutgoingAttachmentEncrypted,
+ RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo,
+ RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle,
+
+ // - Room membership
+ RoomTimelineCellIdentifierMembership,
+ RoomTimelineCellIdentifierMembershipWithPaginationTitle,
+ RoomTimelineCellIdentifierMembershipCollapsed,
+ RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle,
+ RoomTimelineCellIdentifierMembershipExpanded,
+ RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle,
+
+ // - Key verification
+ RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval,
+ RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle,
+ RoomTimelineCellIdentifierKeyVerificationRequestStatus,
+ RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle,
+ RoomTimelineCellIdentifierKeyVerificationConclusion,
+ RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle,
+
+ // - Room creation
+ RoomTimelineCellIdentifierRoomCreationCollapsed,
+ RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle,
+
+ // - Call
+ RoomTimelineCellIdentifierDirectCallStatus,
+ RoomTimelineCellIdentifierGroupCallStatus,
+
+ // - Voice message
+ RoomTimelineCellIdentifierVoiceMessage,
+ RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo,
+ RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle,
+
+ // - Poll
+ RoomTimelineCellIdentifierPoll,
+ RoomTimelineCellIdentifierPollWithoutSenderInfo,
+ RoomTimelineCellIdentifierPollWithPaginationTitle,
+
+ // - Location sharing
+ RoomTimelineCellIdentifierLocation,
+ RoomTimelineCellIdentifierLocationWithoutSenderInfo,
+ RoomTimelineCellIdentifierLocationWithPaginationTitle,
+
+ // - Others
+ RoomTimelineCellIdentifierEmpty,
+ RoomTimelineCellIdentifierSelectedSticker,
+ RoomTimelineCellIdentifierRoomPredecessor,
+ RoomTimelineCellIdentifierRoomCreationIntro,
+ RoomTimelineCellIdentifierTyping
+};
diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomTimelineConfiguration.swift b/Riot/Modules/Room/Views/BubbleCells/RoomTimelineConfiguration.swift
new file mode 100644
index 000000000..1cd3b60d7
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/RoomTimelineConfiguration.swift
@@ -0,0 +1,96 @@
+//
+// Copyright 2021 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
+
+/// RoomTimelineConfiguration enables to manage room timeline appearance configuration
+@objcMembers
+class RoomTimelineConfiguration: NSObject {
+
+ // MARK: - Constants
+
+ static let shared = RoomTimelineConfiguration()
+
+ // MARK: - Properties
+
+ private(set) var currentStyle: RoomTimelineStyle
+
+ // MARK: - Setup
+
+ init(style: RoomTimelineStyle) {
+ self.currentStyle = style
+
+ super.init()
+
+ self.registerThemeDidChange()
+ }
+
+ convenience init(styleIdentifier: RoomTimelineStyleIdentifier) {
+
+ let style = type(of: self).style(for: styleIdentifier)
+ self.init(style: style)
+ }
+
+ convenience override init() {
+ let styleIdentifier = RiotSettings.shared.roomTimelineStyleIdentifier
+ self.init(styleIdentifier: styleIdentifier)
+ }
+
+ // MARK: - Public
+
+ func updateStyle(_ roomTimelineStyle: RoomTimelineStyle) {
+ self.currentStyle = roomTimelineStyle
+ }
+
+ func updateStyle(withIdentifier identifier: RoomTimelineStyleIdentifier) {
+
+ let style = type(of: self).style(for: identifier)
+
+ self.updateStyle(style)
+ }
+
+ // MARK: - Private
+
+ private func registerThemeDidChange() {
+ NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange(notification:)), name: .themeServiceDidChangeTheme, object: nil)
+
+ }
+
+ @objc private func themeDidChange(notification: Notification) {
+
+ guard let themeService = notification.object as? ThemeService else {
+ return
+ }
+
+ self.currentStyle.update(theme: themeService.theme)
+ }
+
+ private class func style(for identifier: RoomTimelineStyleIdentifier) -> RoomTimelineStyle {
+
+ let roomTimelineStyle: RoomTimelineStyle
+
+ let theme = ThemeService.shared().theme
+
+ switch identifier {
+ case .plain:
+ roomTimelineStyle = PlainRoomTimelineStyle(theme: theme)
+ case .bubble:
+ roomTimelineStyle = BubbleRoomTimelineStyle(theme: theme)
+ }
+
+ return roomTimelineStyle
+ }
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Sticker/RoomSelectedStickerBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/Sticker/RoomSelectedStickerBubbleCell.h
index 689b39403..67526a1dd 100644
--- a/Riot/Modules/Room/Views/BubbleCells/Sticker/RoomSelectedStickerBubbleCell.h
+++ b/Riot/Modules/Room/Views/BubbleCells/Sticker/RoomSelectedStickerBubbleCell.h
@@ -27,7 +27,6 @@
@property (weak, nonatomic) IBOutlet UILabel *descriptionLabel;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *userNameLabelTopConstraint;
-@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewLeadingConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *descriptionContainerViewBottomConstraint;
@end
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomCellLayoutUpdater.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomCellLayoutUpdater.swift
new file mode 100644
index 000000000..42c0f3aac
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomCellLayoutUpdater.swift
@@ -0,0 +1,345 @@
+//
+// Copyright 2021 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
+
+@objcMembers
+class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
+
+ // MARK: - Properties
+
+ private var theme: Theme
+
+ private var incomingColor: UIColor {
+ return self.theme.colors.system
+ }
+
+ private var outgoingColor: UIColor {
+ return self.theme.colors.accent.withAlphaComponent(0.10)
+ }
+
+ // MARK: - Setup
+
+ init(theme: Theme) {
+ self.theme = theme
+ }
+
+ // MARK: - Public
+
+ func updateLayoutIfNeeded(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
+
+ if cellData.isSenderCurrentUser {
+ self.updateLayout(forOutgoingTextMessageCell: cell, andCellData: cellData)
+ } else {
+ self.updateLayout(forIncomingTextMessageCell: cell, andCellData: cellData)
+ }
+ }
+
+ func updateLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
+
+ if let messageBubbleBackgroundView = cell.messageBubbleBackgroundView {
+
+ if self.canUseBubbleBackground(forCell: cell, withCellData: cellData) {
+
+ messageBubbleBackgroundView.isHidden = false
+
+ self.updateMessageBubbleBackgroundView(messageBubbleBackgroundView, withCell: cell, andCellData: cellData)
+ } else {
+ messageBubbleBackgroundView.isHidden = true
+ }
+ }
+ }
+
+ func updateLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
+
+ if let messageBubbleBackgroundView = cell.messageBubbleBackgroundView {
+
+ if self.canUseBubbleBackground(forCell: cell, withCellData: cellData) {
+
+ messageBubbleBackgroundView.isHidden = false
+
+ self.updateMessageBubbleBackgroundView(messageBubbleBackgroundView, withCell: cell, andCellData: cellData)
+ } else {
+ messageBubbleBackgroundView.isHidden = true
+ }
+ }
+ }
+
+ func setupLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell) {
+
+ self.setupIncomingMessageTextViewMargins(for: cell)
+
+ self.addBubbleBackgroundViewToCell(cell, backgroundColor: self.incomingColor)
+
+ cell.setNeedsUpdateConstraints()
+ }
+
+ func setupLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell) {
+
+ self.setupOutgoingMessageTextViewMargins(for: cell)
+
+ // Hide avatar view
+ cell.pictureView?.isHidden = true
+
+ self.addBubbleBackgroundViewToCell(cell, backgroundColor: self.outgoingColor)
+
+ cell.setNeedsUpdateConstraints()
+ }
+
+ func setupLayout(forOutgoingFileAttachmentCell cell: MXKRoomBubbleTableViewCell) {
+
+ // Hide avatar view
+ cell.pictureView?.isHidden = true
+
+ self.setupOutgoingFileAttachViewMargins(for: cell)
+ }
+
+ // MARK: Themable
+
+ func update(theme: Theme) {
+ self.theme = theme
+ }
+
+ // MARK: - Private
+
+ // MARK: Bubble background view
+
+ private func createBubbleBackgroundView(with backgroundColor: UIColor) -> RoomMessageBubbleBackgroundView {
+
+ let bubbleBackgroundView = RoomMessageBubbleBackgroundView()
+ bubbleBackgroundView.backgroundColor = backgroundColor
+
+ return bubbleBackgroundView
+ }
+
+ private func addBubbleBackgroundViewToCell(_ bubbleCell: MXKRoomBubbleTableViewCell, backgroundColor: UIColor) {
+
+ guard let messageTextView = bubbleCell.messageTextView else {
+ return
+ }
+
+ let topMargin: CGFloat = 0.0
+ let leftMargin: CGFloat = 5.0
+ let rightMargin: CGFloat = 45.0 // Add extra space for timestamp
+
+ let bubbleBackgroundView = self.createBubbleBackgroundView(with: backgroundColor)
+
+ bubbleCell.contentView.insertSubview(bubbleBackgroundView, at: 0)
+
+ let topAnchor = messageTextView.topAnchor
+ let leadingAnchor = messageTextView.leadingAnchor
+ let trailingAnchor = messageTextView.trailingAnchor
+
+ bubbleBackgroundView.updateHeight(messageTextView.frame.height)
+
+ NSLayoutConstraint.activate([
+ bubbleBackgroundView.topAnchor.constraint(equalTo: topAnchor, constant: topMargin),
+ bubbleBackgroundView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: -leftMargin),
+ bubbleBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: rightMargin)
+ ])
+ }
+
+ private func canUseBubbleBackground(forCell cell: MXKRoomBubbleTableViewCell, withCellData cellData: MXKRoomBubbleCellData) -> Bool {
+
+ guard let firstComponent = cellData.getFirstBubbleComponentWithDisplay(), let firstEvent = firstComponent.event else {
+ return false
+ }
+
+ switch firstEvent.eventType {
+ case .roomMessage:
+ if let messageTypeString = firstEvent.content["msgtype"] as? String {
+
+ let messageType = MXMessageType(identifier: messageTypeString)
+
+ switch messageType {
+ case .text, .emote, .file:
+ return true
+ default:
+ break
+ }
+ }
+ default:
+ break
+ }
+
+ return false
+ }
+
+ private func getTextMessageHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
+
+ guard let roomBubbleCellData = cellData as? RoomBubbleCellData,
+ let lastBubbleComponent = cellData.getLastBubbleComponentWithDisplay(),
+ let firstComponent = roomBubbleCellData.getFirstBubbleComponentWithDisplay() else {
+ return nil
+ }
+
+ let bubbleHeight: CGFloat
+
+ let lastEventId = lastBubbleComponent.event.eventId
+ let lastMessageBottomPosition = cell.bottomPosition(ofEvent: lastEventId)
+
+ let firstEventId = firstComponent.event.eventId
+ let firstMessageTopPosition = cell.topPosition(ofEvent: firstEventId)
+
+ let additionalContentHeight = roomBubbleCellData.additionalContentHeight
+
+ bubbleHeight = lastMessageBottomPosition - firstMessageTopPosition - additionalContentHeight
+
+ guard bubbleHeight >= 0 else {
+ return nil
+ }
+
+ return bubbleHeight
+ }
+
+ // TODO: Improve text message height calculation
+ // This method is closer to final result but lack of stability because of extra vertical space not handled here.
+// private func getTextMessageHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
+//
+// guard let roomBubbleCellData = cellData as? RoomBubbleCellData,
+// let firstComponent = roomBubbleCellData.getFirstBubbleComponentWithDisplay() else {
+// return nil
+// }
+//
+// let bubbleHeight: CGFloat
+//
+// let componentIndex = cellData.bubbleComponentIndex(forEventId: firstComponent.event.eventId)
+//
+// let componentFrame = cell.componentFrameInContentView(for: componentIndex)
+//
+// bubbleHeight = componentFrame.height
+//
+// guard bubbleHeight >= 0 else {
+// return nil
+// }
+//
+// return bubbleHeight
+// }
+
+ private func getMessageBubbleBackgroundHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
+
+ var finalBubbleHeight: CGFloat?
+ let extraMargin: CGFloat = 4.0
+
+ if let bubbleHeight = self.getTextMessageHeight(for: cell, andCellData: cellData) {
+ finalBubbleHeight = bubbleHeight + extraMargin
+
+ } else if let messageTextViewHeight = cell.messageTextView?.frame.height {
+
+ finalBubbleHeight = messageTextViewHeight + extraMargin
+ }
+
+ return finalBubbleHeight
+ }
+
+ @discardableResult
+ private func updateMessageBubbleBackgroundView(_ roomMessageBubbleBackgroundView: RoomMessageBubbleBackgroundView, withCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> Bool {
+
+ if let bubbleHeight = self.getMessageBubbleBackgroundHeight(for: cell, andCellData: cellData) {
+ return roomMessageBubbleBackgroundView.updateHeight(bubbleHeight)
+ } else {
+ return false
+ }
+ }
+
+ private func getIncomingMessageTextViewInsets(from bubbleCell: MXKRoomBubbleTableViewCell) -> UIEdgeInsets {
+
+ let messageViewMarginTop: CGFloat
+ let messageViewMarginBottom: CGFloat = -2.0
+ let messageViewMarginLeft: CGFloat = 3.0
+ let messageViewMarginRight: CGFloat = 80
+
+ if bubbleCell.userNameLabel != nil {
+ messageViewMarginTop = 10.0
+ } else {
+ messageViewMarginTop = 0.0
+ }
+
+ let messageViewInsets = UIEdgeInsets(top: messageViewMarginTop, left: messageViewMarginLeft, bottom: messageViewMarginBottom, right: messageViewMarginRight)
+
+ return messageViewInsets
+ }
+
+ // MARK: Text message
+
+ private func setupIncomingMessageTextViewMargins(for cell: MXKRoomBubbleTableViewCell) {
+
+ guard cell.messageTextView != nil else {
+ return
+ }
+
+ let messageViewInsets = self.getIncomingMessageTextViewInsets(from: cell)
+
+ cell.msgTextViewBottomConstraint.constant += messageViewInsets.bottom
+ cell.msgTextViewTopConstraint.constant += messageViewInsets.top
+ cell.msgTextViewLeadingConstraint.constant += messageViewInsets.left
+ cell.msgTextViewTrailingConstraint.constant += messageViewInsets.right
+ }
+
+ private func setupOutgoingMessageTextViewMargins(for cell: MXKRoomBubbleTableViewCell) {
+
+ guard let messageTextView = cell.messageTextView else {
+ return
+ }
+
+ let contentView = cell.contentView
+
+ let leftMargin: CGFloat = 80.0
+ let rightMargin: CGFloat = 78.0
+ let bottomMargin: CGFloat = -2.0
+
+ cell.msgTextViewLeadingConstraint.isActive = false
+ cell.msgTextViewTrailingConstraint.isActive = false
+
+ let leftConstraint = messageTextView.leadingAnchor.constraint(greaterThanOrEqualTo: contentView.leadingAnchor, constant: leftMargin)
+
+ let rightConstraint = messageTextView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -rightMargin)
+
+ NSLayoutConstraint.activate([
+ leftConstraint,
+ rightConstraint
+ ])
+
+ cell.msgTextViewLeadingConstraint = leftConstraint
+ cell.msgTextViewTrailingConstraint = rightConstraint
+
+ cell.msgTextViewBottomConstraint.constant += bottomMargin
+ }
+
+ private func setupOutgoingFileAttachViewMargins(for cell: MXKRoomBubbleTableViewCell) {
+
+ guard let attachmentView = cell.attachmentView else {
+ return
+ }
+
+ let contentView = cell.contentView
+
+ // TODO: Use constants
+ // Same as URL preview
+ let rightMargin: CGFloat = 34.0
+
+ if let attachViewLeadingConstraint = cell.attachViewLeadingConstraint {
+ attachViewLeadingConstraint.isActive = false
+ cell.attachViewLeadingConstraint = nil
+ }
+
+ let rightConstraint = attachmentView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -rightMargin)
+
+ NSLayoutConstraint.activate([
+ rightConstraint
+ ])
+ }
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellDecorator.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellDecorator.swift
new file mode 100644
index 000000000..2ea6ab381
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellDecorator.swift
@@ -0,0 +1,230 @@
+//
+// Copyright 2021 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
+
+class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
+
+ override func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
+
+ guard self.canShowTimestamp(forCellData: cellData) else {
+ return
+ }
+
+ self.addTimestampLabel(toCell: cell, cellData: cellData)
+ }
+
+ override func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
+
+ // If cell contains a bubble background, add the timestamp inside of it
+ if let bubbleBackgroundView = cell.messageBubbleBackgroundView, bubbleBackgroundView.isHidden == false {
+
+ let componentIndex = cellData.mostRecentComponentIndex
+
+ guard let bubbleComponents = cellData.bubbleComponents,
+ componentIndex < bubbleComponents.count else {
+ return
+ }
+
+ let component = bubbleComponents[componentIndex]
+
+ let timestampLabel = self.createTimestampLabel(cellData: cellData,
+ bubbleComponent: component,
+ viewTag: componentIndex)
+ timestampLabel.translatesAutoresizingMaskIntoConstraints = false
+
+ cell.addTemporarySubview(timestampLabel)
+
+ bubbleBackgroundView.addSubview(timestampLabel)
+
+ let rightMargin: CGFloat = 8.0
+ let bottomMargin: CGFloat = 4.0
+
+ let trailingConstraint = timestampLabel.trailingAnchor.constraint(equalTo: bubbleBackgroundView.trailingAnchor, constant: -rightMargin)
+
+ let bottomConstraint = timestampLabel.bottomAnchor.constraint(equalTo: bubbleBackgroundView.bottomAnchor, constant: -bottomMargin)
+
+ NSLayoutConstraint.activate([
+ trailingConstraint,
+ bottomConstraint
+ ])
+ } else {
+ super.addTimestampLabel(toCell: cell, cellData: cellData)
+ }
+ }
+
+ override func addReactionView(_ reactionsView: BubbleReactionsView,
+ toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData, contentViewPositionY: CGFloat, upperDecorationView: UIView?) {
+
+ cell.addTemporarySubview(reactionsView)
+
+ if let reactionsDisplayable = cell as? BubbleCellReactionsDisplayable {
+ reactionsDisplayable.addReactionsView(reactionsView)
+ return
+ }
+
+ reactionsView.translatesAutoresizingMaskIntoConstraints = false
+
+ let cellContentView = cell.contentView
+
+ cellContentView.addSubview(reactionsView)
+
+ // TODO: Use constants
+ let topMargin: CGFloat = 4.0
+ let leftMargin: CGFloat
+ let rightMargin: CGFloat
+
+ // Outgoing message
+ if cellData.isSenderCurrentUser {
+ reactionsView.alignment = .right
+
+ // TODO: Use constants
+ var outgointLeftMargin: CGFloat = 80.0
+
+ if cellData.containsBubbleComponentWithEncryptionBadge {
+ outgointLeftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
+ }
+
+ leftMargin = outgointLeftMargin
+
+ // TODO: Use constants
+ rightMargin = 33
+ } else {
+ // Incoming message
+
+ var incomingLeftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
+
+ if cellData.containsBubbleComponentWithEncryptionBadge {
+ incomingLeftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
+ }
+
+ leftMargin = incomingLeftMargin - 6.0
+
+ // TODO: Use constants
+ let messageViewMarginRight: CGFloat = 42.0
+
+ rightMargin = messageViewMarginRight
+ }
+
+ let leadingConstraint = reactionsView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
+
+ let trailingConstraint = reactionsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin)
+
+ let topConstraint: NSLayoutConstraint
+ if let upperDecorationView = upperDecorationView {
+ topConstraint = reactionsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
+ } else {
+ topConstraint = reactionsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
+ }
+
+ NSLayoutConstraint.activate([
+ leadingConstraint,
+ trailingConstraint,
+ topConstraint
+ ])
+ }
+
+ override func addURLPreviewView(_ urlPreviewView: URLPreviewView,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat) {
+
+ cell.addTemporarySubview(urlPreviewView)
+
+ let cellContentView = cell.contentView
+
+ urlPreviewView.translatesAutoresizingMaskIntoConstraints = false
+ urlPreviewView.availableWidth = cellData.maxTextViewWidth
+ cellContentView.addSubview(urlPreviewView)
+
+ let leadingOrTrailingConstraint: NSLayoutConstraint
+
+ // Outgoing message
+ if cellData.isSenderCurrentUser {
+
+ // TODO: Use constants
+ let rightMargin: CGFloat = 34.0
+
+ leadingOrTrailingConstraint = urlPreviewView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin)
+ } else {
+ // Incoming message
+
+ var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
+ if cellData.containsBubbleComponentWithEncryptionBadge {
+ leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
+ }
+
+ leftMargin-=5.0
+
+ leadingOrTrailingConstraint = urlPreviewView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
+ }
+
+ let topMargin = contentViewPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin
+
+ // Set the preview view's origin
+ NSLayoutConstraint.activate([
+ leadingOrTrailingConstraint,
+ urlPreviewView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: topMargin)
+ ])
+ }
+
+ // MARK: - Private
+
+ private func createTimestampLabel(cellData: MXKRoomBubbleCellData, bubbleComponent: MXKRoomBubbleComponent, viewTag: Int) -> UILabel {
+
+ let timeLabel = UILabel()
+
+ timeLabel.text = cellData.eventFormatter.timeString(from: bubbleComponent.date)
+ timeLabel.textAlignment = .right
+ timeLabel.textColor = ThemeService.shared().theme.textSecondaryColor
+ timeLabel.font = UIFont.systemFont(ofSize: 11, weight: .light)
+ timeLabel.adjustsFontSizeToFitWidth = true
+ timeLabel.tag = viewTag
+ timeLabel.accessibilityIdentifier = "timestampLabel"
+
+ return timeLabel
+ }
+
+ private func canShowTimestamp(forCellData cellData: MXKRoomBubbleCellData) -> Bool {
+
+ guard cellData.isCollapsableAndCollapsed == false else {
+ return false
+ }
+
+ guard let firstComponent = cellData.getFirstBubbleComponentWithDisplay(), let firstEvent = firstComponent.event else {
+ return false
+ }
+
+ switch firstEvent.eventType {
+ case .roomMessage:
+ if let messageTypeString = firstEvent.content["msgtype"] as? String {
+
+ let messageType = MXMessageType(identifier: messageTypeString)
+
+ switch messageType {
+ case .text, .emote, .file:
+ return true
+ default:
+ break
+ }
+ }
+ default:
+ break
+ }
+
+ return false
+ }
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellProvider.h b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellProvider.h
new file mode 100644
index 000000000..a389242cc
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellProvider.h
@@ -0,0 +1,25 @@
+//
+// Copyright 2021 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 "PlainRoomTimelineCellProvider.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface BubbleRoomTimelineCellProvider : PlainRoomTimelineCellProvider
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellProvider.m b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellProvider.m
new file mode 100644
index 000000000..f36d21fdf
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineCellProvider.m
@@ -0,0 +1,90 @@
+//
+// Copyright 2021 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 "BubbleRoomTimelineCellProvider.h"
+
+#pragma mark - Imports
+
+#pragma mark Text message
+
+// Outgoing
+
+// Clear
+#import "RoomOutgoingTextMsgBubbleCell.h"
+#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
+#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
+#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
+#import "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
+
+// Encrypted
+
+#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
+
+#pragma mark Attachment
+
+// Outgoing
+
+// Clear
+#import "RoomOutgoingAttachmentBubbleCell.h"
+#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
+// Encrypted
+#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
+#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
+
+@implementation BubbleRoomTimelineCellProvider
+
+- (NSDictionary*)outgoingTextMessageCellsMapping
+{
+ // Hide sender info and avatar for bubble outgoing messages
+ return @{
+ // Clear
+ @(RoomTimelineCellIdentifierOutgoingTextMessage) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName) : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ // Encrypted
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncrypted) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)outgoingAttachmentCellsMapping
+{
+ // Hide sender info and avatar for bubble outgoing file attachment
+ return @{
+ // Clear
+ @(RoomTimelineCellIdentifierOutgoingAttachment) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle) : RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ // Encrypted
+ @(RoomTimelineCellIdentifierOutgoingAttachmentEncrypted) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle) : RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class
+ };
+}
+
+@end
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineStyle.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineStyle.swift
new file mode 100644
index 000000000..137338e57
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/BubbleRoomTimelineStyle.swift
@@ -0,0 +1,76 @@
+//
+// Copyright 2021 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
+
+class BubbleRoomTimelineStyle: RoomTimelineStyle {
+
+ // MARK: - Properties
+
+ // MARK: Private
+
+ private var theme: Theme
+
+ // MARK: Public
+
+ let identifier: RoomTimelineStyleIdentifier
+
+ let cellLayoutUpdater: RoomCellLayoutUpdating?
+
+ let cellProvider: RoomTimelineCellProvider
+
+ let cellDecorator: RoomTimelineCellDecorator
+
+ // MARK: - Setup
+
+ init(theme: Theme) {
+ self.theme = theme
+ self.identifier = .bubble
+ self.cellLayoutUpdater = BubbleRoomCellLayoutUpdater(theme: theme)
+ self.cellProvider = BubbleRoomTimelineCellProvider()
+ self.cellDecorator = BubbleRoomTimelineCellDecorator()
+ }
+
+ // MARK: - Public
+
+ func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool {
+ return false
+ }
+
+ func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
+
+ // Check whether the selected event belongs to this bubble
+ let selectedComponentIndex = cellData.selectedComponentIndex
+ if selectedComponentIndex != NSNotFound {
+
+ cell.selectComponent(UInt(selectedComponentIndex),
+ showEditButton: false,
+ showTimestamp: false)
+
+ self.cellDecorator.addTimestampLabel(toCell: cell, cellData: cellData)
+ } else {
+ cell.blurred = true
+ }
+ }
+
+ // MARK: Themable
+
+ func update(theme: Theme) {
+ self.theme = theme
+ self.cellLayoutUpdater?.update(theme: theme)
+ }
+
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/MXKRoomBubbleTableViewCell+BubbleStyle.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/MXKRoomBubbleTableViewCell+BubbleStyle.swift
new file mode 100644
index 000000000..a0fd3f527
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/MXKRoomBubbleTableViewCell+BubbleStyle.swift
@@ -0,0 +1,30 @@
+//
+// Copyright 2021 New Vector Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+import Foundation
+
+extension MXKRoomBubbleTableViewCell {
+
+ // Enables to get existing bubble background view
+ // This used while there is no dedicated cell classes for bubble style
+ var messageBubbleBackgroundView: RoomMessageBubbleBackgroundView? {
+
+ let foundView = self.contentView.subviews.first { view in
+ return view is RoomMessageBubbleBackgroundView
+ }
+ return foundView as? RoomMessageBubbleBackgroundView
+ }
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/RoomMessageBubbleBackgroundView.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/RoomMessageBubbleBackgroundView.swift
new file mode 100644
index 000000000..1408b48c7
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Bubble/RoomMessageBubbleBackgroundView.swift
@@ -0,0 +1,74 @@
+//
+// Copyright 2021 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
+
+class RoomMessageBubbleBackgroundView: UIView {
+
+ // MARK: - Constant
+
+ private enum Constants {
+ static let cornerRadius: CGFloat = 12.0
+ }
+
+ // MARK: - Properties
+
+ private var heightConstraint: NSLayoutConstraint?
+
+ // MARK: - Setup
+
+ convenience init() {
+ self.init(frame: CGRect.zero)
+ }
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ self.commonInit()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ self.commonInit()
+ }
+
+ private func commonInit() {
+ self.translatesAutoresizingMaskIntoConstraints = false
+ self.layer.masksToBounds = true
+ self.layer.cornerRadius = Constants.cornerRadius
+ }
+
+ // MARK: - Public
+
+ @discardableResult
+ func updateHeight(_ height: CGFloat) -> Bool {
+ if let heightConstraint = self.heightConstraint {
+
+ guard heightConstraint.constant != height else {
+ return false
+ }
+
+ heightConstraint.constant = height
+
+ return true
+ } else {
+ let heightConstraint = self.heightAnchor.constraint(equalToConstant: height)
+ heightConstraint.isActive = true
+ self.heightConstraint = heightConstraint
+
+ return true
+ }
+ }
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellDecorator.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellDecorator.swift
new file mode 100644
index 000000000..749ccece5
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellDecorator.swift
@@ -0,0 +1,197 @@
+//
+// Copyright 2021 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
+
+@objcMembers
+class PlainRoomTimelineCellDecorator: RoomTimelineCellDecorator {
+
+ func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
+
+ guard cellData.containsLastMessage && cellData.isCollapsableAndCollapsed == false else {
+ return
+ }
+
+ // Display timestamp of the last message
+ self.addTimestampLabel(toCell: cell, cellData: cellData)
+ }
+
+ func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
+ cell.addTimestampLabel(forComponent: UInt(cellData.mostRecentComponentIndex))
+ }
+
+ func addURLPreviewView(_ urlPreviewView: URLPreviewView,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat) {
+ cell.addTemporarySubview(urlPreviewView)
+
+ let cellContentView = cell.contentView
+
+ urlPreviewView.translatesAutoresizingMaskIntoConstraints = false
+ urlPreviewView.availableWidth = cellData.maxTextViewWidth
+ cellContentView.addSubview(urlPreviewView)
+
+ var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
+ if cellData.containsBubbleComponentWithEncryptionBadge {
+ leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
+ }
+
+ let topMargin = contentViewPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin
+
+ // Set the preview view's origin
+ NSLayoutConstraint.activate([
+ urlPreviewView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin),
+ urlPreviewView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: topMargin)
+ ])
+ }
+
+ func addReactionView(_ reactionsView: BubbleReactionsView,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat,
+ upperDecorationView: UIView?) {
+
+ cell.addTemporarySubview(reactionsView)
+
+ if let reactionsDisplayable = cell as? BubbleCellReactionsDisplayable {
+ reactionsDisplayable.addReactionsView(reactionsView)
+ } else {
+ reactionsView.translatesAutoresizingMaskIntoConstraints = false
+
+ let cellContentView = cell.contentView
+
+ cellContentView.addSubview(reactionsView)
+
+ var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
+
+ if cellData.containsBubbleComponentWithEncryptionBadge {
+ leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
+ }
+
+ let rightMargin = RoomBubbleCellLayout.reactionsViewRightMargin
+ let topMargin = RoomBubbleCellLayout.reactionsViewTopMargin
+
+ // The top constraint may need to include the URL preview view
+ let topConstraint: NSLayoutConstraint
+ if let upperDecorationView = upperDecorationView {
+ topConstraint = reactionsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
+ } else {
+ topConstraint = reactionsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
+ }
+
+ NSLayoutConstraint.activate([
+ reactionsView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin),
+ reactionsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin),
+ topConstraint
+ ])
+ }
+ }
+
+ func addReadReceiptsView(_ readReceiptsView: MXKReceiptSendersContainer,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat,
+ upperDecorationView: UIView?) {
+
+ cell.addTemporarySubview(readReceiptsView)
+
+ if let readReceiptsDisplayable = cell as? BubbleCellReadReceiptsDisplayable {
+ readReceiptsDisplayable.addReadReceiptsView(readReceiptsView)
+ } else {
+
+ let cellContentView = cell.contentView
+
+ cellContentView.addSubview(readReceiptsView)
+
+ // Force receipts container size
+ let widthConstraint = readReceiptsView.widthAnchor.constraint(equalToConstant: RoomBubbleCellLayout.readReceiptsViewWidth)
+ let heightConstraint = readReceiptsView.heightAnchor.constraint(equalToConstant: RoomBubbleCellLayout.readReceiptsViewHeight)
+
+ // Force receipts container position
+ let trailingConstraint = readReceiptsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -RoomBubbleCellLayout.readReceiptsViewRightMargin)
+
+ let topMargin = RoomBubbleCellLayout.readReceiptsViewTopMargin
+
+ let topConstraint: NSLayoutConstraint
+ if let upperDecorationView = upperDecorationView {
+ topConstraint = readReceiptsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
+ } else {
+ topConstraint = readReceiptsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
+ }
+
+ NSLayoutConstraint.activate([
+ widthConstraint,
+ heightConstraint,
+ trailingConstraint,
+ topConstraint
+ ])
+ }
+ }
+
+ func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat,
+ upperDecorationView: UIView?) {
+
+ cell.addTemporarySubview(threadSummaryView)
+
+ if let threadSummaryDisplayable = cell as? BubbleCellThreadSummaryDisplayable {
+ threadSummaryDisplayable.addThreadSummaryView(threadSummaryView)
+ } else {
+ threadSummaryView.translatesAutoresizingMaskIntoConstraints = false
+
+ let cellContentView = cell.contentView
+
+ cellContentView.addSubview(threadSummaryView)
+
+ var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
+
+ if cellData.containsBubbleComponentWithEncryptionBadge {
+ leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
+ }
+
+ let rightMargin = RoomBubbleCellLayout.reactionsViewRightMargin
+ let topMargin = RoomBubbleCellLayout.threadSummaryViewTopMargin
+ let height = ThreadSummaryView.contentViewHeight(forThread: threadSummaryView.thread,
+ fitting: cellData.maxTextViewWidth)
+
+ // The top constraint may need to include the URL preview view
+ let topConstraint: NSLayoutConstraint
+ if let upperDecorationView = upperDecorationView {
+ topConstraint = threadSummaryView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor,
+ constant: topMargin)
+ } else {
+ topConstraint = threadSummaryView.topAnchor.constraint(equalTo: cellContentView.topAnchor,
+ constant: contentViewPositionY + topMargin)
+ }
+
+ NSLayoutConstraint.activate([
+ threadSummaryView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor,
+ constant: leftMargin),
+ threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: cellContentView.trailingAnchor,
+ constant: -rightMargin),
+ threadSummaryView.heightAnchor.constraint(equalToConstant: height),
+ topConstraint
+ ])
+ }
+ }
+
+ func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell, withFailedEventIds failedEventIds: Set) {
+ cell.updateTickView(withFailedEventIds: failedEventIds)
+ }
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.h b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.h
new file mode 100644
index 000000000..12b1876ee
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.h
@@ -0,0 +1,29 @@
+//
+// Copyright 2021 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 "RoomTimelineCellProvider.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface PlainRoomTimelineCellProvider: NSObject
+
+- (NSDictionary*)outgoingTextMessageCellsMapping;
+
+- (NSDictionary*)outgoingAttachmentCellsMapping;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m
new file mode 100644
index 000000000..e36abb851
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineCellProvider.m
@@ -0,0 +1,453 @@
+//
+// Copyright 2021 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 "PlainRoomTimelineCellProvider.h"
+
+#import "MXKRoomBubbleTableViewCell+Riot.h"
+
+#import "RoomEmptyBubbleCell.h"
+
+#import "RoomIncomingTextMsgBubbleCell.h"
+#import "RoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
+#import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h"
+#import "RoomIncomingTextMsgWithoutSenderNameBubbleCell.h"
+#import "RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
+#import "RoomIncomingAttachmentBubbleCell.h"
+#import "RoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
+#import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h"
+
+#import "RoomIncomingEncryptedTextMsgBubbleCell.h"
+#import "RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
+#import "RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
+#import "RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
+#import "RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
+#import "RoomIncomingEncryptedAttachmentBubbleCell.h"
+#import "RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
+#import "RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
+
+#import "RoomOutgoingTextMsgBubbleCell.h"
+#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
+#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
+#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
+#import "RoomOutgoingAttachmentBubbleCell.h"
+#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
+#import "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
+
+#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
+#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
+#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
+#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
+#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
+
+#import "RoomMembershipBubbleCell.h"
+#import "RoomMembershipWithPaginationTitleBubbleCell.h"
+#import "RoomMembershipCollapsedBubbleCell.h"
+#import "RoomMembershipCollapsedWithPaginationTitleBubbleCell.h"
+#import "RoomMembershipExpandedBubbleCell.h"
+#import "RoomMembershipExpandedWithPaginationTitleBubbleCell.h"
+#import "RoomCreationWithPaginationCollapsedBubbleCell.h"
+#import "RoomCreationCollapsedBubbleCell.h"
+
+#import "RoomSelectedStickerBubbleCell.h"
+#import "RoomPredecessorBubbleCell.h"
+
+#import "GeneratedInterface-Swift.h"
+
+@interface PlainRoomTimelineCellProvider()
+
+@property (nonatomic, strong) NSDictionary* cellClasses;
+
+@end
+
+@implementation PlainRoomTimelineCellProvider
+
+#pragma mark - Public
+
+- (void)registerCellsForTableView:(UITableView*)tableView
+{
+ // Text message
+
+ [self registerIncomingTextMessageCellsForTableView:tableView];
+
+ [self registerOutgoingTextMessageCellsForTableView:tableView];
+
+ // Attachment cells
+
+ [self registerIncomingAttachmentCellsForTableView:tableView];
+
+ [self registerOutgoingAttachmentCellsForTableView:tableView];
+
+ // Other cells
+
+ [self registerMembershipCellsForTableView:tableView];
+
+ [self registerKeyVerificationCellsForTableView:tableView];
+
+ [self registerRoomCreationCellsForTableView:tableView];
+
+ [self registerCallCellsForTableView:tableView];
+
+ [self registerVoiceMessageCellsForTableView:tableView];
+
+ [self registerPollCellsForTableView:tableView];
+
+ [self registerLocationCellsForTableView:tableView];
+
+ [tableView registerClass:RoomEmptyBubbleCell.class forCellReuseIdentifier:RoomEmptyBubbleCell.defaultReuseIdentifier];
+
+ [tableView registerClass:RoomSelectedStickerBubbleCell.class forCellReuseIdentifier:RoomSelectedStickerBubbleCell.defaultReuseIdentifier];
+
+ [tableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier];
+
+ [tableView registerClass:RoomCreationIntroCell.class forCellReuseIdentifier:RoomCreationIntroCell.defaultReuseIdentifier];
+
+ [tableView registerNib:RoomTypingBubbleCell.nib forCellReuseIdentifier:RoomTypingBubbleCell.defaultReuseIdentifier];
+}
+
+- (Class)cellViewClassForCellIdentifier:(RoomTimelineCellIdentifier)identifier
+{
+ if (self.cellClasses == nil)
+ {
+ self.cellClasses = [self buildCellClasses];
+ }
+
+ Class cellViewClass = self.cellClasses[@(identifier)];
+
+
+ return cellViewClass;
+}
+
+#pragma mark - Private
+
+#pragma mark Cell registration
+
+- (void)registerIncomingTextMessageCellsForTableView:(UITableView*)tableView
+{
+ // Clear
+
+ [tableView registerClass:RoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+
+ // Encrypted
+
+ [tableView registerClass:RoomIncomingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerOutgoingTextMessageCellsForTableView:(UITableView*)tableView
+{
+ // Clear
+
+ [tableView registerClass:RoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+
+ // Encrypted
+
+ [tableView registerClass:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerIncomingAttachmentCellsForTableView:(UITableView*)tableView
+{
+ // Clear
+
+ [tableView registerClass:RoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+
+ // Encrypted
+
+ [tableView registerClass:RoomIncomingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerOutgoingAttachmentCellsForTableView:(UITableView*)tableView
+{
+ // Clear
+
+ [tableView registerClass:RoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
+
+ // Encrypted
+
+ [tableView registerClass:RoomOutgoingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerMembershipCellsForTableView:(UITableView*)tableView
+{
+ [tableView registerClass:RoomMembershipBubbleCell.class forCellReuseIdentifier:RoomMembershipBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomMembershipWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomMembershipCollapsedBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomMembershipCollapsedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomMembershipExpandedBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomMembershipExpandedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerKeyVerificationCellsForTableView:(UITableView*)tableView
+{
+ [tableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:KeyVerificationConclusionWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerRoomCreationCellsForTableView:(UITableView*)tableView
+{
+ [tableView registerClass:RoomCreationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationCollapsedBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomCreationWithPaginationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationWithPaginationCollapsedBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerCallCellsForTableView:(UITableView*)tableView
+{
+ [tableView registerClass:RoomDirectCallStatusBubbleCell.class forCellReuseIdentifier:RoomDirectCallStatusBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:RoomGroupCallStatusBubbleCell.class forCellReuseIdentifier:RoomGroupCallStatusBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerVoiceMessageCellsForTableView:(UITableView*)tableView
+{
+ [tableView registerClass:VoiceMessageBubbleCell.class forCellReuseIdentifier:VoiceMessageBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:VoiceMessageWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:VoiceMessageWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerPollCellsForTableView:(UITableView*)tableView
+{
+ [tableView registerClass:PollBubbleCell.class forCellReuseIdentifier:PollBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:PollWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:PollWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:PollWithPaginationTitleBubbleCell.class forCellReuseIdentifier:PollWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+}
+
+- (void)registerLocationCellsForTableView:(UITableView*)tableView
+{
+ [tableView registerClass:LocationBubbleCell.class forCellReuseIdentifier:LocationBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:LocationWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
+ [tableView registerClass:LocationWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationWithPaginationTitleBubbleCell.defaultReuseIdentifier];
+}
+
+#pragma mark Cell class association
+
+- (NSDictionary*)buildCellClasses
+{
+ NSMutableDictionary* cellClasses = [NSMutableDictionary dictionary];
+
+ // Text message
+
+ NSDictionary *incomingTextMessageCellsMapping = [self incomingTextMessageCellsMapping];
+ [cellClasses addEntriesFromDictionary:incomingTextMessageCellsMapping];
+
+ NSDictionary *outgoingTextMessageCellsMapping = [self outgoingTextMessageCellsMapping];
+ [cellClasses addEntriesFromDictionary:outgoingTextMessageCellsMapping];
+
+ // Attachment
+
+ NSDictionary *incomingAttachmentCellsMapping = [self incomingAttachmentCellsMapping];
+ [cellClasses addEntriesFromDictionary:incomingAttachmentCellsMapping];
+
+ NSDictionary *outgoingAttachmentCellsMapping = [self outgoingAttachmentCellsMapping];
+ [cellClasses addEntriesFromDictionary:outgoingAttachmentCellsMapping];
+
+ // Other cells
+
+ NSDictionary *roomMembershipCellsMapping = [self membershipCellsMapping];
+ [cellClasses addEntriesFromDictionary:roomMembershipCellsMapping];
+
+ NSDictionary *keyVerificationCellsMapping = [self keyVerificationCellsMapping];
+ [cellClasses addEntriesFromDictionary:keyVerificationCellsMapping];
+
+ NSDictionary *roomCreationCellsMapping = [self roomCreationCellsMapping];
+ [cellClasses addEntriesFromDictionary:roomCreationCellsMapping];
+
+ NSDictionary *callCellsMapping = [self callCellsMapping];
+ [cellClasses addEntriesFromDictionary:callCellsMapping];
+
+ NSDictionary *voiceMessageCellsMapping = [self voiceMessageCellsMapping];
+ [cellClasses addEntriesFromDictionary:voiceMessageCellsMapping];
+
+ NSDictionary *pollCellsMapping = [self pollCellsMapping];
+ [cellClasses addEntriesFromDictionary:pollCellsMapping];
+
+ NSDictionary *locationCellsMapping = [self locationCellsMapping];
+ [cellClasses addEntriesFromDictionary:locationCellsMapping];
+
+ NSDictionary *othersCells = @{
+ @(RoomTimelineCellIdentifierEmpty) : RoomEmptyBubbleCell.class,
+ @(RoomTimelineCellIdentifierSelectedSticker) : RoomSelectedStickerBubbleCell.class,
+ @(RoomTimelineCellIdentifierRoomPredecessor) : RoomPredecessorBubbleCell.class,
+ @(RoomTimelineCellIdentifierRoomCreationIntro) : RoomCreationIntroCell.class,
+ @(RoomTimelineCellIdentifierTyping) : RoomTypingBubbleCell.class,
+ };
+ [cellClasses addEntriesFromDictionary:othersCells];
+
+ return [cellClasses copy];
+}
+
+- (NSDictionary*)incomingTextMessageCellsMapping
+{
+ return @{
+ // Clear
+ @(RoomTimelineCellIdentifierIncomingTextMessage) : RoomIncomingTextMsgBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo) : RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle) : RoomIncomingTextMsgWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName) : RoomIncomingTextMsgWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName) : RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ // Encrypted
+ @(RoomTimelineCellIdentifierIncomingTextMessageEncrypted) : RoomIncomingEncryptedTextMsgBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo) : RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle) : RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName) : RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)outgoingTextMessageCellsMapping
+{
+ return @{
+ // Clear
+ @(RoomTimelineCellIdentifierOutgoingTextMessage) : RoomOutgoingTextMsgBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle) : RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName) : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ // Encrypted
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncrypted) : RoomOutgoingEncryptedTextMsgBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle) : RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)incomingAttachmentCellsMapping
+{
+ return @{
+ // Clear
+ @(RoomTimelineCellIdentifierIncomingAttachment) : RoomIncomingAttachmentBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo) : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle) : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class,
+ // Encrypted
+ @(RoomTimelineCellIdentifierIncomingAttachmentEncrypted) : RoomIncomingEncryptedAttachmentBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo) : RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle) : RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class
+ };
+}
+
+- (NSDictionary*)outgoingAttachmentCellsMapping
+{
+ return @{
+ // Clear
+ @(RoomTimelineCellIdentifierOutgoingAttachment) : RoomOutgoingAttachmentBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle) : RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class,
+ // Encrypted
+ @(RoomTimelineCellIdentifierOutgoingAttachmentEncrypted) : RoomOutgoingEncryptedAttachmentBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle) : RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class
+ };
+}
+
+- (NSDictionary*)membershipCellsMapping
+{
+ return @{
+ @(RoomTimelineCellIdentifierMembership) : RoomMembershipBubbleCell.class,
+ @(RoomTimelineCellIdentifierMembershipWithPaginationTitle) : RoomMembershipWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierMembershipCollapsed) : RoomMembershipCollapsedBubbleCell.class,
+ @(RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle) : RoomMembershipCollapsedWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierMembershipExpanded) : RoomMembershipExpandedBubbleCell.class,
+ @(RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle) : RoomMembershipExpandedWithPaginationTitleBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)keyVerificationCellsMapping
+{
+ return @{
+ @(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval) : KeyVerificationIncomingRequestApprovalBubbleCell.class,
+ @(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle) : KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierKeyVerificationRequestStatus) : KeyVerificationRequestStatusBubbleCell.class,
+ @(RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle) : KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class,
+ @(RoomTimelineCellIdentifierKeyVerificationConclusion) : KeyVerificationConclusionBubbleCell.class,
+ @(RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle) : KeyVerificationConclusionWithPaginationTitleBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)roomCreationCellsMapping
+{
+ return @{
+ @(RoomTimelineCellIdentifierRoomCreationCollapsed) : RoomCreationCollapsedBubbleCell.class,
+ @(RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle) : RoomCreationWithPaginationCollapsedBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)callCellsMapping
+{
+ return @{
+ @(RoomTimelineCellIdentifierDirectCallStatus) : RoomDirectCallStatusBubbleCell.class,
+ @(RoomTimelineCellIdentifierGroupCallStatus) : RoomGroupCallStatusBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)voiceMessageCellsMapping
+{
+ return @{
+ @(RoomTimelineCellIdentifierVoiceMessage) : VoiceMessageBubbleCell.class,
+ @(RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo) : VoiceMessageWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle) : VoiceMessageWithPaginationTitleBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)pollCellsMapping
+{
+ return @{
+ @(RoomTimelineCellIdentifierPoll) : PollBubbleCell.class,
+ @(RoomTimelineCellIdentifierPollWithoutSenderInfo) : PollWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierPollWithPaginationTitle) : PollWithPaginationTitleBubbleCell.class,
+ };
+}
+
+- (NSDictionary*)locationCellsMapping
+{
+ return @{
+ @(RoomTimelineCellIdentifierLocation) : LocationBubbleCell.class,
+ @(RoomTimelineCellIdentifierLocationWithoutSenderInfo) : LocationWithoutSenderInfoBubbleCell.class,
+ @(RoomTimelineCellIdentifierLocationWithPaginationTitle) : LocationWithPaginationTitleBubbleCell.class
+ };
+}
+
+
+@end
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineStyle.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineStyle.swift
new file mode 100644
index 000000000..f3fba9c4e
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/Plain/PlainRoomTimelineStyle.swift
@@ -0,0 +1,74 @@
+//
+// Copyright 2021 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
+
+class PlainRoomTimelineStyle: RoomTimelineStyle {
+
+ // MARK: - Properties
+
+ // MARK: Private
+
+ private var theme: Theme
+
+ // MARK: Public
+
+ let identifier: RoomTimelineStyleIdentifier
+
+ let cellLayoutUpdater: RoomCellLayoutUpdating?
+
+ let cellProvider: RoomTimelineCellProvider
+
+ let cellDecorator: RoomTimelineCellDecorator
+
+ // MARK: - Setup
+
+ init(theme: Theme) {
+ self.theme = theme
+ self.identifier = .plain
+ self.cellLayoutUpdater = nil
+ self.cellProvider = PlainRoomTimelineCellProvider()
+ self.cellDecorator = PlainRoomTimelineCellDecorator()
+ }
+
+ // MARK: - Methods
+
+ func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool {
+ return true
+ }
+
+ func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
+
+ // Check whether the selected event belongs to this bubble
+ let selectedComponentIndex = cellData.selectedComponentIndex
+ if selectedComponentIndex != NSNotFound {
+
+ let showTimestamp = cellData.showTimestampForSelectedComponent
+
+ cell.selectComponent(UInt(selectedComponentIndex),
+ showEditButton: false,
+ showTimestamp: showTimestamp)
+ } else {
+ cell.blurred = true
+ }
+ }
+
+ // MARK: Themable
+
+ func update(theme: Theme) {
+ self.theme = theme
+ }
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/RoomCellLayoutUpdating.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomCellLayoutUpdating.swift
new file mode 100644
index 000000000..aaacccb6f
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomCellLayoutUpdating.swift
@@ -0,0 +1,30 @@
+//
+// Copyright 2021 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
+
+/// Enables to setup or update a room timeline cell view
+@objc
+protocol RoomCellLayoutUpdating: Themable {
+
+ func updateLayoutIfNeeded(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData)
+
+ func setupLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell)
+
+ func setupLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell)
+
+ func setupLayout(forOutgoingFileAttachmentCell cell: MXKRoomBubbleTableViewCell)
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineCellDecorator.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineCellDecorator.swift
new file mode 100644
index 000000000..ec60bcbf4
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineCellDecorator.swift
@@ -0,0 +1,53 @@
+//
+// Copyright 2021 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
+
+/// RoomTimelineCellDecorator enables to add decoration on a cell (reactions, read receipts, timestamp, URL preview).
+@objc
+protocol RoomTimelineCellDecorator {
+
+ func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData)
+
+ func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData)
+
+ func addURLPreviewView(_ urlPreviewView: URLPreviewView,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat)
+
+ func addReactionView(_ reactionsView: BubbleReactionsView,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat,
+ upperDecorationView: UIView?)
+
+ func addReadReceiptsView(_ readReceiptsView: MXKReceiptSendersContainer,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat,
+ upperDecorationView: UIView?)
+
+ func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView,
+ toCell cell: MXKRoomBubbleTableViewCell,
+ cellData: RoomBubbleCellData,
+ contentViewPositionY: CGFloat,
+ upperDecorationView: UIView?)
+
+ func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell,
+ withFailedEventIds failedEventIds: Set)
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineCellProvider.h b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineCellProvider.h
new file mode 100644
index 000000000..40037c3a2
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineCellProvider.h
@@ -0,0 +1,36 @@
+//
+// Copyright 2021 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
+
+#import "RoomTimelineCellIdentifier.h"
+#import "MXKCellRendering.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Enables to register and provide room timeline cells
+@protocol RoomTimelineCellProvider
+
+/// Register timeline cells for the given table view
+- (void)registerCellsForTableView:(UITableView*)tableView;
+
+/// Get timeline cell class from cell identifier
+- (Class)cellViewClassForCellIdentifier:(RoomTimelineCellIdentifier)identifier;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineStyle.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineStyle.swift
new file mode 100644
index 000000000..b430171b5
--- /dev/null
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineStyle.swift
@@ -0,0 +1,45 @@
+//
+// Copyright 2021 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
+import MatrixSDK
+
+/// RoomTimelineStyle describes a room timeline style used to customize timeline appearance
+@objc
+protocol RoomTimelineStyle: Themable {
+
+ // MARK: - Properties
+
+ /// Style identifier
+ var identifier: RoomTimelineStyleIdentifier { get }
+
+ /// Update layout if needed for cells provided by the cell provider
+ var cellLayoutUpdater: RoomCellLayoutUpdating? { get }
+
+ /// Register and provide timeline cells
+ var cellProvider: RoomTimelineCellProvider { get }
+
+ /// Handle cell decorations (reactions, read receipts, URL preview, …)
+ var cellDecorator: RoomTimelineCellDecorator { get }
+
+ // MARK: - Methods
+
+ /// Indicate to merge or not event in timeline
+ func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool
+
+ /// Apply selected or blurred style on cell
+ func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData)
+}
diff --git a/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineStyleIdentifier.swift b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineStyleIdentifier.swift
index e4f9a2316..a285fe8e0 100644
--- a/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineStyleIdentifier.swift
+++ b/Riot/Modules/Room/Views/BubbleCells/Styles/RoomTimelineStyleIdentifier.swift
@@ -17,7 +17,8 @@
import Foundation
/// Represents the room timeline style identifiers available
-enum RoomTimelineStyleIdentifier {
+@objc
+enum RoomTimelineStyleIdentifier: Int {
case plain
case bubble
}
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgBubbleCell.m
similarity index 69%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgBubbleCell.m
index 253e7141f..f4cfc616c 100644
--- a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgBubbleCell.m
+++ b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgBubbleCell.m
@@ -16,6 +16,17 @@
#import "MXKRoomIncomingTextMsgBubbleCell.h"
+#import "GeneratedInterface-Swift.h"
+
@implementation MXKRoomIncomingTextMsgBubbleCell
+- (void)setupViews
+{
+ [super setupViews];
+
+ RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
+
+ [timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForIncomingTextMessageCell:self];
+}
+
@end
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgBubbleCell.xib
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Incoming/Common/MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.xib
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgBubbleCell.m
similarity index 69%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgBubbleCell.m
index 232813182..bf6c70ae8 100644
--- a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgBubbleCell.m
+++ b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgBubbleCell.m
@@ -16,6 +16,18 @@
#import "MXKRoomOutgoingTextMsgBubbleCell.h"
+#import "GeneratedInterface-Swift.h"
+
@implementation MXKRoomOutgoingTextMsgBubbleCell
-@end
\ No newline at end of file
+- (void)setupViews
+{
+ [super setupViews];
+
+ RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
+
+ [timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForOutgoingTextMessageCell:self];
+}
+
+
+@end
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgBubbleCell.xib
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m
diff --git a/Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib b/Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib
similarity index 100%
rename from Riot/Modules/MatrixKit/Views/RoomBubbleList/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib
rename to Riot/Modules/Room/Views/BubbleCells/TextMessage/Outgoing/Common/MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib
diff --git a/Riot/Modules/Room/Views/Threads/From/FromThreadView.swift b/Riot/Modules/Room/Views/Threads/From/FromAThreadView.swift
similarity index 86%
rename from Riot/Modules/Room/Views/Threads/From/FromThreadView.swift
rename to Riot/Modules/Room/Views/Threads/From/FromAThreadView.swift
index 992a8b202..2ffd27f21 100644
--- a/Riot/Modules/Room/Views/Threads/From/FromThreadView.swift
+++ b/Riot/Modules/Room/Views/Threads/From/FromAThreadView.swift
@@ -18,7 +18,7 @@ import Foundation
import Reusable
@objcMembers
-class FromThreadView: UIView {
+class FromAThreadView: UIView {
private enum Constants {
static let viewHeight: CGFloat = 18
@@ -32,8 +32,8 @@ class FromThreadView: UIView {
return Constants.viewHeight
}
- static func instantiate() -> FromThreadView {
- let view = FromThreadView.loadFromNib()
+ static func instantiate() -> FromAThreadView {
+ let view = FromAThreadView.loadFromNib()
view.update(theme: ThemeService.shared().theme)
view.titleLabel.text = VectorL10n.messageFromAThread
return view
@@ -41,9 +41,9 @@ class FromThreadView: UIView {
}
-extension FromThreadView: NibLoadable {}
+extension FromAThreadView: NibLoadable {}
-extension FromThreadView: Themable {
+extension FromAThreadView: Themable {
func update(theme: Theme) {
backgroundColor = .clear
diff --git a/Riot/Modules/Room/Views/Threads/From/FromThreadView.xib b/Riot/Modules/Room/Views/Threads/From/FromAThreadView.xib
similarity index 91%
rename from Riot/Modules/Room/Views/Threads/From/FromThreadView.xib
rename to Riot/Modules/Room/Views/Threads/From/FromAThreadView.xib
index 8e8e9f8b2..d1f306129 100644
--- a/Riot/Modules/Room/Views/Threads/From/FromThreadView.xib
+++ b/Riot/Modules/Room/Views/Threads/From/FromAThreadView.xib
@@ -11,22 +11,22 @@
-
-
+
+
-
+
-
+
diff --git a/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryViewModel.swift b/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryModel.swift
similarity index 79%
rename from Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryViewModel.swift
rename to Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryModel.swift
index 0521c7f1a..59419d6ac 100644
--- a/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryViewModel.swift
+++ b/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryModel.swift
@@ -16,8 +16,8 @@
import Foundation
-struct ThreadSummaryViewModel {
- var numberOfReplies: Int
- var lastMessageSenderAvatar: AvatarViewDataProtocol?
- var lastMessageText: NSAttributedString?
+struct ThreadSummaryModel {
+ let numberOfReplies: Int
+ let lastMessageSenderAvatar: AvatarViewDataProtocol?
+ let lastMessageText: NSAttributedString?
}
diff --git a/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryView.swift b/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryView.swift
index 61917e30e..c1da2d9dd 100644
--- a/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryView.swift
+++ b/Riot/Modules/Room/Views/Threads/Summary/ThreadSummaryView.swift
@@ -38,7 +38,7 @@ class ThreadSummaryView: UIView {
@IBOutlet private weak var lastMessageContentLabel: UILabel!
private var theme: Theme = ThemeService.shared().theme
- private(set) var thread: MXThread!
+ private(set) var thread: MXThread?
private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
return UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
@@ -56,9 +56,10 @@ class ThreadSummaryView: UIView {
loadNibContent()
update(theme: ThemeService.shared().theme)
configure()
+ translatesAutoresizingMaskIntoConstraints = false
}
- static func contentViewHeight(forThread thread: MXThread, fitting maxWidth: CGFloat) -> CGFloat {
+ static func contentViewHeight(forThread thread: MXThread?, fitting maxWidth: CGFloat) -> CGFloat {
return RoomBubbleCellLayout.threadSummaryViewHeight
}
@@ -67,14 +68,14 @@ class ThreadSummaryView: UIView {
loadNibContent()
}
- @nonobjc func configure(withViewModel viewModel: ThreadSummaryViewModel) {
- numberOfRepliesLabel.text = String(viewModel.numberOfReplies)
- if let avatar = viewModel.lastMessageSenderAvatar {
+ @nonobjc func configure(withModel model: ThreadSummaryModel) {
+ numberOfRepliesLabel.text = String(model.numberOfReplies)
+ if let avatar = model.lastMessageSenderAvatar {
lastMessageAvatarView.fill(with: avatar)
} else {
lastMessageAvatarView.avatarImageView.image = nil
}
- if let lastMessage = viewModel.lastMessageText {
+ if let lastMessage = model.lastMessageText {
let mutable = NSMutableAttributedString(attributedString: lastMessage)
mutable.setAttributes([
.font: Constants.lastMessageFont
@@ -116,10 +117,10 @@ class ThreadSummaryView: UIView {
with: roomState,
error: formatterError)
- let viewModel = ThreadSummaryViewModel(numberOfReplies: thread.numberOfReplies,
- lastMessageSenderAvatar: avatarViewData,
- lastMessageText: lastMessageText)
- self.configure(withViewModel: viewModel)
+ let model = ThreadSummaryModel(numberOfReplies: thread.numberOfReplies,
+ lastMessageSenderAvatar: avatarViewData,
+ lastMessageText: lastMessageText)
+ self.configure(withModel: model)
}
}
@@ -132,8 +133,6 @@ class ThreadSummaryView: UIView {
}
}
-// extension ThreadSummaryView: NibLoadable {}
-
extension ThreadSummaryView: NibOwnerLoadable {}
extension ThreadSummaryView: Themable {
diff --git a/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleViewModel.swift b/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleModel.swift
similarity index 63%
rename from Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleViewModel.swift
rename to Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleModel.swift
index 9db319dea..059d99f5e 100644
--- a/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleViewModel.swift
+++ b/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleModel.swift
@@ -16,12 +16,12 @@
import Foundation
-struct ThreadRoomTitleViewModel {
- var roomAvatar: AvatarViewDataProtocol?
- var roomEncryptionBadge: UIImage?
- var roomDisplayName: String?
+struct ThreadRoomTitleModel {
+ let roomAvatar: AvatarViewDataProtocol?
+ let roomEncryptionBadge: UIImage?
+ let roomDisplayName: String?
- static let empty = ThreadRoomTitleViewModel(roomAvatar: nil,
- roomEncryptionBadge: nil,
- roomDisplayName: nil)
+ static let empty = ThreadRoomTitleModel(roomAvatar: nil,
+ roomEncryptionBadge: nil,
+ roomDisplayName: nil)
}
diff --git a/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleView.swift b/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleView.swift
index 22efeafba..59f4571f4 100644
--- a/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleView.swift
+++ b/Riot/Modules/Room/Views/Title/Thread/ThreadRoomTitleView.swift
@@ -38,15 +38,15 @@ class ThreadRoomTitleView: RoomTitleView {
// MARK: - Methods
- func configure(withViewModel viewModel: ThreadRoomTitleViewModel) {
- if let avatarViewData = viewModel.roomAvatar {
+ func configure(withModel model: ThreadRoomTitleModel) {
+ if let avatarViewData = model.roomAvatar {
roomAvatarView.fill(with: avatarViewData)
} else {
roomAvatarView.avatarImageView.image = nil
}
- roomEncryptionBadgeView.image = viewModel.roomEncryptionBadge
- roomEncryptionBadgeView.isHidden = viewModel.roomEncryptionBadge == nil
- roomNameLabel.text = viewModel.roomDisplayName
+ roomEncryptionBadgeView.image = model.roomEncryptionBadge
+ roomEncryptionBadgeView.isHidden = model.roomEncryptionBadge == nil
+ roomNameLabel.text = model.roomDisplayName
}
// MARK: - Overrides
@@ -81,10 +81,10 @@ class ThreadRoomTitleView: RoomTitleView {
encrpytionBadge = nil
}
- let viewModel = ThreadRoomTitleViewModel(roomAvatar: avatarViewData,
- roomEncryptionBadge: encrpytionBadge,
- roomDisplayName: room.displayName)
- configure(withViewModel: viewModel)
+ let model = ThreadRoomTitleModel(roomAvatar: avatarViewData,
+ roomEncryptionBadge: encrpytionBadge,
+ roomDisplayName: room.displayName)
+ configure(withModel: model)
}
override func awakeFromNib() {
diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m
index 7881b1541..be9326fdb 100644
--- a/Riot/Modules/Settings/SettingsViewController.m
+++ b/Riot/Modules/Settings/SettingsViewController.m
@@ -3898,6 +3898,13 @@ TableViewSectionsDelegate>
- (void)toggleEnableRoomMessageBubbles:(UISwitch *)sender
{
RiotSettings.shared.roomScreenEnableMessageBubbles = sender.isOn;
+
+ [[RoomTimelineConfiguration shared] updateStyleWithIdentifier:RiotSettings.shared.roomTimelineStyleIdentifier];
+
+ // Close all room data sources
+ // Be sure to use new room timeline style configurations
+ MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mainSession];
+ [roomDataSourceManager reset];
}
#pragma mark - TextField listener
diff --git a/Riot/Modules/SideMenu/SideMenuViewModel.swift b/Riot/Modules/SideMenu/SideMenuViewModel.swift
index c8baac060..7c9d128ee 100644
--- a/Riot/Modules/SideMenu/SideMenuViewModel.swift
+++ b/Riot/Modules/SideMenu/SideMenuViewModel.swift
@@ -97,8 +97,13 @@ final class SideMenuViewModel: SideMenuViewModelType {
return
}
- let sideMenuItems: [SideMenuItem] = [
- .inviteFriends,
+ var sideMenuItems: [SideMenuItem] = []
+
+ if BuildSettings.sideMenuShowInviteFriends {
+ sideMenuItems += [.inviteFriends]
+ }
+
+ sideMenuItems += [
.settings,
.help,
.feedback
diff --git a/Riot/Modules/SplitView/SplitViewCoordinator.swift b/Riot/Modules/SplitView/SplitViewCoordinator.swift
index bd56a095a..442da486e 100644
--- a/Riot/Modules/SplitView/SplitViewCoordinator.swift
+++ b/Riot/Modules/SplitView/SplitViewCoordinator.swift
@@ -363,13 +363,13 @@ extension SplitViewCoordinator: SplitViewMasterPresentableDelegate {
detailNavigationRouter.push(detailPresentable, animated: true, popCompletion: popCompletion)
}
- func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [PresentableModule]) {
+ func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [NavigationModule]) {
MXLog.debug("[SplitViewCoordinator] splitViewMasterPresentable: \(presentable) wantsToReplaceDetailsWith modules: \(modules)")
self.detailNavigationRouter?.setModules(modules, animated: true)
}
- func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [PresentableModule]) {
+ func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [NavigationModule]) {
guard let detailNavigationRouter = self.detailNavigationRouter else {
MXLog.warning("[SplitViewCoordinator] Failed to stack \(modules) because detailNavigationRouter is nil")
return
diff --git a/Riot/Modules/SplitView/SplitViewPresentable.swift b/Riot/Modules/SplitView/SplitViewPresentable.swift
index 7dcb0da12..4e63663f1 100644
--- a/Riot/Modules/SplitView/SplitViewPresentable.swift
+++ b/Riot/Modules/SplitView/SplitViewPresentable.swift
@@ -28,10 +28,10 @@ protocol SplitViewMasterPresentableDelegate: AnyObject {
func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack detailPresentable: Presentable, popCompletion: (() -> Void)?)
/// Replace split view detail with the given modules
- func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [PresentableModule])
+ func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [NavigationModule])
/// Stack modules on the existing split view detail stack
- func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [PresentableModule])
+ func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [NavigationModule])
/// Pop to module on the existing split view detail stack
func splitViewMasterPresentable(_ presentable: Presentable, wantsToPopTo module: Presentable)
diff --git a/Riot/Modules/TabBar/TabBarCoordinator.swift b/Riot/Modules/TabBar/TabBarCoordinator.swift
index d2283f18d..c0454e86c 100644
--- a/Riot/Modules/TabBar/TabBarCoordinator.swift
+++ b/Riot/Modules/TabBar/TabBarCoordinator.swift
@@ -395,58 +395,8 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
private func showRoom(withNavigationParameters roomNavigationParameters: RoomNavigationParameters, completion: (() -> Void)?) {
if let threadParameters = roomNavigationParameters.threadParameters, threadParameters.stackRoomScreen {
- self.activityIndicatorPresenter.presentActivityIndicator(on: toPresentable().view, animated: false)
- let dispatchGroup = DispatchGroup()
-
- // create room coordinator
- let roomCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
- session: roomNavigationParameters.mxSession,
- roomId: roomNavigationParameters.roomId,
- eventId: nil,
- threadId: nil)
-
- dispatchGroup.enter()
- let roomCoordinator = RoomCoordinator(parameters: roomCoordinatorParameters)
- roomCoordinator.delegate = self
- roomCoordinator.start {
- dispatchGroup.leave()
- }
- self.add(childCoordinator: roomCoordinator)
-
- // create thread coordinator
- let threadCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
- session: roomNavigationParameters.mxSession,
- roomId: roomNavigationParameters.roomId,
- eventId: roomNavigationParameters.eventId,
- threadId: roomNavigationParameters.threadParameters?.threadId,
- displayConfiguration: .forThreads)
-
- dispatchGroup.enter()
- let threadCoordinator = RoomCoordinator(parameters: threadCoordinatorParameters)
- threadCoordinator.delegate = self
- threadCoordinator.start {
- dispatchGroup.leave()
- }
- self.add(childCoordinator: threadCoordinator)
-
- dispatchGroup.notify(queue: .main) { [weak self] in
- guard let self = self else { return }
- let modules: [PresentableModule] = [
- PresentableModule(presentable: roomCoordinator, popCompletion: { [weak self] in
- // NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
- self?.remove(childCoordinator: roomCoordinator)
- }),
- PresentableModule(presentable: threadCoordinator, popCompletion: { [weak self] in
- // NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
- self?.remove(childCoordinator: threadCoordinator)
- })
- ]
-
- self.showSplitViewDetails(with: modules,
- stack: roomNavigationParameters.presentationParameters.stackAboveVisibleViews)
-
- self.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true)
- }
+ showRoomAndThread(with: roomNavigationParameters,
+ completion: completion)
} else {
let threadId = roomNavigationParameters.threadParameters?.threadId
let displayConfig: RoomDisplayConfiguration
@@ -531,6 +481,62 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
self?.remove(childCoordinator: coordinator)
}
}
+
+ private func showRoomAndThread(with roomNavigationParameters: RoomNavigationParameters,
+ completion: (() -> Void)? = nil) {
+ self.activityIndicatorPresenter.presentActivityIndicator(on: toPresentable().view, animated: false)
+ let dispatchGroup = DispatchGroup()
+
+ // create room coordinator
+ let roomCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
+ session: roomNavigationParameters.mxSession,
+ roomId: roomNavigationParameters.roomId,
+ eventId: nil,
+ threadId: nil)
+
+ dispatchGroup.enter()
+ let roomCoordinator = RoomCoordinator(parameters: roomCoordinatorParameters)
+ roomCoordinator.delegate = self
+ roomCoordinator.start {
+ dispatchGroup.leave()
+ }
+ self.add(childCoordinator: roomCoordinator)
+
+ // create thread coordinator
+ let threadCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
+ session: roomNavigationParameters.mxSession,
+ roomId: roomNavigationParameters.roomId,
+ eventId: roomNavigationParameters.eventId,
+ threadId: roomNavigationParameters.threadParameters?.threadId,
+ displayConfiguration: .forThreads)
+
+ dispatchGroup.enter()
+ let threadCoordinator = RoomCoordinator(parameters: threadCoordinatorParameters)
+ threadCoordinator.delegate = self
+ threadCoordinator.start {
+ dispatchGroup.leave()
+ }
+ self.add(childCoordinator: threadCoordinator)
+
+ dispatchGroup.notify(queue: .main) { [weak self] in
+ guard let self = self else { return }
+ let modules: [NavigationModule] = [
+ NavigationModule(presentable: roomCoordinator, popCompletion: { [weak self] in
+ // NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
+ self?.remove(childCoordinator: roomCoordinator)
+ }),
+ NavigationModule(presentable: threadCoordinator, popCompletion: { [weak self] in
+ // NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
+ self?.remove(childCoordinator: threadCoordinator)
+ })
+ ]
+
+ self.showSplitViewDetails(with: modules,
+ stack: roomNavigationParameters.presentationParameters.stackAboveVisibleViews)
+
+ self.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true)
+ }
+ }
// MARK: Split view
@@ -553,7 +559,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
}
}
- private func showSplitViewDetails(with modules: [PresentableModule], stack: Bool) {
+ private func showSplitViewDetails(with modules: [NavigationModule], stack: Bool) {
if stack {
self.splitViewMasterPresentableDelegate?.splitViewMasterPresentable(self, wantsToStack: modules)
} else {
diff --git a/Riot/Modules/Threads/Thread/ThreadViewController.swift b/Riot/Modules/Threads/Thread/ThreadViewController.swift
index 3000885f0..2dace6547 100644
--- a/Riot/Modules/Threads/Thread/ThreadViewController.swift
+++ b/Riot/Modules/Threads/Thread/ThreadViewController.swift
@@ -113,11 +113,11 @@ class ThreadViewController: RoomViewController {
}
private func copyPermalink() {
- guard let permalink = permalink else {
+ guard let permalink = permalink, let url = URL(string: permalink) else {
return
}
- MXKPasteboardManager.shared.pasteboard.string = permalink
+ MXKPasteboardManager.shared.pasteboard.url = url
view.vc_toast(message: VectorL10n.roomEventCopyLinkInfo,
image: Asset.Images.linkIcon.image,
additionalMargin: self.roomInputToolbarContainerHeightConstraint.constant)
diff --git a/Riot/Modules/Threads/ThreadList/ThreadListCoordinatorProtocol.swift b/Riot/Modules/Threads/ThreadList/ThreadListCoordinatorProtocol.swift
index e15c70f35..e23505480 100644
--- a/Riot/Modules/Threads/ThreadList/ThreadListCoordinatorProtocol.swift
+++ b/Riot/Modules/Threads/ThreadList/ThreadListCoordinatorProtocol.swift
@@ -25,7 +25,7 @@ protocol ThreadListCoordinatorDelegate: AnyObject {
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol)
}
-/// `ThreadListCoordinatorProtocol` is a protocol describing a Coordinator that handle xxxxxxx navigation flow.
+/// `ThreadListCoordinatorProtocol` is a protocol describing a Coordinator that handle thread list navigation flow.
protocol ThreadListCoordinatorProtocol: Coordinator, Presentable {
var delegate: ThreadListCoordinatorDelegate? { get }
}
diff --git a/Riot/Modules/Threads/ThreadList/ThreadListViewController.swift b/Riot/Modules/Threads/ThreadList/ThreadListViewController.swift
index 7c9eba632..1a34664e0 100644
--- a/Riot/Modules/Threads/ThreadList/ThreadListViewController.swift
+++ b/Riot/Modules/Threads/ThreadList/ThreadListViewController.swift
@@ -20,12 +20,6 @@ import UIKit
final class ThreadListViewController: UIViewController {
- // MARK: - Constants
-
- private enum Constants {
- static let aConstant: Int = 666
- }
-
// MARK: - Properties
// MARK: Outlets
@@ -125,7 +119,7 @@ final class ThreadListViewController: UIViewController {
private func setupViews() {
let titleView = ThreadRoomTitleView.loadFromNib()
titleView.mode = .allThreads
- titleView.configure(withViewModel: viewModel.titleViewModel)
+ titleView.configure(withModel: viewModel.titleModel)
titleView.updateLayout(for: UIApplication.shared.statusBarOrientation)
self.titleView = titleView
navigationItem.leftItemsSupplementBackButton = true
@@ -150,14 +144,14 @@ final class ThreadListViewController: UIViewController {
renderLoading()
case .loaded:
renderLoaded()
- case .empty(let viewModel):
- renderEmptyView(withViewModel: viewModel)
+ case .empty(let model):
+ renderEmptyView(withModel: model)
case .showingFilterTypes:
renderShowingFilterTypes()
- case .showingLongPressActions:
- renderShowingLongPressActions()
- case .share(let string):
- renderShare(string)
+ case .showingLongPressActions(let index):
+ renderShowingLongPressActions(index)
+ case .share(let url, let index):
+ renderShare(url, index: index)
case .toastForCopyLink:
toastForCopyLink()
case .error(let error):
@@ -184,9 +178,9 @@ final class ThreadListViewController: UIViewController {
}
}
- private func renderEmptyView(withViewModel emptyViewModel: ThreadListEmptyViewModel) {
+ private func renderEmptyView(withModel model: ThreadListEmptyModel) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
- emptyView.configure(withViewModel: emptyViewModel)
+ emptyView.configure(withModel: model)
threadsTableView.isHidden = true
emptyView.isHidden = false
navigationItem.rightBarButtonItem?.isEnabled = viewModel.selectedFilterType == .myThreads
@@ -232,7 +226,7 @@ final class ThreadListViewController: UIViewController {
self.present(alertController, animated: true, completion: nil)
}
- private func renderShowingLongPressActions() {
+ private func renderShowingLongPressActions(_ index: Int) {
let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
controller.addAction(UIAlertAction(title: VectorL10n.roomEventActionViewInRoom,
@@ -259,14 +253,25 @@ final class ThreadListViewController: UIViewController {
controller.addAction(UIAlertAction(title: VectorL10n.cancel,
style: .cancel,
handler: nil))
-
+
+ if let cell = threadsTableView.cellForRow(at: IndexPath(row: index, section: 0)) {
+ controller.popoverPresentationController?.sourceView = cell
+ } else {
+ controller.popoverPresentationController?.sourceView = view
+ }
+
self.present(controller, animated: true, completion: nil)
}
- private func renderShare(_ string: String) {
- let activityVC = UIActivityViewController(activityItems: [string],
+ private func renderShare(_ url: URL, index: Int) {
+ let activityVC = UIActivityViewController(activityItems: [url],
applicationActivities: nil)
activityVC.modalTransitionStyle = .coverVertical
+ if let cell = threadsTableView.cellForRow(at: IndexPath(row: index, section: 0)) {
+ activityVC.popoverPresentationController?.sourceView = cell
+ } else {
+ activityVC.popoverPresentationController?.sourceView = view
+ }
present(activityVC, animated: true, completion: nil)
}
@@ -327,8 +332,8 @@ extension ThreadListViewController: UITableViewDataSource {
let cell: ThreadTableViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.update(theme: theme)
- if let threadVM = viewModel.threadViewModel(at: indexPath.row) {
- cell.configure(withViewModel: threadVM)
+ if let threadModel = viewModel.threadModel(at: indexPath.row) {
+ cell.configure(withModel: threadModel)
}
return cell
diff --git a/Riot/Modules/Threads/ThreadList/ThreadListViewModel.swift b/Riot/Modules/Threads/ThreadList/ThreadListViewModel.swift
index 0e844c7a6..381c19f52 100644
--- a/Riot/Modules/Threads/ThreadList/ThreadListViewModel.swift
+++ b/Riot/Modules/Threads/ThreadList/ThreadListViewModel.swift
@@ -92,14 +92,14 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
return threads.count
}
- func threadViewModel(at index: Int) -> ThreadViewModel? {
+ func threadModel(at index: Int) -> ThreadModel? {
guard index < threads.count else {
return nil
}
- return viewModel(forThread: threads[index])
+ return model(forThread: threads[index])
}
- var titleViewModel: ThreadRoomTitleViewModel {
+ var titleModel: ThreadRoomTitleModel {
guard let room = session.room(withRoomId: roomId) else {
return .empty
}
@@ -118,33 +118,33 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
encrpytionBadge = nil
}
- return ThreadRoomTitleViewModel(roomAvatar: avatarViewData,
- roomEncryptionBadge: encrpytionBadge,
- roomDisplayName: room.displayName)
+ return ThreadRoomTitleModel(roomAvatar: avatarViewData,
+ roomEncryptionBadge: encrpytionBadge,
+ roomDisplayName: room.displayName)
}
- private var emptyViewModel: ThreadListEmptyViewModel {
+ private var emptyViewModel: ThreadListEmptyModel {
switch selectedFilterType {
case .all:
- return ThreadListEmptyViewModel(icon: Asset.Images.threadsIcon.image,
- title: VectorL10n.threadsEmptyTitle,
- info: VectorL10n.threadsEmptyInfoAll,
- tip: VectorL10n.threadsEmptyTip,
- showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
- showAllThreadsButtonHidden: true)
+ return ThreadListEmptyModel(icon: Asset.Images.threadsIcon.image,
+ title: VectorL10n.threadsEmptyTitle,
+ info: VectorL10n.threadsEmptyInfoAll,
+ tip: VectorL10n.threadsEmptyTip,
+ showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
+ showAllThreadsButtonHidden: true)
case .myThreads:
- return ThreadListEmptyViewModel(icon: Asset.Images.threadsIcon.image,
- title: VectorL10n.threadsEmptyTitle,
- info: VectorL10n.threadsEmptyInfoMy,
- tip: nil,
- showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
- showAllThreadsButtonHidden: false)
+ return ThreadListEmptyModel(icon: Asset.Images.threadsIcon.image,
+ title: VectorL10n.threadsEmptyTitle,
+ info: VectorL10n.threadsEmptyInfoMy,
+ tip: nil,
+ showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
+ showAllThreadsButtonHidden: false)
}
}
// MARK: - Private
- private func viewModel(forThread thread: MXThread) -> ThreadViewModel {
+ private func model(forThread thread: MXThread) -> ThreadModel {
let rootAvatarViewData: AvatarViewData?
let rootMessageSender: MXUser?
let lastAvatarViewData: AvatarViewData?
@@ -184,19 +184,19 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
lastAvatarViewData = nil
lastMessageSender = nil
}
-
- let summaryViewModel = ThreadSummaryViewModel(numberOfReplies: thread.numberOfReplies,
- lastMessageSenderAvatar: lastAvatarViewData,
- lastMessageText: lastMessageText)
-
- return ThreadViewModel(rootMessageSenderUserId: rootMessageSender?.userId,
- rootMessageSenderAvatar: rootAvatarViewData,
- rootMessageSenderDisplayName: rootMessageSender?.displayname,
- rootMessageText: rootMessageText,
- rootMessageRedacted: thread.rootMessage?.isRedactedEvent() ?? false,
- lastMessageTime: lastMessageTime,
- summaryViewModel: summaryViewModel,
- notificationStatus: notificationStatus)
+
+ let summaryModel = ThreadSummaryModel(numberOfReplies: thread.numberOfReplies,
+ lastMessageSenderAvatar: lastAvatarViewData,
+ lastMessageText: lastMessageText)
+
+ return ThreadModel(rootMessageSenderUserId: rootMessageSender?.userId,
+ rootMessageSenderAvatar: rootAvatarViewData,
+ rootMessageSenderDisplayName: rootMessageSender?.displayname,
+ rootMessageText: rootMessageText,
+ rootMessageRedacted: thread.rootMessage?.isRedactedEvent() ?? false,
+ lastMessageTime: lastMessageTime,
+ summaryModel: summaryModel,
+ notificationStatus: notificationStatus)
}
private func rootMessageText(forThread thread: MXThread) -> NSAttributedString? {
@@ -298,7 +298,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
return
}
longPressedThread = threads[index]
- viewState = .showingLongPressActions
+ viewState = .showingLongPressActions(index)
}
private func actionViewInRoom() {
@@ -313,19 +313,22 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
guard let thread = longPressedThread else {
return
}
- if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId) {
- MXKPasteboardManager.shared.pasteboard.string = permalink
+ if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId),
+ let url = URL(string: permalink) {
+ MXKPasteboardManager.shared.pasteboard.url = url
viewState = .toastForCopyLink
}
longPressedThread = nil
}
private func actionShare() {
- guard let thread = longPressedThread else {
+ guard let thread = longPressedThread,
+ let index = threads.firstIndex(of: thread) else {
return
}
- if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId) {
- viewState = .share(permalink)
+ if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId),
+ let url = URL(string: permalink) {
+ viewState = .share(url, index)
}
longPressedThread = nil
}
diff --git a/Riot/Modules/Threads/ThreadList/ThreadListViewModelProtocol.swift b/Riot/Modules/Threads/ThreadList/ThreadListViewModelProtocol.swift
index 457cf39d5..3720f0c35 100644
--- a/Riot/Modules/Threads/ThreadList/ThreadListViewModelProtocol.swift
+++ b/Riot/Modules/Threads/ThreadList/ThreadListViewModelProtocol.swift
@@ -39,10 +39,10 @@ protocol ThreadListViewModelProtocol {
var viewState: ThreadListViewState { get }
- var titleViewModel: ThreadRoomTitleViewModel { get }
+ var titleModel: ThreadRoomTitleModel { get }
var selectedFilterType: ThreadListFilterType { get }
var numberOfThreads: Int { get }
- func threadViewModel(at index: Int) -> ThreadViewModel?
+ func threadModel(at index: Int) -> ThreadModel?
}
enum ThreadListFilterType {
diff --git a/Riot/Modules/Threads/ThreadList/ThreadListViewState.swift b/Riot/Modules/Threads/ThreadList/ThreadListViewState.swift
index 07196a49e..6140ef41f 100644
--- a/Riot/Modules/Threads/ThreadList/ThreadListViewState.swift
+++ b/Riot/Modules/Threads/ThreadList/ThreadListViewState.swift
@@ -23,10 +23,10 @@ enum ThreadListViewState {
case idle
case loading
case loaded
- case empty(_ viewModel: ThreadListEmptyViewModel)
+ case empty(_ viewModel: ThreadListEmptyModel)
case showingFilterTypes
- case showingLongPressActions
- case share(_ string: String)
+ case showingLongPressActions(_ index: Int)
+ case share(_ url: URL, _ index: Int)
case toastForCopyLink
case error(Error)
}
diff --git a/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadViewModel.swift b/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadModel.swift
similarity index 71%
rename from Riot/Modules/Threads/ThreadList/Views/Cell/ThreadViewModel.swift
rename to Riot/Modules/Threads/ThreadList/Views/Cell/ThreadModel.swift
index e95dcdb58..1692b9f6c 100644
--- a/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadViewModel.swift
+++ b/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadModel.swift
@@ -16,22 +16,22 @@
import Foundation
-struct ThreadViewModel {
- var rootMessageSenderUserId: String?
- var rootMessageSenderAvatar: AvatarViewDataProtocol?
- var rootMessageSenderDisplayName: String?
- var rootMessageText: NSAttributedString?
- var rootMessageRedacted: Bool
- var lastMessageTime: String?
- var summaryViewModel: ThreadSummaryViewModel?
- var notificationStatus: ThreadNotificationStatus
+struct ThreadModel {
+ let rootMessageSenderUserId: String?
+ let rootMessageSenderAvatar: AvatarViewDataProtocol?
+ let rootMessageSenderDisplayName: String?
+ let rootMessageText: NSAttributedString?
+ let rootMessageRedacted: Bool
+ let lastMessageTime: String?
+ let summaryModel: ThreadSummaryModel?
+ let notificationStatus: ThreadNotificationStatus
}
enum ThreadNotificationStatus {
case none
case notified
case highlighted
-
+
init(withThread thread: MXThread) {
if thread.highlightCount > 0 {
self = .highlighted
diff --git a/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadTableViewCell.swift b/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadTableViewCell.swift
index ae4e22ba4..48a7f8cf9 100644
--- a/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadTableViewCell.swift
+++ b/Riot/Modules/Threads/ThreadList/Views/Cell/ThreadTableViewCell.swift
@@ -40,10 +40,7 @@ class ThreadTableViewCell: UITableViewCell {
@IBOutlet private weak var summaryView: ThreadSummaryView!
@IBOutlet private weak var notificationStatusView: ThreadNotificationStatusView!
- private static var usernameColorGenerator: UserNameColorGenerator = {
- let generator = UserNameColorGenerator()
- return generator
- }()
+ private static var usernameColorGenerator = UserNameColorGenerator()
override func awakeFromNib() {
super.awakeFromNib()
@@ -51,26 +48,26 @@ class ThreadTableViewCell: UITableViewCell {
separatorInset = Constants.separatorInset
}
- func configure(withViewModel viewModel: ThreadViewModel) {
- if let rootAvatar = viewModel.rootMessageSenderAvatar {
+ func configure(withModel model: ThreadModel) {
+ if let rootAvatar = model.rootMessageSenderAvatar {
rootMessageAvatarView.fill(with: rootAvatar)
} else {
rootMessageAvatarView.avatarImageView.image = nil
}
- configuredSenderId = viewModel.rootMessageSenderUserId
- configuredRootMessageRedacted = viewModel.rootMessageRedacted
+ configuredSenderId = model.rootMessageSenderUserId
+ configuredRootMessageRedacted = model.rootMessageRedacted
updateRootMessageSenderColor()
- rootMessageSenderLabel.text = viewModel.rootMessageSenderDisplayName
- if let rootMessageText = viewModel.rootMessageText {
+ rootMessageSenderLabel.text = model.rootMessageSenderDisplayName
+ if let rootMessageText = model.rootMessageText {
updateRootMessageContentAttributes(rootMessageText, color: rootMessageColor)
} else {
rootMessageContentLabel.attributedText = nil
}
- lastMessageTimeLabel.text = viewModel.lastMessageTime
- if let summaryViewModel = viewModel.summaryViewModel {
- summaryView.configure(withViewModel: summaryViewModel)
+ lastMessageTimeLabel.text = model.lastMessageTime
+ if let summaryModel = model.summaryModel {
+ summaryView.configure(withModel: summaryModel)
}
- notificationStatusView.status = viewModel.notificationStatus
+ notificationStatusView.status = model.notificationStatus
}
private func updateRootMessageSenderColor() {
diff --git a/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyViewModel.swift b/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyModel.swift
similarity index 95%
rename from Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyViewModel.swift
rename to Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyModel.swift
index bef214bba..74162b2a0 100644
--- a/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyViewModel.swift
+++ b/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyModel.swift
@@ -16,7 +16,7 @@
import Foundation
-struct ThreadListEmptyViewModel {
+struct ThreadListEmptyModel {
let icon: UIImage?
let title: String?
let info: String?
diff --git a/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyView.swift b/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyView.swift
index 98e9b0535..fd33b28bd 100644
--- a/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyView.swift
+++ b/Riot/Modules/Threads/ThreadList/Views/Empty/ThreadListEmptyView.swift
@@ -22,6 +22,7 @@ protocol ThreadListEmptyViewDelegate: AnyObject {
func threadListEmptyViewTappedShowAllThreads(_ emptyView: ThreadListEmptyView)
}
+/// View to be shown on the thread list screen when no thread is available. Use a `ThreadListEmptyModel` instance to configure.
class ThreadListEmptyView: UIView {
@IBOutlet weak var delegate: ThreadListEmptyViewDelegate?
@@ -38,14 +39,14 @@ class ThreadListEmptyView: UIView {
loadNibContent()
}
- func configure(withViewModel viewModel: ThreadListEmptyViewModel) {
- iconView.image = viewModel.icon
- titleLabel.text = viewModel.title
- infoLabel.text = viewModel.info
- tipLabel.text = viewModel.tip
- showAllThreadsButton.setTitle(viewModel.showAllThreadsButtonTitle,
+ func configure(withModel model: ThreadListEmptyModel) {
+ iconView.image = model.icon
+ titleLabel.text = model.title
+ infoLabel.text = model.info
+ tipLabel.text = model.tip
+ showAllThreadsButton.setTitle(model.showAllThreadsButtonTitle,
for: .normal)
- showAllThreadsButton.isHidden = viewModel.showAllThreadsButtonHidden
+ showAllThreadsButton.isHidden = model.showAllThreadsButtonHidden
titleLabel.isHidden = titleLabel.text?.isEmpty ?? true
infoLabel.isHidden = infoLabel.text?.isEmpty ?? true
diff --git a/Riot/Modules/Threads/ThreadsCoordinator.swift b/Riot/Modules/Threads/ThreadsCoordinator.swift
index 9e6e63e8f..f5857dcc9 100644
--- a/Riot/Modules/Threads/ThreadsCoordinator.swift
+++ b/Riot/Modules/Threads/ThreadsCoordinator.swift
@@ -54,7 +54,12 @@ final class ThreadsCoordinator: NSObject, ThreadsCoordinatorProtocol {
func start() {
- let rootCoordinator = self.createThreadListCoordinator()
+ let rootCoordinator: Coordinator & Presentable
+ if let threadId = parameters.threadId {
+ rootCoordinator = createThreadCoordinator(forThreadId: threadId)
+ } else {
+ rootCoordinator = createThreadListCoordinator()
+ }
rootCoordinator.start()
@@ -77,6 +82,10 @@ final class ThreadsCoordinator: NSObject, ThreadsCoordinatorProtocol {
func stop() {
if selectedThreadCoordinator != nil {
let modules = self.navigationRouter.modules
+ // if a thread is selected from the thread list coordinator, then navigation stack will look like:
+ // ... -> Screen A -> Thread List Screen -> Thread Screen
+ // we'll try to pop to Screen A here
+ // sanity check: navigation stack contains at least 3 items
guard modules.count >= 3 else {
return
}
@@ -116,13 +125,13 @@ final class ThreadsCoordinator: NSObject, ThreadsCoordinatorProtocol {
return coordinator
}
- private func createThreadCoordinator(forThread thread: MXThread) -> RoomCoordinator {
+ private func createThreadCoordinator(forThreadId threadId: String) -> RoomCoordinator {
let parameters = RoomCoordinatorParameters(navigationRouter: navigationRouter,
navigationRouterStore: nil,
session: parameters.session,
roomId: parameters.roomId,
eventId: nil,
- threadId: thread.id,
+ threadId: threadId,
displayConfiguration: .forThreads)
let coordinator = RoomCoordinator(parameters: parameters)
coordinator.delegate = self
@@ -145,7 +154,7 @@ extension ThreadsCoordinator: ThreadListCoordinatorDelegate {
}
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThread) {
- let roomCoordinator = createThreadCoordinator(forThread: thread)
+ let roomCoordinator = createThreadCoordinator(forThreadId: thread.id)
selectedThreadCoordinator = roomCoordinator
roomCoordinator.start()
self.add(childCoordinator: roomCoordinator)
diff --git a/Riot/Modules/Threads/ThreadsCoordinatorBridgePresenter.swift b/Riot/Modules/Threads/ThreadsCoordinatorBridgePresenter.swift
index 6c12eb40c..43879b292 100644
--- a/Riot/Modules/Threads/ThreadsCoordinatorBridgePresenter.swift
+++ b/Riot/Modules/Threads/ThreadsCoordinatorBridgePresenter.swift
@@ -45,6 +45,7 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
private let session: MXSession
private let roomId: String
+ private let threadId: String?
private var navigationType: NavigationType = .present
private var coordinator: ThreadsCoordinator?
@@ -53,11 +54,18 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
weak var delegate: ThreadsCoordinatorBridgePresenterDelegate?
// MARK: - Setup
-
+
+ /// Initializer
+ /// - Parameters:
+ /// - session: Session instance
+ /// - roomId: Room identifier
+ /// - threadId: Thread identifier. Specified thread will be opened if provided, the thread list otherwise
init(session: MXSession,
- roomId: String) {
+ roomId: String,
+ threadId: String?) {
self.session = session
self.roomId = roomId
+ self.threadId = threadId
super.init()
}
@@ -71,7 +79,8 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
func present(from viewController: UIViewController, animated: Bool) {
let threadsCoordinatorParameters = ThreadsCoordinatorParameters(session: self.session,
- roomId: self.roomId)
+ roomId: self.roomId,
+ threadId: self.threadId)
let threadsCoordinator = ThreadsCoordinator(parameters: threadsCoordinatorParameters)
threadsCoordinator.delegate = self
@@ -89,6 +98,7 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
let threadsCoordinatorParameters = ThreadsCoordinatorParameters(session: self.session,
roomId: self.roomId,
+ threadId: self.threadId,
navigationRouter: navigationRouter)
let threadsCoordinator = ThreadsCoordinator(parameters: threadsCoordinatorParameters)
diff --git a/Riot/Modules/Threads/ThreadsCoordinatorParameters.swift b/Riot/Modules/Threads/ThreadsCoordinatorParameters.swift
index 3e21ad86e..83a2d47be 100644
--- a/Riot/Modules/Threads/ThreadsCoordinatorParameters.swift
+++ b/Riot/Modules/Threads/ThreadsCoordinatorParameters.swift
@@ -26,15 +26,20 @@ struct ThreadsCoordinatorParameters {
/// Room identifier
let roomId: String
+
+ /// Thread identifier. Specified thread will be opened if provided, the thread list otherwise
+ let threadId: String?
/// The navigation router that manage physical navigation
let navigationRouter: NavigationRouterType
init(session: MXSession,
roomId: String,
+ threadId: String?,
navigationRouter: NavigationRouterType? = nil) {
self.session = session
self.roomId = roomId
+ self.threadId = threadId
self.navigationRouter = navigationRouter ?? NavigationRouter(navigationController: RiotNavigationController())
}
}
diff --git a/Riot/Routers/PresentableModule.swift b/Riot/Routers/NavigationModule.swift
similarity index 83%
rename from Riot/Routers/PresentableModule.swift
rename to Riot/Routers/NavigationModule.swift
index 4ee7e3379..01c54bb98 100644
--- a/Riot/Routers/PresentableModule.swift
+++ b/Riot/Routers/NavigationModule.swift
@@ -17,7 +17,7 @@
import Foundation
/// Structure used to pass modules to routers with pop completion blocks.
-struct PresentableModule {
+struct NavigationModule {
/// Actual presentable of the module
let presentable: Presentable
@@ -27,10 +27,10 @@ struct PresentableModule {
// MARK: - CustomStringConvertible
-extension PresentableModule: CustomStringConvertible {
+extension NavigationModule: CustomStringConvertible {
var description: String {
- return "PresentableModule: \(presentable), pop completion: \(String(describing: popCompletion))"
+ return "NavigationModule: \(presentable), pop completion: \(String(describing: popCompletion))"
}
}
diff --git a/Riot/Routers/NavigationRouter.swift b/Riot/Routers/NavigationRouter.swift
index c406cc7e7..23c05aff1 100755
--- a/Riot/Routers/NavigationRouter.swift
+++ b/Riot/Routers/NavigationRouter.swift
@@ -117,7 +117,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
self.didPushViewController(controller)
}
- func setModules(_ modules: [PresentableModule], hideNavigationBar: Bool, animated: Bool) {
+ func setModules(_ modules: [NavigationModule], hideNavigationBar: Bool, animated: Bool) {
MXLog.debug("[NavigationRouter] Set modules \(modules)")
@@ -221,7 +221,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
self.didPushViewController(controller)
}
- func push(_ modules: [PresentableModule], animated: Bool) {
+ func push(_ modules: [NavigationModule], animated: Bool) {
MXLog.debug("[NavigationRouter] Push modules \(modules)")
// Avoid pushing any UINavigationController onto stack
diff --git a/Riot/Routers/NavigationRouterType.swift b/Riot/Routers/NavigationRouterType.swift
index ca248526f..f1275efa0 100755
--- a/Riot/Routers/NavigationRouterType.swift
+++ b/Riot/Routers/NavigationRouterType.swift
@@ -45,7 +45,7 @@ protocol NavigationRouterType: AnyObject, Presentable {
/// - modules: The modules stack to set.
/// - hideNavigationBar: Specify true to hide the UINavigationBar.
/// - animated: Specify true to animate the transition.
- func setModules(_ modules: [PresentableModule], hideNavigationBar: Bool, animated: Bool)
+ func setModules(_ modules: [NavigationModule], hideNavigationBar: Bool, animated: Bool)
/// Pop to root view controller of navigation controller and remove all others
///
@@ -68,7 +68,7 @@ protocol NavigationRouterType: AnyObject, Presentable {
///
/// - Parameter modules: Modules to push
/// - Parameter animated: Specify true to animate the transition.
- func push(_ modules: [PresentableModule], animated: Bool)
+ func push(_ modules: [NavigationModule], animated: Bool)
/// Pop last view controller from navigation controller stack
///
@@ -99,7 +99,7 @@ extension NavigationRouterType {
setRootModule(module, hideNavigationBar: false, animated: false, popCompletion: popCompletion)
}
- func setModules(_ modules: [PresentableModule], animated: Bool) {
+ func setModules(_ modules: [NavigationModule], animated: Bool) {
setModules(modules, hideNavigationBar: false, animated: animated)
}
@@ -109,15 +109,15 @@ extension NavigationRouterType {
}
-// MARK: - Presentable <--> ModulePresentable Transitive Methods
+// MARK: - Presentable <--> NavigationModule Transitive Methods
extension NavigationRouterType {
- func setRootModule(_ module: PresentableModule) {
+ func setRootModule(_ module: NavigationModule) {
setRootModule(module.presentable, popCompletion: module.popCompletion)
}
- func push(_ module: PresentableModule, animated: Bool) {
+ func push(_ module: NavigationModule, animated: Bool) {
push(module.presentable, animated: animated, popCompletion: module.popCompletion)
}
diff --git a/Riot/Routers/Presentable.swift b/Riot/Routers/Presentable.swift
index 15943afbf..e9f760393 100755
--- a/Riot/Routers/Presentable.swift
+++ b/Riot/Routers/Presentable.swift
@@ -31,8 +31,8 @@ extension Presentable {
/// Returns a new module from the presentable without a pop completion block
/// - Returns: Module
- func toModule() -> PresentableModule {
- return PresentableModule(presentable: self, popCompletion: nil)
+ func toModule() -> NavigationModule {
+ return NavigationModule(presentable: self, popCompletion: nil)
}
}
diff --git a/Riot/SupportingFiles/Riot-Bridging-Header.h b/Riot/SupportingFiles/Riot-Bridging-Header.h
index c5a22e8a7..9eaae3a43 100644
--- a/Riot/SupportingFiles/Riot-Bridging-Header.h
+++ b/Riot/SupportingFiles/Riot-Bridging-Header.h
@@ -46,6 +46,9 @@
#import "NSArray+Element.h"
#import "ShareItemSender.h"
#import "HTMLFormatter.h"
+#import "RoomTimelineCellProvider.h"
+#import "PlainRoomTimelineCellProvider.h"
+#import "BubbleRoomTimelineCellProvider.h"
// MatrixKit common imports, shared with all targets
#import "MatrixKit-Bridging-Header.h"
diff --git a/RiotSwiftUI/Modules/Room/LocationSharing/Coordinator/LocationSharingCoordinator.swift b/RiotSwiftUI/Modules/Room/LocationSharing/Coordinator/LocationSharingCoordinator.swift
index 931c6a3d7..471187dd5 100644
--- a/RiotSwiftUI/Modules/Room/LocationSharing/Coordinator/LocationSharingCoordinator.swift
+++ b/RiotSwiftUI/Modules/Room/LocationSharing/Coordinator/LocationSharingCoordinator.swift
@@ -17,7 +17,6 @@
import Foundation
import UIKit
import SwiftUI
-import Keys
struct LocationSharingCoordinatorParameters {
let roomDataSource: MXKRoomDataSource
diff --git a/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift b/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift
index 386471b02..fd4ca6a4a 100644
--- a/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift
+++ b/RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift
@@ -16,7 +16,6 @@
import Foundation
import SwiftUI
-import Keys
import CoreLocation
@available(iOS 14.0, *)
@@ -35,7 +34,7 @@ enum MockLocationSharingScreenState: MockScreenState, CaseIterable {
location = CLLocationCoordinate2D(latitude: 51.4932641, longitude: -0.257096)
}
- let mapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=" + RiotKeys().mapTilerAPIKey)!
+ let mapURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx")!
let viewModel = LocationSharingViewModel(tileServerMapURL: mapURL,
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "", displayName: "Alice"),
location: location)
diff --git a/RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingUserMarkerView.swift b/RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingUserMarkerView.swift
index 0727e0b5b..26bc101d3 100644
--- a/RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingUserMarkerView.swift
+++ b/RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingUserMarkerView.swift
@@ -25,16 +25,20 @@ struct LocationSharingUserMarkerView: View {
@Environment(\.theme) private var theme: ThemeSwiftUI
+ @State private var frame: CGRect = .zero
+
// MARK: Public
let avatarData: AvatarInputProtocol
var body: some View {
- ZStack(alignment: .center) {
+ ZStack {
Image(uiImage: Asset.Images.locationUserMarker.image)
AvatarImage(avatarData: avatarData, size: .large)
- .offset(.init(width: 0.0, height: -1.5))
+ .offset(y: -1.5)
}
+ .background(ViewFrameReader(frame: $frame))
+ .padding(.bottom, frame.height)
.accentColor(theme.colors.accent)
}
}
diff --git a/changelog.d/4208.bugfix b/changelog.d/4208.bugfix
deleted file mode 100644
index 135c79d86..000000000
--- a/changelog.d/4208.bugfix
+++ /dev/null
@@ -1 +0,0 @@
-Fixed home screen not updating properly on theme changes.
\ No newline at end of file
diff --git a/changelog.d/4384.change b/changelog.d/4384.change
deleted file mode 100644
index 13dd82545..000000000
--- a/changelog.d/4384.change
+++ /dev/null
@@ -1 +0,0 @@
-Using mutable room list fetch sort options after chaning them to be a structure. Adaptation to MXStore api changes.
diff --git a/changelog.d/5294.misc b/changelog.d/5294.misc
deleted file mode 100644
index c1a31bb4a..000000000
--- a/changelog.d/5294.misc
+++ /dev/null
@@ -1 +0,0 @@
-Fix graphql warnings in issue workflow automation
diff --git a/changelog.d/5321.feature b/changelog.d/5321.feature
deleted file mode 100644
index 8fc5d69a2..000000000
--- a/changelog.d/5321.feature
+++ /dev/null
@@ -1 +0,0 @@
-Message bubbles: Add settings and build flag.
\ No newline at end of file
diff --git a/changelog.d/5345.change b/changelog.d/5345.change
deleted file mode 100644
index 80ee600a1..000000000
--- a/changelog.d/5345.change
+++ /dev/null
@@ -1 +0,0 @@
-Reduce grace period to report decryption failure
diff --git a/changelog.d/5375.bugfix b/changelog.d/5375.bugfix
deleted file mode 100644
index b8c851286..000000000
--- a/changelog.d/5375.bugfix
+++ /dev/null
@@ -1 +0,0 @@
-Fixes DTMF(dial tones) during voice calls.
diff --git a/changelog.d/pr-5446.misc b/changelog.d/pr-5446.misc
new file mode 100644
index 000000000..cdd5b09d5
--- /dev/null
+++ b/changelog.d/pr-5446.misc
@@ -0,0 +1 @@
+Add WIP to towncrier.
\ No newline at end of file
diff --git a/towncrier.toml b/towncrier.toml
index 2587d18b2..689728cc2 100644
--- a/towncrier.toml
+++ b/towncrier.toml
@@ -39,6 +39,11 @@ template = "changelog.d/_template.md.jinja"
name = "📄 Documentation"
showcontent = true
+[[tool.towncrier.type]]
+ directory = "wip"
+ name = "🚧 In development 🚧"
+ showcontent = true
+
[[tool.towncrier.type]]
directory = "misc"
name = "Others"