mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-20 00:24:43 +02:00
Merge branch 'ismail/5068_design_tweaks' into ismail/5096_thread_notifications
This commit is contained in:
@@ -122,6 +122,8 @@ class ThreadViewController: RoomViewController {
|
||||
}
|
||||
|
||||
MXKPasteboardManager.shared.pasteboard.string = permalink
|
||||
view.vc_toast(message: VectorL10n.roomEventCopyLinkInfo,
|
||||
image: Asset.Images.linkIcon.image)
|
||||
}
|
||||
|
||||
private func sharePermalink() {
|
||||
|
||||
@@ -69,6 +69,10 @@ extension ThreadListCoordinator: ThreadListViewModelCoordinatorDelegate {
|
||||
self.delegate?.threadListCoordinatorDidSelectThread(self, thread: thread)
|
||||
}
|
||||
|
||||
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThread) {
|
||||
self.delegate?.threadListCoordinatorDidSelectRoom(self, roomId: thread.roomId, eventId: thread.id)
|
||||
}
|
||||
|
||||
func threadListViewModelDidCancel(_ viewModel: ThreadListViewModelProtocol) {
|
||||
self.delegate?.threadListCoordinatorDidCancel(self)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import Foundation
|
||||
protocol ThreadListCoordinatorDelegate: AnyObject {
|
||||
func threadListCoordinatorDidLoadThreads(_ coordinator: ThreadListCoordinatorProtocol)
|
||||
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThread)
|
||||
func threadListCoordinatorDidSelectRoom(_ coordinator: ThreadListCoordinatorProtocol, roomId: String, eventId: String)
|
||||
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,5 +25,9 @@ enum ThreadListViewAction {
|
||||
case showFilterTypes
|
||||
case selectFilterType(_ type: ThreadListFilterType)
|
||||
case selectThread(_ index: Int)
|
||||
case longPressThread(_ index: Int)
|
||||
case actionViewInRoom
|
||||
case actionCopyLinkToThread
|
||||
case actionShare
|
||||
case cancel
|
||||
}
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="X8K-NO-SQ3">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<gestureRecognizers/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="V8j-Lb-PgC" id="FCQ-5E-AuZ"/>
|
||||
<outlet property="delegate" destination="V8j-Lb-PgC" id="Kxs-vj-1RW"/>
|
||||
<outletCollection property="gestureRecognizers" destination="OxP-Mp-c6Z" appends="YES" id="371-L6-Skg"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" placeholderIntrinsicWidth="414" placeholderIntrinsicHeight="818" translatesAutoresizingMaskIntoConstraints="NO" id="7VY-m9-wCS" customClass="ThreadListEmptyView" customModule="Riot" customModuleProvider="target">
|
||||
@@ -52,6 +54,11 @@
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="OxP-Mp-c6Z">
|
||||
<connections>
|
||||
<action selector="longPressed:" destination="V8j-Lb-PgC" id="rvv-ml-CSq"/>
|
||||
</connections>
|
||||
</pongPressGestureRecognizer>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-3198.5507246376815" y="-647.54464285714278"/>
|
||||
</scene>
|
||||
|
||||
@@ -147,15 +147,21 @@ final class ThreadListViewController: UIViewController {
|
||||
case .idle:
|
||||
break
|
||||
case .loading:
|
||||
self.renderLoading()
|
||||
renderLoading()
|
||||
case .loaded:
|
||||
self.renderLoaded()
|
||||
renderLoaded()
|
||||
case .empty(let viewModel):
|
||||
self.renderEmptyView(withViewModel: viewModel)
|
||||
renderEmptyView(withViewModel: viewModel)
|
||||
case .showingFilterTypes:
|
||||
self.renderShowingFilterTypes()
|
||||
renderShowingFilterTypes()
|
||||
case .showingLongPressActions:
|
||||
renderShowingLongPressActions()
|
||||
case .share(let string):
|
||||
renderShare(string)
|
||||
case .toastForCopyLink:
|
||||
toastForCopyLink()
|
||||
case .error(let error):
|
||||
self.render(error: error)
|
||||
render(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +176,12 @@ final class ThreadListViewController: UIViewController {
|
||||
threadsTableView.isHidden = false
|
||||
self.threadsTableView.reloadData()
|
||||
navigationItem.rightBarButtonItem?.isEnabled = true
|
||||
switch viewModel.selectedFilterType {
|
||||
case .all:
|
||||
navigationItem.rightBarButtonItem?.image = Asset.Images.threadsFilter.image
|
||||
case .myThreads:
|
||||
navigationItem.rightBarButtonItem?.image = Asset.Images.threadsFilterApplied.image
|
||||
}
|
||||
}
|
||||
|
||||
private func renderEmptyView(withViewModel emptyViewModel: ThreadListEmptyViewModel) {
|
||||
@@ -178,6 +190,12 @@ final class ThreadListViewController: UIViewController {
|
||||
threadsTableView.isHidden = true
|
||||
emptyView.isHidden = false
|
||||
navigationItem.rightBarButtonItem?.isEnabled = viewModel.selectedFilterType == .myThreads
|
||||
switch viewModel.selectedFilterType {
|
||||
case .all:
|
||||
navigationItem.rightBarButtonItem = nil
|
||||
case .myThreads:
|
||||
navigationItem.rightBarButtonItem?.image = Asset.Images.threadsFilterApplied.image
|
||||
}
|
||||
}
|
||||
|
||||
private func renderShowingFilterTypes() {
|
||||
@@ -214,6 +232,49 @@ final class ThreadListViewController: UIViewController {
|
||||
self.present(alertController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
private func renderShowingLongPressActions() {
|
||||
let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
|
||||
controller.addAction(UIAlertAction(title: VectorL10n.roomEventActionViewInRoom,
|
||||
style: .default,
|
||||
handler: { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.viewModel.process(viewAction: .actionViewInRoom)
|
||||
}))
|
||||
|
||||
controller.addAction(UIAlertAction(title: VectorL10n.threadCopyLinkToThread,
|
||||
style: .default,
|
||||
handler: { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.viewModel.process(viewAction: .actionCopyLinkToThread)
|
||||
}))
|
||||
|
||||
controller.addAction(UIAlertAction(title: VectorL10n.roomEventActionShare,
|
||||
style: .default,
|
||||
handler: { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.viewModel.process(viewAction: .actionShare)
|
||||
}))
|
||||
|
||||
controller.addAction(UIAlertAction(title: VectorL10n.cancel,
|
||||
style: .cancel,
|
||||
handler: nil))
|
||||
|
||||
self.present(controller, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
private func renderShare(_ string: String) {
|
||||
let activityVC = UIActivityViewController(activityItems: [string],
|
||||
applicationActivities: nil)
|
||||
activityVC.modalTransitionStyle = .coverVertical
|
||||
present(activityVC, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
private func toastForCopyLink() {
|
||||
view.vc_toast(message: VectorL10n.roomEventCopyLinkInfo,
|
||||
image: Asset.Images.linkIcon.image)
|
||||
}
|
||||
|
||||
private func render(error: Error) {
|
||||
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
|
||||
@@ -225,6 +286,22 @@ final class ThreadListViewController: UIViewController {
|
||||
private func filterButtonTapped(_ sender: UIBarButtonItem) {
|
||||
self.viewModel.process(viewAction: .showFilterTypes)
|
||||
}
|
||||
|
||||
@IBAction private func longPressed(_ sender: UILongPressGestureRecognizer) {
|
||||
guard sender.state == .began else {
|
||||
return
|
||||
}
|
||||
let point = sender.location(in: threadsTableView)
|
||||
guard let indexPath = threadsTableView.indexPathForRow(at: point) else {
|
||||
return
|
||||
}
|
||||
guard let cell = threadsTableView.cellForRow(at: indexPath) else {
|
||||
return
|
||||
}
|
||||
if cell.isHighlighted {
|
||||
viewModel.process(viewAction: .longPressThread(indexPath.row))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -249,10 +326,10 @@ extension ThreadListViewController: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell: ThreadTableViewCell = tableView.dequeueReusableCell(for: indexPath)
|
||||
|
||||
cell.update(theme: theme)
|
||||
if let threadVM = viewModel.threadViewModel(at: indexPath.row) {
|
||||
cell.configure(withViewModel: threadVM)
|
||||
}
|
||||
cell.update(theme: theme)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||
private var roomState: MXRoomState?
|
||||
|
||||
private var currentOperation: MXHTTPOperation?
|
||||
private var longPressedThread: MXThread?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
@@ -73,6 +74,14 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||
loadData()
|
||||
case .selectThread(let index):
|
||||
selectThread(index)
|
||||
case .longPressThread(let index):
|
||||
longPressThread(index)
|
||||
case .actionViewInRoom:
|
||||
actionViewInRoom()
|
||||
case .actionCopyLinkToThread:
|
||||
actionCopyLinkToThread()
|
||||
case .actionShare:
|
||||
actionShare()
|
||||
case .cancel:
|
||||
cancelOperations()
|
||||
coordinatorDelegate?.threadListViewModelDidCancel(self)
|
||||
@@ -103,7 +112,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||
room.displayName))
|
||||
|
||||
let encrpytionBadge: UIImage?
|
||||
if let summary = room.summary, session.crypto != nil {
|
||||
if let summary = room.summary, summary.isEncrypted, session.crypto != nil {
|
||||
encrpytionBadge = EncryptionTrustLevelBadgeImageHelper.roomBadgeImage(for: summary.roomEncryptionTrustLevel())
|
||||
} else {
|
||||
encrpytionBadge = nil
|
||||
@@ -117,14 +126,14 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||
private var emptyViewModel: ThreadListEmptyViewModel {
|
||||
switch selectedFilterType {
|
||||
case .all:
|
||||
return ThreadListEmptyViewModel(icon: Asset.Images.roomContextMenuReplyInThread.image,
|
||||
return ThreadListEmptyViewModel(icon: Asset.Images.threadsIcon.image,
|
||||
title: VectorL10n.threadsEmptyTitle,
|
||||
info: VectorL10n.threadsEmptyInfoAll,
|
||||
tip: VectorL10n.threadsEmptyTip,
|
||||
showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
|
||||
showAllThreadsButtonHidden: true)
|
||||
case .myThreads:
|
||||
return ThreadListEmptyViewModel(icon: Asset.Images.roomContextMenuReplyInThread.image,
|
||||
return ThreadListEmptyViewModel(icon: Asset.Images.threadsIcon.image,
|
||||
title: VectorL10n.threadsEmptyTitle,
|
||||
info: VectorL10n.threadsEmptyInfoMy,
|
||||
tip: VectorL10n.threadsEmptyTip,
|
||||
@@ -180,7 +189,8 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||
lastMessageSenderAvatar: lastAvatarViewData,
|
||||
lastMessageText: lastMessageText)
|
||||
|
||||
return ThreadViewModel(rootMessageSenderAvatar: rootAvatarViewData,
|
||||
return ThreadViewModel(rootMessageSenderUserId: rootMessageSender?.userId,
|
||||
rootMessageSenderAvatar: rootAvatarViewData,
|
||||
rootMessageSenderDisplayName: rootMessageSender?.displayname,
|
||||
rootMessageText: rootMessageText,
|
||||
lastMessageTime: lastMessageTime,
|
||||
@@ -265,6 +275,43 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
|
||||
coordinatorDelegate?.threadListViewModelDidSelectThread(self, thread: thread)
|
||||
}
|
||||
|
||||
private func longPressThread(_ index: Int) {
|
||||
guard index < threads.count else {
|
||||
return
|
||||
}
|
||||
longPressedThread = threads[index]
|
||||
viewState = .showingLongPressActions
|
||||
}
|
||||
|
||||
private func actionViewInRoom() {
|
||||
guard let thread = longPressedThread else {
|
||||
return
|
||||
}
|
||||
coordinatorDelegate?.threadListViewModelDidSelectThreadViewInRoom(self, thread: thread)
|
||||
longPressedThread = nil
|
||||
}
|
||||
|
||||
private func actionCopyLinkToThread() {
|
||||
guard let thread = longPressedThread else {
|
||||
return
|
||||
}
|
||||
if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId) {
|
||||
MXKPasteboardManager.shared.pasteboard.string = permalink
|
||||
viewState = .toastForCopyLink
|
||||
}
|
||||
longPressedThread = nil
|
||||
}
|
||||
|
||||
private func actionShare() {
|
||||
guard let thread = longPressedThread else {
|
||||
return
|
||||
}
|
||||
if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId) {
|
||||
viewState = .share(permalink)
|
||||
}
|
||||
longPressedThread = nil
|
||||
}
|
||||
|
||||
private func cancelOperations() {
|
||||
self.currentOperation?.cancel()
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ protocol ThreadListViewModelViewDelegate: AnyObject {
|
||||
protocol ThreadListViewModelCoordinatorDelegate: AnyObject {
|
||||
func threadListViewModelDidLoadThreads(_ viewModel: ThreadListViewModelProtocol)
|
||||
func threadListViewModelDidSelectThread(_ viewModel: ThreadListViewModelProtocol, thread: MXThread)
|
||||
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThread)
|
||||
func threadListViewModelDidCancel(_ viewModel: ThreadListViewModelProtocol)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,5 +25,8 @@ enum ThreadListViewState {
|
||||
case loaded
|
||||
case empty(_ viewModel: ThreadListEmptyViewModel)
|
||||
case showingFilterTypes
|
||||
case showingLongPressActions
|
||||
case share(_ string: String)
|
||||
case toastForCopyLink
|
||||
case error(Error)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ class ThreadTableViewCell: UITableViewCell {
|
||||
@IBOutlet private weak var lastMessageTimeLabel: UILabel!
|
||||
@IBOutlet private weak var summaryView: ThreadSummaryView!
|
||||
@IBOutlet private weak var notificationStatusView: ThreadNotificationStatusView!
|
||||
|
||||
private static var usernameColorGenerator: UserNameColorGenerator = {
|
||||
let generator = UserNameColorGenerator()
|
||||
return generator
|
||||
}()
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
@@ -42,6 +47,11 @@ class ThreadTableViewCell: UITableViewCell {
|
||||
} else {
|
||||
rootMessageAvatarView.avatarImageView.image = nil
|
||||
}
|
||||
if let senderUserId = viewModel.rootMessageSenderUserId {
|
||||
rootMessageSenderLabel.textColor = Self.usernameColorGenerator.color(from: senderUserId)
|
||||
} else {
|
||||
rootMessageSenderLabel.textColor = Self.usernameColorGenerator.defaultColor
|
||||
}
|
||||
rootMessageSenderLabel.text = viewModel.rootMessageSenderDisplayName
|
||||
rootMessageContentLabel.attributedText = viewModel.rootMessageText
|
||||
lastMessageTimeLabel.text = viewModel.lastMessageTime
|
||||
@@ -58,6 +68,8 @@ extension ThreadTableViewCell: NibReusable {}
|
||||
extension ThreadTableViewCell: Themable {
|
||||
|
||||
func update(theme: Theme) {
|
||||
Self.usernameColorGenerator.defaultColor = theme.colors.primaryContent
|
||||
Self.usernameColorGenerator.userNameColors = theme.colors.namesAndAvatars
|
||||
rootMessageAvatarView.backgroundColor = .clear
|
||||
rootMessageContentLabel.textColor = theme.colors.primaryContent
|
||||
lastMessageTimeLabel.textColor = theme.colors.secondaryContent
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="104" id="KGk-i7-Jjw" customClass="ThreadTableViewCell" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="104"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="100" id="KGk-i7-Jjw" customClass="ThreadTableViewCell" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="104"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="I32-A5-WWw" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
@@ -26,14 +26,14 @@
|
||||
<constraint firstAttribute="height" constant="32" id="uWM-eP-XnP"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="108-Xh-aZf">
|
||||
<rect key="frame" x="56" y="12" width="200" height="17"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="108-Xh-aZf">
|
||||
<rect key="frame" x="56" y="12" width="201" height="17"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" text="Time" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C2U-Ih-4Oh">
|
||||
<rect key="frame" x="264" y="13" width="28" height="15"/>
|
||||
<rect key="frame" x="265" y="14" width="28" height="15"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -52,14 +52,17 @@
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Message" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xzR-f9-3qV">
|
||||
<rect key="frame" x="56" y="33" width="236" height="17"/>
|
||||
<rect key="frame" x="56" y="33" width="236" height="15"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Md3-uq-cSB" customClass="ThreadSummaryView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="47" y="58" width="245" height="34"/>
|
||||
<rect key="frame" x="47" y="56" width="245" height="32"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="32" id="Pnm-yi-36O"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
@@ -76,9 +79,9 @@
|
||||
<constraint firstItem="aUq-D2-1KM" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="17" id="rvj-qg-S3J"/>
|
||||
<constraint firstItem="108-Xh-aZf" firstAttribute="leading" secondItem="I32-A5-WWw" secondAttribute="trailing" constant="12" id="sXf-FI-gD3"/>
|
||||
<constraint firstItem="xzR-f9-3qV" firstAttribute="top" secondItem="108-Xh-aZf" secondAttribute="bottom" constant="4" id="tQN-Rr-MIS"/>
|
||||
<constraint firstItem="C2U-Ih-4Oh" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="13" id="u3s-nr-avO"/>
|
||||
<constraint firstItem="C2U-Ih-4Oh" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="14" id="u3s-nr-avO"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Md3-uq-cSB" secondAttribute="trailing" constant="28" id="vxt-vD-jy8"/>
|
||||
<constraint firstAttribute="trailing" secondItem="C2U-Ih-4Oh" secondAttribute="trailing" constant="28" id="wNc-xV-uIR"/>
|
||||
<constraint firstAttribute="trailing" secondItem="C2U-Ih-4Oh" secondAttribute="trailing" constant="27" id="wNc-xV-uIR"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
@@ -90,7 +93,7 @@
|
||||
<outlet property="rootMessageSenderLabel" destination="108-Xh-aZf" id="nUc-qK-UCD"/>
|
||||
<outlet property="summaryView" destination="Md3-uq-cSB" id="3ye-77-1m6"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="2.8985507246376816" y="129.91071428571428"/>
|
||||
<point key="canvasLocation" x="2.8985507246376816" y="127.23214285714285"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import Foundation
|
||||
|
||||
struct ThreadViewModel {
|
||||
var rootMessageSenderUserId: String?
|
||||
var rootMessageSenderAvatar: AvatarViewDataProtocol?
|
||||
var rootMessageSenderDisplayName: String?
|
||||
var rootMessageText: NSAttributedString?
|
||||
|
||||
@@ -64,6 +64,7 @@ extension ThreadListEmptyView: Themable {
|
||||
|
||||
func update(theme: Theme) {
|
||||
iconBackgroundView.backgroundColor = theme.colors.system
|
||||
iconView.tintColor = theme.colors.secondaryContent
|
||||
titleLabel.textColor = theme.colors.primaryContent
|
||||
infoLabel.textColor = theme.colors.secondaryContent
|
||||
tipLabel.textColor = theme.colors.secondaryContent
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?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"/>
|
||||
<device id="retina3_5" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||
@@ -20,23 +20,23 @@
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="437" height="540"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="313" height="540"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="f50-47-PNo">
|
||||
<rect key="frame" x="20" y="126" width="397" height="288"/>
|
||||
<rect key="frame" x="20" y="108" width="273" height="324"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lm2-HJ-sTN">
|
||||
<rect key="frame" x="78.5" y="0.0" width="240" height="1"/>
|
||||
<rect key="frame" x="16.5" y="0.0" width="240" height="1"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="SCQ-dJ-7RE"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TO4-Bz-2iH">
|
||||
<rect key="frame" x="166.5" y="21" width="64" height="64"/>
|
||||
<rect key="frame" x="104.5" y="21" width="64" height="64"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="room_context_menu_reply_in_thread" translatesAutoresizingMaskIntoConstraints="NO" id="96m-sr-xQJ">
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="threads_icon" translatesAutoresizingMaskIntoConstraints="NO" id="96m-sr-xQJ">
|
||||
<rect key="frame" x="16" y="16" width="32" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="K7U-U0-prN"/>
|
||||
@@ -57,33 +57,33 @@
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Keep discussions organised with threads" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0q6-zY-VZH">
|
||||
<rect key="frame" x="27.5" y="105" width="342.5" height="21.5"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Keep discussions organised with threads" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0q6-zY-VZH">
|
||||
<rect key="frame" x="17.5" y="105" width="238" height="43"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Threads help keep your conversations on-topic and easy to track." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OE7-gq-abZ">
|
||||
<rect key="frame" x="3" y="146.5" width="391.5" height="36"/>
|
||||
<rect key="frame" x="4.5" y="168" width="264.5" height="36"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tip: Use “Thread” option when selecting a message." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RyB-Ah-jey">
|
||||
<rect key="frame" x="50.5" y="202.5" width="296.5" height="14.5"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tip: Use “Thread” option when selecting a message." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RyB-Ah-jey">
|
||||
<rect key="frame" x="20.5" y="224" width="232.5" height="29"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uTW-xb-Z9y">
|
||||
<rect key="frame" x="142" y="237" width="113" height="30"/>
|
||||
<rect key="frame" x="80" y="273" width="113" height="30"/>
|
||||
<state key="normal" title="Show all threads"/>
|
||||
<connections>
|
||||
<action selector="showAllThreadsButtonTapped:" destination="-1" eventType="touchUpInside" id="cX4-am-oWF"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TKE-Zn-n2Q">
|
||||
<rect key="frame" x="78.5" y="287" width="240" height="1"/>
|
||||
<rect key="frame" x="16.5" y="323" width="240" height="1"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="oXf-fF-mRt"/>
|
||||
@@ -101,10 +101,10 @@
|
||||
<constraint firstItem="f50-47-PNo" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="gnS-Sc-jsF"/>
|
||||
</constraints>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="-100.72463768115942" y="-9.375"/>
|
||||
<point key="canvasLocation" x="-218.4375" y="-10"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="room_context_menu_reply_in_thread" width="18" height="18"/>
|
||||
<image name="threads_icon" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -151,6 +151,10 @@ extension ThreadsCoordinator: ThreadListCoordinatorDelegate {
|
||||
self.add(childCoordinator: roomCoordinator)
|
||||
}
|
||||
|
||||
func threadListCoordinatorDidSelectRoom(_ coordinator: ThreadListCoordinatorProtocol, roomId: String, eventId: String) {
|
||||
self.delegate?.threadsCoordinatorDidSelect(self, roomId: roomId, eventId: eventId)
|
||||
}
|
||||
|
||||
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol) {
|
||||
self.delegate?.threadsCoordinatorDidComplete(self)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user