mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-18 21:52:18 +02:00
Merge pull request #2549 from vector-im/riot_2510
Reactions: Show at most 8 reactions
This commit is contained in:
@@ -75,6 +75,8 @@
|
||||
32891D712264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32891D6F2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift */; };
|
||||
32891D75226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */; };
|
||||
32891D76226728EF00C82226 /* DeviceVerificationDataLoadingViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */; };
|
||||
329E746622CD02EA006F9797 /* BubbleReactionActionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 329E746422CD02EA006F9797 /* BubbleReactionActionViewCell.xib */; };
|
||||
329E746722CD02EA006F9797 /* BubbleReactionActionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 329E746522CD02EA006F9797 /* BubbleReactionActionViewCell.swift */; };
|
||||
32A6001622C661100042C1D9 /* EditHistoryViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6000D22C661100042C1D9 /* EditHistoryViewState.swift */; };
|
||||
32A6001722C661100042C1D9 /* EditHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6000E22C661100042C1D9 /* EditHistoryViewController.swift */; };
|
||||
32A6001822C661100042C1D9 /* EditHistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6000F22C661100042C1D9 /* EditHistoryViewModel.swift */; };
|
||||
@@ -617,6 +619,8 @@
|
||||
32891D6F2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationVerifiedViewController.swift; sourceTree = "<group>"; };
|
||||
32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationDataLoadingViewController.swift; sourceTree = "<group>"; };
|
||||
32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DeviceVerificationDataLoadingViewController.storyboard; sourceTree = "<group>"; };
|
||||
329E746422CD02EA006F9797 /* BubbleReactionActionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BubbleReactionActionViewCell.xib; sourceTree = "<group>"; };
|
||||
329E746522CD02EA006F9797 /* BubbleReactionActionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionActionViewCell.swift; sourceTree = "<group>"; };
|
||||
32A6000D22C661100042C1D9 /* EditHistoryViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewState.swift; sourceTree = "<group>"; };
|
||||
32A6000E22C661100042C1D9 /* EditHistoryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewController.swift; sourceTree = "<group>"; };
|
||||
32A6000F22C661100042C1D9 /* EditHistoryViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewModel.swift; sourceTree = "<group>"; };
|
||||
@@ -2001,6 +2005,8 @@
|
||||
B1963B24228F1C4800CBA17F /* BubbleReactions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
329E746522CD02EA006F9797 /* BubbleReactionActionViewCell.swift */,
|
||||
329E746422CD02EA006F9797 /* BubbleReactionActionViewCell.xib */,
|
||||
B1963B31228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift */,
|
||||
B1963B27228F1C4800CBA17F /* BubbleReactionsViewModel.swift */,
|
||||
B1963B25228F1C4800CBA17F /* BubbleReactionsView.swift */,
|
||||
@@ -3607,6 +3613,7 @@
|
||||
B1B5574320EE6C4D00210D55 /* CallViewController.xib in Resources */,
|
||||
F083BDEA1E7009ED00A9B29C /* ringback.mp3 in Resources */,
|
||||
F083BDF21E7009ED00A9B29C /* GoogleService-Info.plist in Resources */,
|
||||
329E746622CD02EA006F9797 /* BubbleReactionActionViewCell.xib in Resources */,
|
||||
B1B558E320EF768F00210D55 /* RoomEmptyBubbleCell.xib in Resources */,
|
||||
B1E5368F21FB7258001F3AFF /* KeyBackupRecoverFromPassphraseViewController.storyboard in Resources */,
|
||||
B1B5590420EF768F00210D55 /* RoomOutgoingAttachmentBubbleCell.xib in Resources */,
|
||||
@@ -4098,6 +4105,7 @@
|
||||
32A6001A22C661100042C1D9 /* EditHistoryCoordinator.swift in Sources */,
|
||||
F083BD1E1E7009ED00A9B29C /* AppDelegate.m in Sources */,
|
||||
B1B558E620EF768F00210D55 /* RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m in Sources */,
|
||||
329E746722CD02EA006F9797 /* BubbleReactionActionViewCell.swift in Sources */,
|
||||
B1098BFB21ECFE65000DDA48 /* KeyBackupSetupCoordinatorType.swift in Sources */,
|
||||
B1098BF721ECFE65000DDA48 /* PasswordStrength.swift in Sources */,
|
||||
324A2052225FC571004FE8B0 /* DeviceVerificationIncomingViewAction.swift in Sources */,
|
||||
|
||||
@@ -280,10 +280,8 @@
|
||||
"room_event_action_view_encryption" = "Encryption Information";
|
||||
"room_event_action_reply" = "Reply";
|
||||
"room_event_action_edit" = "Edit";
|
||||
"room_event_action_reaction_agree" = "Agree %@";
|
||||
"room_event_action_reaction_disagree" = "Disagree %@";
|
||||
"room_event_action_reaction_like" = "Like %@";
|
||||
"room_event_action_reaction_dislike" = "Dislike %@";
|
||||
"room_event_action_reaction_show_all" = "Show all";
|
||||
"room_event_action_reaction_show_less" = "Show less";
|
||||
"room_warning_about_encryption" = "End-to-end encryption is in beta and may not be reliable.\n\nYou should not yet trust it to secure data.\n\nDevices will not yet be able to decrypt history from before they joined the room.\n\nEncrypted messages will not be visible on clients that do not yet implement encryption.";
|
||||
"room_event_failed_to_send" = "Failed to send";
|
||||
"room_action_send_photo_or_video" = "Send photo or video";
|
||||
|
||||
@@ -1722,21 +1722,13 @@ internal enum VectorL10n {
|
||||
internal static var roomEventActionQuote: String {
|
||||
return VectorL10n.tr("Vector", "room_event_action_quote")
|
||||
}
|
||||
/// Agree %@
|
||||
internal static func roomEventActionReactionAgree(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "room_event_action_reaction_agree", p1)
|
||||
/// Show all
|
||||
internal static var roomEventActionReactionShowAll: String {
|
||||
return VectorL10n.tr("Vector", "room_event_action_reaction_show_all")
|
||||
}
|
||||
/// Disagree %@
|
||||
internal static func roomEventActionReactionDisagree(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "room_event_action_reaction_disagree", p1)
|
||||
}
|
||||
/// Dislike %@
|
||||
internal static func roomEventActionReactionDislike(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "room_event_action_reaction_dislike", p1)
|
||||
}
|
||||
/// Like %@
|
||||
internal static func roomEventActionReactionLike(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "room_event_action_reaction_like", p1)
|
||||
/// Show less
|
||||
internal static var roomEventActionReactionShowLess: String {
|
||||
return VectorL10n.tr("Vector", "room_event_action_reaction_show_less")
|
||||
}
|
||||
/// Remove
|
||||
internal static var roomEventActionRedact: String {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2019 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
import Reusable
|
||||
|
||||
final class BubbleReactionActionViewCell: UICollectionViewCell, NibReusable, Themable {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var actionLabel: UILabel!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var theme: Theme?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
|
||||
if #available(iOS 12.0, *) {
|
||||
/*
|
||||
On iOS 12, there are issues with self-sizing cells as described in Apple release notes (https://developer.apple.com/documentation/ios_release_notes/ios_12_release_notes) :
|
||||
"You might encounter issues with systemLayoutSizeFitting(_:) when using a UICollectionViewCell subclass that requires updateConstraints().
|
||||
(42138227) — Workaround: Don't call the cell's setNeedsUpdateConstraints() method unless you need to support live constraint changes.
|
||||
If you need to support live constraint changes, call updateConstraintsIfNeeded() before calling systemLayoutSizeFitting(_:)."
|
||||
*/
|
||||
self.updateConstraintsIfNeeded()
|
||||
}
|
||||
return super.preferredLayoutAttributesFitting(layoutAttributes)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func fill(actionString: String) {
|
||||
self.actionLabel.text = actionString
|
||||
self.updateViews()
|
||||
}
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
self.updateViews()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateViews() {
|
||||
self.actionLabel.textColor = self.theme?.tintColor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<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"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="BubbleReactionActionViewCell" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="66" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="66" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jjn-uq-kYN">
|
||||
<rect key="frame" x="1" y="1" width="64" height="20"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="Show all" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gyn-ux-gmi">
|
||||
<rect key="frame" x="6" y="4" width="52" height="12"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="gyn-ux-gmi" secondAttribute="trailing" constant="6" id="HAk-8U-Qky"/>
|
||||
<constraint firstItem="gyn-ux-gmi" firstAttribute="leading" secondItem="jjn-uq-kYN" secondAttribute="leading" constant="6" id="OZ2-Xd-9f3"/>
|
||||
<constraint firstItem="gyn-ux-gmi" firstAttribute="top" secondItem="jjn-uq-kYN" secondAttribute="top" constant="4" id="et3-mn-8dh"/>
|
||||
<constraint firstAttribute="bottom" secondItem="gyn-ux-gmi" secondAttribute="bottom" constant="4" id="thv-mo-0kv"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="jjn-uq-kYN" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="1" id="E5H-9a-us9"/>
|
||||
<constraint firstAttribute="bottom" secondItem="jjn-uq-kYN" secondAttribute="bottom" constant="1" id="Ggm-1f-3EB"/>
|
||||
<constraint firstItem="jjn-uq-kYN" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="1" id="iT6-rk-qd6"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jjn-uq-kYN" secondAttribute="trailing" constant="1" id="ztM-7J-Dnf"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
|
||||
<size key="customSize" width="443" height="170"/>
|
||||
<connections>
|
||||
<outlet property="actionLabel" destination="gyn-ux-gmi" id="qme-DX-UAc"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-459.4202898550725" y="-207.58928571428569"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -38,6 +38,7 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
|
||||
// MARK: Private
|
||||
|
||||
private var reactionsViewData: [BubbleReactionViewData] = []
|
||||
private var showAllButtonState: BubbleReactionsViewState.ShowAllButtonState = .none
|
||||
private var theme: Theme?
|
||||
|
||||
// MARK: Public
|
||||
@@ -65,6 +66,7 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
|
||||
}
|
||||
|
||||
self.collectionView.register(cellType: BubbleReactionViewCell.self)
|
||||
self.collectionView.register(cellType: BubbleReactionActionViewCell.self)
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
@@ -90,31 +92,64 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
|
||||
self.theme = theme
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
func fill(reactionsViewData: [BubbleReactionViewData]) {
|
||||
private func fill(reactionsViewData: [BubbleReactionViewData], showAllButtonState: BubbleReactionsViewState.ShowAllButtonState) {
|
||||
self.reactionsViewData = reactionsViewData
|
||||
self.showAllButtonState = showAllButtonState
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
private func actionButtonString() -> String {
|
||||
let actionString: String
|
||||
switch self.showAllButtonState {
|
||||
case .showAll:
|
||||
actionString = VectorL10n.roomEventActionReactionShowAll
|
||||
case .showLess:
|
||||
actionString = VectorL10n.roomEventActionReactionShowLess
|
||||
case .none:
|
||||
actionString = ""
|
||||
}
|
||||
|
||||
return actionString
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
extension BubbleReactionsView: UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return self.reactionsViewData.count
|
||||
// "Show all" or "Show less" is a cell in the same section as reactions cells
|
||||
let additionalItems = self.showAllButtonState == .none ? 0 : 1
|
||||
|
||||
return self.reactionsViewData.count + additionalItems
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell: BubbleReactionViewCell = collectionView.dequeueReusableCell(for: indexPath)
|
||||
|
||||
if let theme = self.theme {
|
||||
cell.update(theme: theme)
|
||||
if indexPath.row < self.reactionsViewData.count {
|
||||
let cell: BubbleReactionViewCell = collectionView.dequeueReusableCell(for: indexPath)
|
||||
|
||||
if let theme = self.theme {
|
||||
cell.update(theme: theme)
|
||||
}
|
||||
|
||||
let viewData = self.reactionsViewData[indexPath.row]
|
||||
cell.fill(viewData: viewData)
|
||||
|
||||
return cell
|
||||
} else {
|
||||
let cell: BubbleReactionActionViewCell = collectionView.dequeueReusableCell(for: indexPath)
|
||||
|
||||
if let theme = self.theme {
|
||||
cell.update(theme: theme)
|
||||
}
|
||||
|
||||
let actionString = self.actionButtonString()
|
||||
cell.fill(actionString: actionString)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
let viewData = self.reactionsViewData[indexPath.row]
|
||||
cell.fill(viewData: viewData)
|
||||
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +157,18 @@ extension BubbleReactionsView: UICollectionViewDataSource {
|
||||
extension BubbleReactionsView: UICollectionViewDelegate {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
self.viewModel?.process(viewAction: .tapReaction(index: indexPath.row))
|
||||
if indexPath.row < self.reactionsViewData.count {
|
||||
self.viewModel?.process(viewAction: .tapReaction(index: indexPath.row))
|
||||
} else {
|
||||
switch self.showAllButtonState {
|
||||
case .showAll:
|
||||
self.viewModel?.process(viewAction: .tapShowAction(action: .showAll))
|
||||
case .showLess:
|
||||
self.viewModel?.process(viewAction: .tapShowAction(action: .showLess))
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,8 +177,8 @@ extension BubbleReactionsView: BubbleReactionsViewModelViewDelegate {
|
||||
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didUpdateViewState viewState: BubbleReactionsViewState) {
|
||||
switch viewState {
|
||||
case .loaded(reactionsViewData: let reactionsViewData):
|
||||
self.fill(reactionsViewData: reactionsViewData)
|
||||
case .loaded(reactionsViewData: let reactionsViewData, showAllButtonState: let showAllButtonState):
|
||||
self.fill(reactionsViewData: reactionsViewData, showAllButtonState: showAllButtonState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,20 @@
|
||||
import Foundation
|
||||
|
||||
@objc final class BubbleReactionsViewModel: NSObject, BubbleReactionsViewModelType {
|
||||
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
private enum Constants {
|
||||
static let maxItemsWhenLimited: Int = 8
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let aggregatedReactions: MXAggregatedReactions
|
||||
private let reactionsViewData: [BubbleReactionViewData]
|
||||
private let eventId: String
|
||||
private let showAll: Bool
|
||||
|
||||
// MARK: Public
|
||||
|
||||
@@ -34,13 +40,11 @@ import Foundation
|
||||
// MARK: - Setup
|
||||
|
||||
@objc init(aggregatedReactions: MXAggregatedReactions,
|
||||
eventId: String) {
|
||||
eventId: String,
|
||||
showAll: Bool) {
|
||||
self.aggregatedReactions = aggregatedReactions
|
||||
self.eventId = eventId
|
||||
|
||||
self.reactionsViewData = aggregatedReactions.reactions.map { (reactionCount) -> BubbleReactionViewData in
|
||||
return BubbleReactionViewData(emoji: reactionCount.reaction, countString: "\(reactionCount.count)", isCurrentUserReacted: reactionCount.myUserHasReacted)
|
||||
}
|
||||
self.showAll = showAll
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -48,7 +52,7 @@ import Foundation
|
||||
func process(viewAction: BubbleReactionsViewAction) {
|
||||
switch viewAction {
|
||||
case .loadData:
|
||||
self.viewDelegate?.bubbleReactionsViewModel(self, didUpdateViewState: .loaded(reactionsViewData: self.reactionsViewData))
|
||||
self.loadData()
|
||||
case .tapReaction(let index):
|
||||
guard index < self.aggregatedReactions.reactions.count else {
|
||||
return
|
||||
@@ -61,6 +65,31 @@ import Foundation
|
||||
}
|
||||
case .addNewReaction:
|
||||
break
|
||||
case .tapShowAction(.showAll):
|
||||
self.viewModelDelegate?.bubbleReactionsViewModel(self, didShowAllTappedForEventId: self.eventId)
|
||||
case .tapShowAction(.showLess):
|
||||
self.viewModelDelegate?.bubbleReactionsViewModel(self, didShowLessTappedForEventId: self.eventId)
|
||||
}
|
||||
}
|
||||
|
||||
func loadData() {
|
||||
var reactions = self.aggregatedReactions.reactions
|
||||
var showAllButtonState: BubbleReactionsViewState.ShowAllButtonState = .none
|
||||
|
||||
// Limit displayed reactions if required
|
||||
if reactions.count > Constants.maxItemsWhenLimited {
|
||||
if self.showAll == true {
|
||||
showAllButtonState = .showLess
|
||||
} else {
|
||||
reactions = Array(reactions[0..<Constants.maxItemsWhenLimited])
|
||||
showAllButtonState = .showAll
|
||||
}
|
||||
}
|
||||
|
||||
let reactionsViewData = reactions.map { (reactionCount) -> BubbleReactionViewData in
|
||||
return BubbleReactionViewData(emoji: reactionCount.reaction, countString: "\(reactionCount.count)", isCurrentUserReacted: reactionCount.myUserHasReacted)
|
||||
}
|
||||
|
||||
self.viewDelegate?.bubbleReactionsViewModel(self, didUpdateViewState: .loaded(reactionsViewData: reactionsViewData, showAllButtonState: showAllButtonState))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,29 @@ enum BubbleReactionsViewAction {
|
||||
case loadData
|
||||
case tapReaction(index: Int)
|
||||
case addNewReaction
|
||||
case tapShowAction(action: ShowAction)
|
||||
|
||||
enum ShowAction {
|
||||
case showAll
|
||||
case showLess
|
||||
}
|
||||
}
|
||||
|
||||
enum BubbleReactionsViewState {
|
||||
case loaded(reactionsViewData: [BubbleReactionViewData])
|
||||
case loaded(reactionsViewData: [BubbleReactionViewData], showAllButtonState: ShowAllButtonState)
|
||||
|
||||
enum ShowAllButtonState {
|
||||
case none
|
||||
case showAll
|
||||
case showLess
|
||||
}
|
||||
}
|
||||
|
||||
@objc protocol BubbleReactionsViewModelDelegate: class {
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didAddReaction reactionCount: MXReactionCount, forEventId eventId: String)
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didRemoveReaction reactionCount: MXReactionCount, forEventId eventId: String)
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didShowAllTappedForEventId eventId: String)
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didShowLessTappedForEventId eventId: String)
|
||||
}
|
||||
|
||||
protocol BubbleReactionsViewModelViewDelegate: class {
|
||||
|
||||
@@ -80,4 +80,10 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag)
|
||||
*/
|
||||
- (void)updateAdditionalContentHeightIfNeeded;
|
||||
|
||||
|
||||
#pragma mark - Show all reactions
|
||||
|
||||
- (BOOL)showAllReactionsForEvent:(NSString*)eventId;
|
||||
- (void)setShowAllReactions:(BOOL)showAllReactions forEvent:(NSString*)eventId;
|
||||
|
||||
@end
|
||||
|
||||
@@ -32,6 +32,9 @@ static NSAttributedString *timestampVerticalWhitespace = nil;
|
||||
@property(nonatomic, readwrite) CGFloat additionalContentHeight;
|
||||
@property(nonatomic) BOOL shouldUpdateAdditionalContentHeight;
|
||||
|
||||
// Flags to "Show All" reactions for an event
|
||||
@property(nonatomic) NSMutableSet<NSString* /* eventId */> *eventsToShowAllReactions;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RoomBubbleCellData
|
||||
@@ -43,6 +46,16 @@ static NSAttributedString *timestampVerticalWhitespace = nil;
|
||||
|
||||
#pragma mark - Override MXKRoomBubbleCellData
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
_eventsToShowAllReactions = [NSMutableSet set];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithEvent:(MXEvent *)event andRoomState:(MXRoomState *)roomState andRoomDataSource:(MXKRoomDataSource *)roomDataSource2
|
||||
{
|
||||
self = [super initWithEvent:event andRoomState:roomState andRoomDataSource:roomDataSource2];
|
||||
@@ -368,9 +381,11 @@ static NSAttributedString *timestampVerticalWhitespace = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
bubbleReactionsView = [BubbleReactionsView new];
|
||||
});
|
||||
|
||||
BOOL showAllReactions = [self.eventsToShowAllReactions containsObject:eventId];
|
||||
|
||||
bubbleReactionsView.frame = CGRectMake(0, 0, bubbleReactionsViewWidth, 1.0);
|
||||
BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId];
|
||||
BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId showAll:showAllReactions];
|
||||
bubbleReactionsView.viewModel = viemModel;
|
||||
[bubbleReactionsView setNeedsLayout];
|
||||
[bubbleReactionsView layoutIfNeeded];
|
||||
@@ -455,9 +470,11 @@ static NSAttributedString *timestampVerticalWhitespace = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
bubbleReactionsView = [BubbleReactionsView new];
|
||||
});
|
||||
|
||||
BOOL showAllReactions = [self.eventsToShowAllReactions containsObject:eventId];
|
||||
|
||||
bubbleReactionsView.frame = CGRectMake(0, 0, bubbleReactionsViewWidth, 1.0);
|
||||
BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId];
|
||||
BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId showAll:showAllReactions];
|
||||
bubbleReactionsView.viewModel = viemModel;
|
||||
[bubbleReactionsView setNeedsLayout];
|
||||
[bubbleReactionsView layoutIfNeeded];
|
||||
@@ -636,4 +653,24 @@ static NSAttributedString *timestampVerticalWhitespace = nil;
|
||||
return [super addEvent:event andRoomState:roomState];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Show all reactions
|
||||
|
||||
- (BOOL)showAllReactionsForEvent:(NSString*)eventId
|
||||
{
|
||||
return [self.eventsToShowAllReactions containsObject:eventId];
|
||||
}
|
||||
|
||||
- (void)setShowAllReactions:(BOOL)showAllReactions forEvent:(NSString*)eventId
|
||||
{
|
||||
if (showAllReactions)
|
||||
{
|
||||
[self.eventsToShowAllReactions addObject:eventId];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.eventsToShowAllReactions removeObject:eventId];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -244,7 +244,10 @@
|
||||
|
||||
if (reactions && !isCollapsableCellCollapsed)
|
||||
{
|
||||
BubbleReactionsViewModel *bubbleReactionsViewModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:reactions eventId:componentEventId];
|
||||
BOOL showAllReactions = [cellData showAllReactionsForEvent:componentEventId];
|
||||
BubbleReactionsViewModel *bubbleReactionsViewModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:reactions
|
||||
eventId:componentEventId
|
||||
showAll:showAllReactions];
|
||||
|
||||
reactionsView = [BubbleReactionsView new];
|
||||
reactionsView.viewModel = bubbleReactionsViewModel;
|
||||
@@ -572,4 +575,28 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)bubbleReactionsViewModel:(BubbleReactionsViewModel *)viewModel didShowAllTappedForEventId:(NSString * _Nonnull)eventId
|
||||
{
|
||||
[self setShowAllReactions:YES forEvent:eventId];
|
||||
}
|
||||
|
||||
- (void)bubbleReactionsViewModel:(BubbleReactionsViewModel *)viewModel didShowLessTappedForEventId:(NSString * _Nonnull)eventId
|
||||
{
|
||||
[self setShowAllReactions:NO forEvent:eventId];
|
||||
}
|
||||
|
||||
- (void)setShowAllReactions:(BOOL)showAllReactions forEvent:(NSString*)eventId
|
||||
{
|
||||
id<MXKRoomBubbleCellDataStoring> cellData = [self cellDataOfEventWithEventId:eventId];
|
||||
if ([cellData isKindOfClass:[RoomBubbleCellData class]])
|
||||
{
|
||||
RoomBubbleCellData *roomBubbleCellData = (RoomBubbleCellData*)cellData;
|
||||
|
||||
[roomBubbleCellData setShowAllReactions:showAllReactions forEvent:eventId];
|
||||
[self updateCellDataReactions:roomBubbleCellData forEventId:eventId];
|
||||
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user