mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-02 06:06:57 +02:00
Merge branch 'develop' into ismail/5096_thread_notifications
This commit is contained in:
@@ -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 {
|
||||
|
||||
|
||||
@@ -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<MXKViewControllerActivityHandling> *homeViewController = (UIViewController<MXKViewControllerActivityHandling>*)_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<MXKViewControllerActivityHandling> *homeViewController = (UIViewController<MXKViewControllerActivityHandling>*)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];
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
|
||||
eventId:eventId
|
||||
mxSession:session
|
||||
threadParameters:nil
|
||||
threadParameters:nil
|
||||
presentationParameters:presentationParameters];
|
||||
|
||||
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
|
||||
|
||||
@@ -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]
|
||||
]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
|
||||
eventId:nil
|
||||
mxSession:mxSession
|
||||
threadParameters:nil
|
||||
threadParameters:nil
|
||||
presentationParameters:presentationParameters];
|
||||
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
|
||||
}
|
||||
|
||||
+19
-1
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)";
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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ę";
|
||||
|
||||
@@ -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).";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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" = "надсилає дані про своє місцеперебування.";
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
|
||||
#import "MXKRoomInputToolbarView.h"
|
||||
#import "MXKImageView.h"
|
||||
#import "MXKRoomBubbleCellData.h"
|
||||
|
||||
@@ -169,4 +169,11 @@
|
||||
*/
|
||||
- (MXKRoomBubbleComponent*)getFirstBubbleComponentWithDisplay;
|
||||
|
||||
/**
|
||||
Get the last visible component.
|
||||
|
||||
@return Last visible component or nil.
|
||||
*/
|
||||
- (MXKRoomBubbleComponent*)getLastBubbleComponentWithDisplay;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -118,14 +118,14 @@
|
||||
@protocol RoomDataSourceDelegate <MXKDataSourceDelegate>
|
||||
|
||||
/**
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -383,6 +383,8 @@ const CGFloat kTypingCellHeight = 24;
|
||||
|
||||
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
|
||||
id<RoomTimelineCellDecorator> 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<BubbleCellReactionsDisplayable> reactionsDisplayable = (id<BubbleCellReactionsDisplayable>)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<BubbleCellThreadSummaryDisplayable> threadSummaryDisplayable = (id<BubbleCellThreadSummaryDisplayable>)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<BubbleCellReadReceiptsDisplayable> readReceiptsDisplayable = (id<BubbleCellReadReceiptsDisplayable>)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<MXKRoomBubbleCellDataStoring> cellData = [self cellDataOfEventWithEventId:eventId];
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import UIKit
|
||||
import Reusable
|
||||
import Mapbox
|
||||
|
||||
class LocationUserMarkerView: MGLAnnotationView, NibLoadable {
|
||||
class LocationMarkerView: MGLAnnotationView, NibLoadable {
|
||||
|
||||
@IBOutlet private var avatarView: UserAvatarView!
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="iN0-l3-epB" customClass="LocationMarkerView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="108"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GS1-Cw-Ezx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_user_marker" translatesAutoresizingMaskIntoConstraints="NO" id="ldO-kc-R5W">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="50" id="41S-fj-tn4"/>
|
||||
<constraint firstAttribute="height" constant="54" id="MAX-5E-xvS"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_marker_icon" translatesAutoresizingMaskIntoConstraints="NO" id="gQe-Hv-22e">
|
||||
<rect key="frame" x="13" y="15" width="24" height="24"/>
|
||||
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="XuF-VU-qG2"/>
|
||||
<constraint firstAttribute="height" constant="24" id="ejE-pC-umv"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qut-wn-BX3" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="2" y="2" width="46" height="46"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="46" id="BjG-I5-n8f"/>
|
||||
<constraint firstAttribute="width" constant="46" id="W3F-Aw-FO3"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="ldO-kc-R5W" firstAttribute="top" secondItem="GS1-Cw-Ezx" secondAttribute="top" id="1cb-YG-bcI"/>
|
||||
<constraint firstItem="ldO-kc-R5W" firstAttribute="leading" secondItem="GS1-Cw-Ezx" secondAttribute="leading" id="8I8-Zn-R5S"/>
|
||||
<constraint firstItem="gQe-Hv-22e" firstAttribute="centerY" secondItem="GS1-Cw-Ezx" secondAttribute="centerY" id="EE9-rM-y0V"/>
|
||||
<constraint firstItem="qut-wn-BX3" firstAttribute="centerY" secondItem="GS1-Cw-Ezx" secondAttribute="centerY" constant="-2" id="EQM-Hr-37h"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ldO-kc-R5W" secondAttribute="trailing" id="QUB-rY-t4j"/>
|
||||
<constraint firstItem="qut-wn-BX3" firstAttribute="centerX" secondItem="GS1-Cw-Ezx" secondAttribute="centerX" id="XLg-Qs-yTR"/>
|
||||
<constraint firstAttribute="bottom" secondItem="ldO-kc-R5W" secondAttribute="bottom" id="l4H-nN-44g"/>
|
||||
<constraint firstItem="gQe-Hv-22e" firstAttribute="centerX" secondItem="GS1-Cw-Ezx" secondAttribute="centerX" id="syG-Kp-4F9"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="GS1-Cw-Ezx" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="61F-Ve-exC"/>
|
||||
<constraint firstAttribute="trailing" secondItem="GS1-Cw-Ezx" secondAttribute="trailing" id="H8I-4T-A0M"/>
|
||||
<constraint firstItem="GS1-Cw-Ezx" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="hhI-gR-E5z"/>
|
||||
<constraint firstAttribute="bottom" secondItem="GS1-Cw-Ezx" secondAttribute="bottom" constant="54" id="mvD-6W-gMh"/>
|
||||
</constraints>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="avatarView" destination="qut-wn-BX3" id="wHA-bz-A2y"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="58.695652173913047" y="4.6875"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="location_marker_icon" width="24" height="24"/>
|
||||
<image name="location_user_marker" width="51" height="54.5"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="LocationUserMarkerView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_user_marker" translatesAutoresizingMaskIntoConstraints="NO" id="ldO-kc-R5W">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qut-wn-BX3" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="2" y="2" width="46" height="46"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="ldO-kc-R5W" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="VF5-CP-8eH"/>
|
||||
<constraint firstItem="ldO-kc-R5W" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Voc-LH-fTw"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ldO-kc-R5W" secondAttribute="trailing" id="Vt0-UN-s20"/>
|
||||
<constraint firstAttribute="bottom" secondItem="ldO-kc-R5W" secondAttribute="bottom" id="Ybf-8x-UaG"/>
|
||||
</constraints>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="avatarView" destination="qut-wn-BX3" id="wHA-bz-A2y"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-84.057971014492765" y="-80.357142857142847"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="location_user_marker" width="51" height="54.5"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="descriptionContainerView" destination="oVd-gS-Rmb" id="Npu-jp-oYo"/>
|
||||
<outlet property="descriptionIcon" destination="GP2-dA-giJ" id="7YL-UU-ClT"/>
|
||||
<outlet property="descriptionLabel" destination="c68-l7-McA" id="HiH-8Q-yTp"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="165.94202898550725" y="-100.78125"/>
|
||||
|
||||
+1
-79
@@ -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<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
|
||||
{
|
||||
Class cellViewClass = nil;
|
||||
|
||||
// Sanity check
|
||||
if ([cellData conformsToProtocol:@protocol(MXKRoomBubbleCellDataStoring)])
|
||||
{
|
||||
id<MXKRoomBubbleCellDataStoring> bubbleData = (id<MXKRoomBubbleCellDataStoring>)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
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, RoomParticipantsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
|
||||
ReactionsMenuViewModelCoordinatorDelegate, EditHistoryCoordinatorBridgePresenterDelegate, MXKDocumentPickerPresenterDelegate, EmojiPickerCoordinatorBridgePresenterDelegate,
|
||||
ReactionHistoryCoordinatorBridgePresenterDelegate, CameraPresenterDelegate, MediaPickerCoordinatorBridgePresenterDelegate,
|
||||
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, RoomCoordinatorBridgePresenterDelegate, ThreadsCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate>
|
||||
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<MXKCellRendering>)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<MXKRoomBubbleCellDataStoring> bubbleData = (id<MXKRoomBubbleCellDataStoring>)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
|
||||
|
||||
@@ -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]
|
||||
]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
@@ -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
|
||||
+10
@@ -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
|
||||
+3
-2
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -128,6 +128,7 @@
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="OrM-nA-kyg" id="Frc-ED-PlH"/>
|
||||
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
|
||||
<outlet property="attachViewLeadingConstraint" destination="p93-5h-lvW" id="WRx-S5-r3M"/>
|
||||
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
|
||||
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
|
||||
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
|
||||
|
||||
+3
-2
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -161,6 +161,7 @@
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="jmK-pe-WZd" id="F7y-hE-pcg"/>
|
||||
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
|
||||
<outlet property="attachViewLeadingConstraint" destination="6mM-Ag-m0K" id="lG4-bl-Kio"/>
|
||||
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
|
||||
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
|
||||
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
|
||||
|
||||
+24
@@ -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
|
||||
+32
@@ -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
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WmY-Jw-mqv" customClass="RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="120"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WmY-Jw-mqv" id="ef1-Tq-U3Z">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="120"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SFg-55-RF4" userLabel="Pagination Title View">
|
||||
<rect key="frame" x="56" y="10" width="534" height="24"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wkY-7Y-sGw" userLabel="Pagination Label">
|
||||
<rect key="frame" x="0.0" y="0.0" width="524" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="18" id="PiZ-Ag-oxc"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0kR-4b-Wav" userLabel="Pagination Separator View">
|
||||
<rect key="frame" x="0.0" y="23" width="534" height="1"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="PaginationTitleView"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="wkY-7Y-sGw" secondAttribute="trailing" constant="10" id="4DU-xA-diS"/>
|
||||
<constraint firstItem="wkY-7Y-sGw" firstAttribute="top" secondItem="SFg-55-RF4" secondAttribute="top" id="6Cz-bj-kUg"/>
|
||||
<constraint firstItem="0kR-4b-Wav" firstAttribute="top" secondItem="wkY-7Y-sGw" secondAttribute="bottom" constant="5" id="K4B-zf-5x2"/>
|
||||
<constraint firstAttribute="height" constant="24" id="Qo9-cw-LCa"/>
|
||||
<constraint firstAttribute="trailing" secondItem="0kR-4b-Wav" secondAttribute="trailing" id="fnd-bR-QmB"/>
|
||||
<constraint firstAttribute="bottom" secondItem="0kR-4b-Wav" secondAttribute="bottom" id="pBK-pC-oCA"/>
|
||||
<constraint firstItem="0kR-4b-Wav" firstAttribute="leading" secondItem="SFg-55-RF4" secondAttribute="leading" id="rhH-Hz-w9J"/>
|
||||
<constraint firstItem="wkY-7Y-sGw" firstAttribute="leading" secondItem="SFg-55-RF4" secondAttribute="leading" id="uq9-MP-Dmm"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="hgp-Z5-rAj" userLabel="Picture View" customClass="MXKImageView">
|
||||
<rect key="frame" x="13" y="54" width="30" height="30"/>
|
||||
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="PictureView"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="NQk-ck-Lo8"/>
|
||||
<constraint firstAttribute="height" constant="30" id="dNT-QU-CUG"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="5IE-JS-uf3" userLabel="Attachment View" customClass="MXKImageView">
|
||||
<rect key="frame" x="56" y="45" width="192" height="65"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="AttachmentView"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="192" id="9zO-jU-qTb"/>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="34" id="C5F-6D-LZx"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="K9X-gn-noF" userLabel="File Type Image View">
|
||||
<rect key="frame" x="56" y="45" width="32" height="32"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="FileTypeImageView"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="OE8-oh-B7Q"/>
|
||||
<constraint firstAttribute="height" constant="32" id="jJB-zj-fbT"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Cot-3X-2cU" userLabel="Play Icon Image View">
|
||||
<rect key="frame" x="136" y="61.5" width="32" height="32"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="PlayIconImageView"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="32" id="8io-Wk-GzF"/>
|
||||
<constraint firstAttribute="width" constant="32" id="aeJ-j3-rfX"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="jmK-pe-WZd">
|
||||
<rect key="frame" x="142" y="67.5" width="20" height="20"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="ActivityIndicator"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</activityIndicatorView>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW">
|
||||
<rect key="frame" x="515" y="54" width="70" height="66"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="BubbleInfoContainer"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="70" id="tLr-6k-ArA"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fdx-qs-8en" userLabel="ProgressView">
|
||||
<rect key="frame" x="487" y="50" width="100" height="70"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="70" id="5w2-Hm-hZx"/>
|
||||
<constraint firstAttribute="width" constant="100" id="ryE-fW-SgG"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3b7-4a-YL0">
|
||||
<rect key="frame" x="8" y="3" width="584" height="114"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="3b7-4a-YL0" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="topMargin" constant="-8" id="10i-70-PDz"/>
|
||||
<constraint firstItem="hgp-Z5-rAj" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="54" id="2Ih-ga-N9s"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="13" id="6mM-Ag-m0K"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="45" id="96U-67-5TP"/>
|
||||
<constraint firstAttribute="bottom" secondItem="fdx-qs-8en" secondAttribute="bottom" id="AeT-4F-mKp"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="Cot-3X-2cU" secondAttribute="centerY" id="H5t-l6-fL1"/>
|
||||
<constraint firstItem="SFg-55-RF4" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="56" id="I4N-5Q-LFe"/>
|
||||
<constraint firstItem="jmK-pe-WZd" firstAttribute="centerX" secondItem="5IE-JS-uf3" secondAttribute="centerX" id="IoK-NR-EyQ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="5IE-JS-uf3" secondAttribute="bottom" constant="10" id="SHN-tC-zsJ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="IOg-Kt-8vW" secondAttribute="bottom" id="TPw-iE-nii"/>
|
||||
<constraint firstItem="IOg-Kt-8vW" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="54" id="XSL-TG-m62"/>
|
||||
<constraint firstItem="3b7-4a-YL0" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leadingMargin" constant="-8" id="aGh-ad-trR"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="3b7-4a-YL0" secondAttribute="trailing" constant="-8" id="abE-n9-N8T"/>
|
||||
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="15" id="hQV-lO-7aQ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="SFg-55-RF4" secondAttribute="trailing" constant="10" id="jvR-oT-EQF"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="K9X-gn-noF" secondAttribute="leading" id="p93-5h-lvW"/>
|
||||
<constraint firstItem="jmK-pe-WZd" firstAttribute="centerY" secondItem="5IE-JS-uf3" secondAttribute="centerY" id="qqJ-jh-rGK"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerX" secondItem="Cot-3X-2cU" secondAttribute="centerX" id="sF7-QL-vdj"/>
|
||||
<constraint firstItem="hgp-Z5-rAj" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="13" id="tuw-aU-ncu"/>
|
||||
<constraint firstItem="SFg-55-RF4" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="10" id="wJX-7V-bJB"/>
|
||||
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="K9X-gn-noF" secondAttribute="top" id="wkX-zQ-iQS"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="3b7-4a-YL0" secondAttribute="bottom" constant="-8" id="wpa-8Z-Gy3"/>
|
||||
<constraint firstAttribute="trailing" secondItem="fdx-qs-8en" secondAttribute="trailing" constant="13" id="xKk-Gz-moE"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="RoomBubbleCell"/>
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="jmK-pe-WZd" id="F7y-hE-pcg"/>
|
||||
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
|
||||
<outlet property="attachViewLeadingConstraint" destination="6mM-Ag-m0K" id="lG4-bl-Kio"/>
|
||||
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
|
||||
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
|
||||
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
|
||||
<outlet property="attachmentView" destination="5IE-JS-uf3" id="imT-1z-hR1"/>
|
||||
<outlet property="bubbleInfoContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
|
||||
<outlet property="bubbleInfoContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
|
||||
<outlet property="bubbleOverlayContainer" destination="3b7-4a-YL0" id="KNb-h4-YHD"/>
|
||||
<outlet property="fileTypeIconView" destination="K9X-gn-noF" id="4Pj-bc-3gk"/>
|
||||
<outlet property="paginationLabel" destination="wkY-7Y-sGw" id="9Uh-tX-t0I"/>
|
||||
<outlet property="paginationSeparatorView" destination="0kR-4b-Wav" id="c7x-Sh-aj6"/>
|
||||
<outlet property="paginationTitleView" destination="SFg-55-RF4" id="mbP-6I-gOn"/>
|
||||
<outlet property="pictureView" destination="hgp-Z5-rAj" id="rKM-QG-RJN"/>
|
||||
<outlet property="playIconView" destination="Cot-3X-2cU" id="KEF-KK-Og1"/>
|
||||
<outlet property="progressView" destination="fdx-qs-8en" id="V7E-pn-Xze"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-26" y="113"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
+3
-2
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -95,6 +95,7 @@
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="8Bq-Mk-bN8" id="cbT-lK-yjP"/>
|
||||
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
|
||||
<outlet property="attachViewLeadingConstraint" destination="bSL-lG-ued" id="M5E-Ot-73d"/>
|
||||
<outlet property="attachViewMinHeightConstraint" destination="Uqr-7d-0dv" id="UIs-4K-np5"/>
|
||||
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
|
||||
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
|
||||
|
||||
+11
@@ -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];
|
||||
@@ -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() {
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
])
|
||||
}
|
||||
}
|
||||
+230
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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<NSNumber*, Class>*)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<NSNumber*, Class>*)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
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -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
|
||||
}
|
||||
}
|
||||
+74
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+197
@@ -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<AnyHashable>) {
|
||||
cell.updateTickView(withFailedEventIds: failedEventIds)
|
||||
}
|
||||
}
|
||||
@@ -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<RoomTimelineCellProvider>
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping;
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -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<NSNumber*, Class>* 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<MXKCellRendering>)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<NSNumber*, Class>*)buildCellClasses
|
||||
{
|
||||
NSMutableDictionary<NSNumber*, Class>* 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<NSNumber*, Class>*)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<NSNumber*, Class>*)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<NSNumber*, Class>*)incomingAttachmentCellsMapping
|
||||
{
|
||||
return @{
|
||||
// Clear
|
||||
@(RoomTimelineCellIdentifierIncomingAttachment) : RoomIncomingAttachmentBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo) : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle) : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class,
|
||||
// Encrypted
|
||||
@(RoomTimelineCellIdentifierIncomingAttachmentEncrypted) : RoomIncomingEncryptedAttachmentBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo) : RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle) : RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping
|
||||
{
|
||||
return @{
|
||||
// Clear
|
||||
@(RoomTimelineCellIdentifierOutgoingAttachment) : RoomOutgoingAttachmentBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle) : RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class,
|
||||
// Encrypted
|
||||
@(RoomTimelineCellIdentifierOutgoingAttachmentEncrypted) : RoomOutgoingEncryptedAttachmentBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle) : RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)membershipCellsMapping
|
||||
{
|
||||
return @{
|
||||
@(RoomTimelineCellIdentifierMembership) : RoomMembershipBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierMembershipWithPaginationTitle) : RoomMembershipWithPaginationTitleBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierMembershipCollapsed) : RoomMembershipCollapsedBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle) : RoomMembershipCollapsedWithPaginationTitleBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierMembershipExpanded) : RoomMembershipExpandedBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle) : RoomMembershipExpandedWithPaginationTitleBubbleCell.class,
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)keyVerificationCellsMapping
|
||||
{
|
||||
return @{
|
||||
@(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval) : KeyVerificationIncomingRequestApprovalBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle) : KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierKeyVerificationRequestStatus) : KeyVerificationRequestStatusBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle) : KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierKeyVerificationConclusion) : KeyVerificationConclusionBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle) : KeyVerificationConclusionWithPaginationTitleBubbleCell.class,
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)roomCreationCellsMapping
|
||||
{
|
||||
return @{
|
||||
@(RoomTimelineCellIdentifierRoomCreationCollapsed) : RoomCreationCollapsedBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle) : RoomCreationWithPaginationCollapsedBubbleCell.class,
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)callCellsMapping
|
||||
{
|
||||
return @{
|
||||
@(RoomTimelineCellIdentifierDirectCallStatus) : RoomDirectCallStatusBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierGroupCallStatus) : RoomGroupCallStatusBubbleCell.class,
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)voiceMessageCellsMapping
|
||||
{
|
||||
return @{
|
||||
@(RoomTimelineCellIdentifierVoiceMessage) : VoiceMessageBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo) : VoiceMessageWithoutSenderInfoBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle) : VoiceMessageWithPaginationTitleBubbleCell.class,
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)pollCellsMapping
|
||||
{
|
||||
return @{
|
||||
@(RoomTimelineCellIdentifierPoll) : PollBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierPollWithoutSenderInfo) : PollWithoutSenderInfoBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierPollWithPaginationTitle) : PollWithPaginationTitleBubbleCell.class,
|
||||
};
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber*, Class>*)locationCellsMapping
|
||||
{
|
||||
return @{
|
||||
@(RoomTimelineCellIdentifierLocation) : LocationBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierLocationWithoutSenderInfo) : LocationWithoutSenderInfoBubbleCell.class,
|
||||
@(RoomTimelineCellIdentifierLocationWithPaginationTitle) : LocationWithPaginationTitleBubbleCell.class
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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<AnyHashable>)
|
||||
}
|
||||
@@ -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 <UIKit/UIKit.h>
|
||||
|
||||
#import "RoomTimelineCellIdentifier.h"
|
||||
#import "MXKCellRendering.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// Enables to register and provide room timeline cells
|
||||
@protocol RoomTimelineCellProvider <NSObject>
|
||||
|
||||
/// Register timeline cells for the given table view
|
||||
- (void)registerCellsForTableView:(UITableView*)tableView;
|
||||
|
||||
/// Get timeline cell class from cell identifier
|
||||
- (Class<MXKCellRendering>)cellViewClassForCellIdentifier:(RoomTimelineCellIdentifier)identifier;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -17,7 +17,8 @@
|
||||
import Foundation
|
||||
|
||||
/// Represents the room timeline style identifiers available
|
||||
enum RoomTimelineStyleIdentifier {
|
||||
@objc
|
||||
enum RoomTimelineStyleIdentifier: Int {
|
||||
case plain
|
||||
case bubble
|
||||
}
|
||||
|
||||
+11
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user