mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-06 16:07:42 +02:00
Merge pull request #2445 from vector-im/riot_2396
Reactions: Display existing reactions below the message
This commit is contained in:
@@ -4,6 +4,7 @@ Changes in 0.8.7 (2019-xx-xx)
|
||||
Improvements:
|
||||
* RoomVC: When replying, use a "Reply" button instead of "Send".
|
||||
* RoomVC: New message actions (#2394).
|
||||
* Reactions: Display existing reactions below the message (#2396).
|
||||
|
||||
Changes in 0.8.6 (2019-05-06)
|
||||
===============================================
|
||||
|
||||
@@ -79,6 +79,7 @@ abstract_target 'RiotPods' do
|
||||
|
||||
target "Riot" do
|
||||
import_MatrixKit
|
||||
pod 'DGCollectionViewLeftAlignFlowLayout', '~> 1.0.4'
|
||||
end
|
||||
|
||||
target "RiotShareExtension" do
|
||||
|
||||
@@ -194,6 +194,14 @@
|
||||
B169331720F3CBE000746532 /* RecentCellData.m in Sources */ = {isa = PBXBuildFile; fileRef = B16932F920F3C51900746532 /* RecentCellData.m */; };
|
||||
B17982FF2119FED2001FD722 /* GDPRConsentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B17982FE2119FED2001FD722 /* GDPRConsentViewController.swift */; };
|
||||
B1798302211B13B3001FD722 /* OnBoardingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1798301211B13B3001FD722 /* OnBoardingManager.swift */; };
|
||||
B1963B2B228F1C4900CBA17F /* BubbleReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B25228F1C4800CBA17F /* BubbleReactionsView.swift */; };
|
||||
B1963B2C228F1C4900CBA17F /* BubbleReactionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1963B26228F1C4800CBA17F /* BubbleReactionViewCell.xib */; };
|
||||
B1963B2D228F1C4900CBA17F /* BubbleReactionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B27228F1C4800CBA17F /* BubbleReactionsViewModel.swift */; };
|
||||
B1963B2E228F1C4900CBA17F /* BubbleReactionViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B28228F1C4800CBA17F /* BubbleReactionViewData.swift */; };
|
||||
B1963B2F228F1C4900CBA17F /* BubbleReactionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B29228F1C4800CBA17F /* BubbleReactionViewCell.swift */; };
|
||||
B1963B30228F1C4900CBA17F /* BubbleReactionsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1963B2A228F1C4800CBA17F /* BubbleReactionsView.xib */; };
|
||||
B1963B32228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B31228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift */; };
|
||||
B1963B3822933BC800CBA17F /* AutosizedCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1963B3722933BC800CBA17F /* AutosizedCollectionView.swift */; };
|
||||
B19EFA3921F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B19EFA3821F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift */; };
|
||||
B19EFA3B21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B19EFA3A21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift */; };
|
||||
B1A5B33E227ADF2A004CBA85 /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A5B33D227ADF2A004CBA85 /* UIImage.swift */; };
|
||||
@@ -784,6 +792,14 @@
|
||||
B169331320F3CAFC00746532 /* PublicRoomsDirectoryDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PublicRoomsDirectoryDataSource.h; sourceTree = "<group>"; };
|
||||
B17982FE2119FED2001FD722 /* GDPRConsentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GDPRConsentViewController.swift; sourceTree = "<group>"; };
|
||||
B1798301211B13B3001FD722 /* OnBoardingManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnBoardingManager.swift; sourceTree = "<group>"; };
|
||||
B1963B25228F1C4800CBA17F /* BubbleReactionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionsView.swift; sourceTree = "<group>"; };
|
||||
B1963B26228F1C4800CBA17F /* BubbleReactionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BubbleReactionViewCell.xib; sourceTree = "<group>"; };
|
||||
B1963B27228F1C4800CBA17F /* BubbleReactionsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionsViewModel.swift; sourceTree = "<group>"; };
|
||||
B1963B28228F1C4800CBA17F /* BubbleReactionViewData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionViewData.swift; sourceTree = "<group>"; };
|
||||
B1963B29228F1C4800CBA17F /* BubbleReactionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleReactionViewCell.swift; sourceTree = "<group>"; };
|
||||
B1963B2A228F1C4800CBA17F /* BubbleReactionsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BubbleReactionsView.xib; sourceTree = "<group>"; };
|
||||
B1963B31228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleReactionsViewModelType.swift; sourceTree = "<group>"; };
|
||||
B1963B3722933BC800CBA17F /* AutosizedCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutosizedCollectionView.swift; sourceTree = "<group>"; };
|
||||
B19EFA3821F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverCoordinatorType.swift; sourceTree = "<group>"; };
|
||||
B19EFA3A21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyBackupRecoverCoordinator.swift; sourceTree = "<group>"; };
|
||||
B1A5B33D227ADF2A004CBA85 /* UIImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImage.swift; sourceTree = "<group>"; };
|
||||
@@ -1936,6 +1952,29 @@
|
||||
path = OnBoarding;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B1963B24228F1C4800CBA17F /* BubbleReactions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B1963B31228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift */,
|
||||
B1963B27228F1C4800CBA17F /* BubbleReactionsViewModel.swift */,
|
||||
B1963B25228F1C4800CBA17F /* BubbleReactionsView.swift */,
|
||||
B1963B2A228F1C4800CBA17F /* BubbleReactionsView.xib */,
|
||||
B1963B28228F1C4800CBA17F /* BubbleReactionViewData.swift */,
|
||||
B1963B29228F1C4800CBA17F /* BubbleReactionViewCell.swift */,
|
||||
B1963B26228F1C4800CBA17F /* BubbleReactionViewCell.xib */,
|
||||
);
|
||||
path = BubbleReactions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B1963B3622933B9500CBA17F /* CollectionView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B1963B3722933BC800CBA17F /* AutosizedCollectionView.swift */,
|
||||
);
|
||||
name = CollectionView;
|
||||
path = Riot/Modules/Common/CollectionView;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
B1B5567620EE6C4C00210D55 /* Modules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2050,6 +2089,7 @@
|
||||
B1B556A420EE6C4C00210D55 /* Members */,
|
||||
B1B5569020EE6C4C00210D55 /* Settings */,
|
||||
B1C562D7228C0B4C0037F12A /* ContextualMenu */,
|
||||
B1963B24228F1C4800CBA17F /* BubbleReactions */,
|
||||
);
|
||||
path = Room;
|
||||
sourceTree = "<group>";
|
||||
@@ -2231,6 +2271,7 @@
|
||||
B1B556CD20EE6C4C00210D55 /* Common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B1963B3622933B9500CBA17F /* CollectionView */,
|
||||
B1B556CE20EE6C4C00210D55 /* WebViewController */,
|
||||
B1B556D120EE6C4C00210D55 /* NavigationController */,
|
||||
B1B556D420EE6C4C00210D55 /* SegmentedViewController */,
|
||||
@@ -3537,6 +3578,7 @@
|
||||
B1B5593920EF7BAC00210D55 /* TableViewCellWithCheckBoxes.xib in Resources */,
|
||||
B1B557C120EF5B4500210D55 /* DisabledRoomInputToolbarView.xib in Resources */,
|
||||
32891D6C2264CBA300C82226 /* SimpleScreenTemplateViewController.storyboard in Resources */,
|
||||
B1963B2C228F1C4900CBA17F /* BubbleReactionViewCell.xib in Resources */,
|
||||
B1664DA320F4F96200808783 /* Vector.strings in Resources */,
|
||||
B1B557C720EF5CD400210D55 /* DirectoryServerDetailTableViewCell.xib in Resources */,
|
||||
B1B5582620EF638A00210D55 /* RoomMemberTitleView.xib in Resources */,
|
||||
@@ -3588,6 +3630,7 @@
|
||||
B1B5590F20EF782800210D55 /* TableViewCellWithPhoneNumberTextField.xib in Resources */,
|
||||
B1B5578520EF564900210D55 /* GroupTableViewCellWithSwitch.xib in Resources */,
|
||||
B1B557B320EF5AEF00210D55 /* EventDetailsView.xib in Resources */,
|
||||
B1963B30228F1C4900CBA17F /* BubbleReactionsView.xib in Resources */,
|
||||
B1B557DD20EF5FBB00210D55 /* FilesSearchTableViewCell.xib in Resources */,
|
||||
B1B5590320EF768F00210D55 /* RoomSelectedStickerBubbleCell.xib in Resources */,
|
||||
3232ABB62257BE6400AD6A5C /* DeviceVerificationVerifyViewController.storyboard in Resources */,
|
||||
@@ -3634,6 +3677,7 @@
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-RiotPods-Riot/Pods-RiotPods-Riot-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/DGCollectionViewLeftAlignFlowLayout/DGCollectionViewLeftAlignFlowLayout.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/DTCoreText/DTCoreText.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/DTFoundation/DTFoundation.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/GBDeviceInfo/GBDeviceInfo.framework",
|
||||
@@ -3659,6 +3703,7 @@
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AFNetworking.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DGCollectionViewLeftAlignFlowLayout.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DTCoreText.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DTFoundation.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GBDeviceInfo.framework",
|
||||
@@ -3882,6 +3927,7 @@
|
||||
B1098BDF21ECE09F000DDA48 /* Strings.swift in Sources */,
|
||||
B1B558C420EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */,
|
||||
3232ABC022594C0900AD6A5C /* VerifyEmojiCollectionViewCell.swift in Sources */,
|
||||
B1963B2E228F1C4900CBA17F /* BubbleReactionViewData.swift in Sources */,
|
||||
B1B5572F20EE6C4D00210D55 /* ReadReceiptsViewController.m in Sources */,
|
||||
B1B558CB20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
|
||||
B169330B20F3CA3A00746532 /* Contact.m in Sources */,
|
||||
@@ -3914,6 +3960,7 @@
|
||||
B1B5593B20EF7BAC00210D55 /* TableViewCellWithCheckBoxAndLabel.m in Sources */,
|
||||
B1B5581A20EF625800210D55 /* ExpandedRoomTitleView.m in Sources */,
|
||||
B1107EC82200B0720038014B /* KeyBackupRecoverSuccessViewController.swift in Sources */,
|
||||
B1963B2F228F1C4900CBA17F /* BubbleReactionViewCell.swift in Sources */,
|
||||
B1B558E920EF768F00210D55 /* RoomSelectedStickerBubbleCell.m in Sources */,
|
||||
B1B558DF20EF768F00210D55 /* RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
|
||||
F083BE041E7009ED00A9B29C /* Tools.m in Sources */,
|
||||
@@ -3949,6 +3996,7 @@
|
||||
32F6B96E2270623100BBA352 /* DeviceVerificationDataLoadingViewModelType.swift in Sources */,
|
||||
B1B5592C20EF7A5D00210D55 /* TableViewCellWithButton.m in Sources */,
|
||||
32242F1421E8FBA900725742 /* DefaultTheme.swift in Sources */,
|
||||
B1963B2D228F1C4900CBA17F /* BubbleReactionsViewModel.swift in Sources */,
|
||||
32242F1321E8FBA900725742 /* Theme.swift in Sources */,
|
||||
B1B5582520EF638A00210D55 /* RoomMemberTitleView.m in Sources */,
|
||||
B1B5582C20EF666100210D55 /* DirectoryRecentTableViewCell.m in Sources */,
|
||||
@@ -4029,6 +4077,7 @@
|
||||
B1798302211B13B3001FD722 /* OnBoardingManager.swift in Sources */,
|
||||
B1B5573520EE6C4D00210D55 /* GroupDetailsViewController.m in Sources */,
|
||||
B10B3B5B2201DD740072C76B /* KeyBackupBannerCell.swift in Sources */,
|
||||
B1963B32228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift in Sources */,
|
||||
B1098BFA21ECFE65000DDA48 /* KeyBackupSetupPassphraseViewModel.swift in Sources */,
|
||||
B1B5575220EE6C4D00210D55 /* RoomKeyRequestViewController.m in Sources */,
|
||||
F083BD1E1E7009ED00A9B29C /* AppDelegate.m in Sources */,
|
||||
@@ -4082,8 +4131,10 @@
|
||||
B110872621F098F0003554A5 /* ActivityIndicatorView.swift in Sources */,
|
||||
B19EFA3921F8BB2C00FC070E /* KeyBackupRecoverCoordinatorType.swift in Sources */,
|
||||
B1E5368D21FB7245001F3AFF /* KeyBackupRecoverFromPassphraseViewController.swift in Sources */,
|
||||
B1963B3822933BC800CBA17F /* AutosizedCollectionView.swift in Sources */,
|
||||
B169330320F3C98900746532 /* RoomBubbleCellData.m in Sources */,
|
||||
B1B557CC20EF5D8000210D55 /* DirectoryServerTableViewCell.m in Sources */,
|
||||
B1963B2B228F1C4900CBA17F /* BubbleReactionsView.swift in Sources */,
|
||||
B1B5575C20EE6C4D00210D55 /* DirectoryViewController.m in Sources */,
|
||||
B1B558BD20EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.m in Sources */,
|
||||
B1B5577020EE702800210D55 /* WidgetPickerViewController.m in Sources */,
|
||||
|
||||
@@ -30,8 +30,8 @@ class DarkTheme: NSObject, Theme {
|
||||
var searchBackgroundColor: UIColor = UIColor(rgb: 0x181B21)
|
||||
var searchPlaceholderColor: UIColor = UIColor(rgb: 0x61708B)
|
||||
|
||||
var headerBackgroundColor: UIColor = UIColor(rgb: 0x15171B)
|
||||
var headerBorderColor: UIColor = UIColor(rgb: 0x22262E)
|
||||
var headerBackgroundColor: UIColor = UIColor(rgb: 0x22262E)
|
||||
var headerBorderColor: UIColor = UIColor(rgb: 0x181B21)
|
||||
var headerTextPrimaryColor: UIColor = UIColor(rgb: 0xA1B2D1)
|
||||
var headerTextSecondaryColor: UIColor = UIColor(rgb: 0xC8C8CD)
|
||||
|
||||
@@ -39,7 +39,7 @@ class DarkTheme: NSObject, Theme {
|
||||
var textSecondaryColor: UIColor = UIColor(rgb: 0xA1B2D1)
|
||||
|
||||
var tintColor: UIColor = UIColor(rgb: 0x03B381)
|
||||
var tintBackgroundColor: UIColor = UIColor(rgb: 0xe9fff9)
|
||||
var tintBackgroundColor: UIColor = UIColor(rgb: 0x1F6954)
|
||||
var unreadRoomIndentColor: UIColor = UIColor(rgb: 0x2E3648)
|
||||
var lineBreakColor: UIColor = UIColor(rgb: 0x61708B)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class DefaultTheme: NSObject, Theme {
|
||||
var searchBackgroundColor: UIColor = UIColor(rgb: 0xFFFFFF)
|
||||
var searchPlaceholderColor: UIColor = UIColor(rgb: 0x61708B)
|
||||
|
||||
var headerBackgroundColor: UIColor = UIColor(rgb: 0xF2F5F8)
|
||||
var headerBackgroundColor: UIColor = UIColor(rgb: 0xF3F8FD)
|
||||
var headerBorderColor: UIColor = UIColor(rgb: 0xE9EDF1)
|
||||
var headerTextPrimaryColor: UIColor = UIColor(rgb: 0x61708B)
|
||||
var headerTextSecondaryColor: UIColor = UIColor(rgb: 0xC8C8CD)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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
|
||||
|
||||
/// AutosizedCollectionView is a convenient UICollectionView that makes dynamic sizing easier when using Auto Layout
|
||||
class AutosizedCollectionView: UICollectionView {
|
||||
|
||||
override var contentSize: CGSize {
|
||||
didSet {
|
||||
self.invalidateIntrinsicContentSize()
|
||||
}
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return self.contentSize
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
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 BubbleReactionViewCell: UICollectionViewCell, NibReusable, Themable {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
private enum Constants {
|
||||
static let selectedBorderWidth: CGFloat = 1.0
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var reactionBackgroundView: UIView!
|
||||
@IBOutlet private weak var emojiLabel: UILabel!
|
||||
@IBOutlet private weak var countLabel: UILabel!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var theme: Theme?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
private var isReactionSelected: Bool = false
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
|
||||
self.reactionBackgroundView.layer.masksToBounds = true
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
self.reactionBackgroundView.layer.cornerRadius = self.reactionBackgroundView.frame.size.height/2.0
|
||||
}
|
||||
|
||||
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(viewData: BubbleReactionViewData) {
|
||||
self.emojiLabel.text = viewData.emoji
|
||||
self.countLabel.text = viewData.countString
|
||||
self.isReactionSelected = viewData.isCurrentUserReacted
|
||||
|
||||
self.updateViews()
|
||||
}
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
self.reactionBackgroundView.layer.borderColor = self.theme?.tintColor.cgColor
|
||||
self.countLabel.textColor = self.theme?.textPrimaryColor
|
||||
self.updateViews()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateViews() {
|
||||
|
||||
let reactionBackgroundColor: UIColor?
|
||||
let reactionBackgroundBorderWidth: CGFloat
|
||||
|
||||
if self.isReactionSelected {
|
||||
reactionBackgroundColor = self.theme?.tintBackgroundColor
|
||||
reactionBackgroundBorderWidth = Constants.selectedBorderWidth
|
||||
} else {
|
||||
reactionBackgroundColor = self.theme?.headerBackgroundColor
|
||||
reactionBackgroundBorderWidth = 0.0
|
||||
}
|
||||
|
||||
self.reactionBackgroundView.layer.borderWidth = reactionBackgroundBorderWidth
|
||||
self.reactionBackgroundView.backgroundColor = reactionBackgroundColor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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="BubbleReactionViewCell" 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="0.0" y="0.0" width="66" height="22"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="👍" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gyn-ux-gmi">
|
||||
<rect key="frame" x="6" y="4" width="26" height="14"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="230" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DQc-oh-Wus">
|
||||
<rect key="frame" x="34" y="4" width="26" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="26" id="qaD-Xb-kVP"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.95294117647058818" green="0.97254901960784312" blue="0.99215686274509807" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="DQc-oh-Wus" firstAttribute="centerY" secondItem="gyn-ux-gmi" secondAttribute="centerY" id="E1I-l3-qql"/>
|
||||
<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="trailing" secondItem="DQc-oh-Wus" secondAttribute="trailing" constant="6" id="oJE-06-g5e"/>
|
||||
<constraint firstAttribute="bottom" secondItem="gyn-ux-gmi" secondAttribute="bottom" constant="4" id="thv-mo-0kv"/>
|
||||
<constraint firstItem="DQc-oh-Wus" firstAttribute="leading" secondItem="gyn-ux-gmi" secondAttribute="trailing" constant="2" id="y7s-iU-ycf"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="jjn-uq-kYN" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="E5H-9a-us9"/>
|
||||
<constraint firstAttribute="bottom" secondItem="jjn-uq-kYN" secondAttribute="bottom" id="Ggm-1f-3EB"/>
|
||||
<constraint firstItem="jjn-uq-kYN" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="iT6-rk-qd6"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jjn-uq-kYN" secondAttribute="trailing" id="ztM-7J-Dnf"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
|
||||
<size key="customSize" width="443" height="170"/>
|
||||
<connections>
|
||||
<outlet property="countLabel" destination="DQc-oh-Wus" id="GZt-aS-umB"/>
|
||||
<outlet property="emojiLabel" destination="gyn-ux-gmi" id="qme-DX-UAc"/>
|
||||
<outlet property="reactionBackgroundView" destination="jjn-uq-kYN" id="Q0x-Np-wEa"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-459.4202898550725" y="-207.58928571428569"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
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 Foundation
|
||||
|
||||
struct BubbleReactionViewData {
|
||||
let emoji: String
|
||||
let countString: String
|
||||
let isCurrentUserReacted: Bool
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
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 Foundation
|
||||
import MatrixSDK
|
||||
import Reusable
|
||||
import DGCollectionViewLeftAlignFlowLayout
|
||||
|
||||
@objcMembers
|
||||
final class BubbleReactionsView: UIView, NibOwnerLoadable {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
private enum Constants {
|
||||
static let minimumInteritemSpacing: CGFloat = 6.0
|
||||
static let minimumLineSpacing: CGFloat = 2.0
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var collectionView: UICollectionView!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var reactionsViewData: [BubbleReactionViewData] = []
|
||||
private var theme: Theme?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
// Do not use `BubbleReactionsViewModelType` here due to Objective-C incompatibily
|
||||
var viewModel: BubbleReactionsViewModel? {
|
||||
didSet {
|
||||
self.viewModel?.viewDelegate = self
|
||||
self.viewModel?.process(viewAction: .loadData)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func commonInit() {
|
||||
self.collectionView.isScrollEnabled = false
|
||||
self.collectionView.delegate = self
|
||||
self.collectionView.dataSource = self
|
||||
self.collectionView.collectionViewLayout = DGCollectionViewLeftAlignFlowLayout()
|
||||
|
||||
if let collectionViewFlowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
|
||||
collectionViewFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
|
||||
collectionViewFlowLayout.minimumInteritemSpacing = Constants.minimumInteritemSpacing
|
||||
collectionViewFlowLayout.minimumLineSpacing = Constants.minimumLineSpacing
|
||||
}
|
||||
|
||||
self.collectionView.register(cellType: BubbleReactionViewCell.self)
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
convenience init() {
|
||||
self.init(frame: CGRect.zero)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
self.loadNibContent()
|
||||
self.commonInit()
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.loadNibContent()
|
||||
self.commonInit()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
func fill(reactionsViewData: [BubbleReactionViewData]) {
|
||||
self.reactionsViewData = reactionsViewData
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
extension BubbleReactionsView: UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return self.reactionsViewData.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDelegate
|
||||
extension BubbleReactionsView: UICollectionViewDelegate {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
self.viewModel?.process(viewAction: .tapReaction(index: indexPath.row))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - BubbleReactionsViewModelViewDelegate
|
||||
extension BubbleReactionsView: BubbleReactionsViewModelViewDelegate {
|
||||
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didUpdateViewState viewState: BubbleReactionsViewState) {
|
||||
switch viewState {
|
||||
case .loaded(reactionsViewData: let reactionsViewData):
|
||||
self.fill(reactionsViewData: reactionsViewData)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?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" 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="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="BubbleReactionsView" customModule="Riot" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="collectionView" destination="uTe-bw-bWE" id="EGc-ca-YSM"/>
|
||||
</connections>
|
||||
</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="422" height="136"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="uTe-bw-bWE" customClass="AutosizedCollectionView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="422" height="136"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="qeb-Ii-egn">
|
||||
<size key="itemSize" width="1" height="1"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="uTe-bw-bWE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="NbI-pU-tZb"/>
|
||||
<constraint firstAttribute="bottom" secondItem="uTe-bw-bWE" secondAttribute="bottom" id="lwj-Lm-yDr"/>
|
||||
<constraint firstAttribute="trailing" secondItem="uTe-bw-bWE" secondAttribute="trailing" id="rP3-ME-Y83"/>
|
||||
<constraint firstItem="uTe-bw-bWE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="uSd-DZ-bOf"/>
|
||||
</constraints>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="-423" y="11"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
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 Foundation
|
||||
|
||||
@objc final class BubbleReactionsViewModel: NSObject, BubbleReactionsViewModelType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let aggregatedReactions: MXAggregatedReactions
|
||||
private let reactionsViewData: [BubbleReactionViewData]
|
||||
private let eventId: String
|
||||
|
||||
// MARK: Public
|
||||
|
||||
@objc weak var viewModelDelegate: BubbleReactionsViewModelDelegate?
|
||||
weak var viewDelegate: BubbleReactionsViewModelViewDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
@objc init(aggregatedReactions: MXAggregatedReactions,
|
||||
eventId: String) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func process(viewAction: BubbleReactionsViewAction) {
|
||||
switch viewAction {
|
||||
case .loadData:
|
||||
self.viewDelegate?.bubbleReactionsViewModel(self, didUpdateViewState: .loaded(reactionsViewData: self.reactionsViewData))
|
||||
case .tapReaction(let index):
|
||||
guard index < self.aggregatedReactions.reactions.count else {
|
||||
return
|
||||
}
|
||||
let reactionCount = self.aggregatedReactions.reactions[index]
|
||||
if reactionCount.myUserHasReacted {
|
||||
self.viewModelDelegate?.bubbleReactionsViewModel(self, didRemoveReaction: reactionCount, forEventId: self.eventId)
|
||||
} else {
|
||||
self.viewModelDelegate?.bubbleReactionsViewModel(self, didAddReaction: reactionCount, forEventId: self.eventId)
|
||||
}
|
||||
case .addNewReaction:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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 Foundation
|
||||
|
||||
enum BubbleReactionsViewAction {
|
||||
case loadData
|
||||
case tapReaction(index: Int)
|
||||
case addNewReaction
|
||||
}
|
||||
|
||||
enum BubbleReactionsViewState {
|
||||
case loaded(reactionsViewData: [BubbleReactionViewData])
|
||||
}
|
||||
|
||||
@objc protocol BubbleReactionsViewModelDelegate: class {
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didAddReaction reactionCount: MXReactionCount, forEventId eventId: String)
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didRemoveReaction reactionCount: MXReactionCount, forEventId eventId: String)
|
||||
}
|
||||
|
||||
protocol BubbleReactionsViewModelViewDelegate: class {
|
||||
func bubbleReactionsViewModel(_ viewModel: BubbleReactionsViewModel, didUpdateViewState viewState: BubbleReactionsViewState)
|
||||
}
|
||||
|
||||
protocol BubbleReactionsViewModelType {
|
||||
var viewModelDelegate: BubbleReactionsViewModelDelegate? { get set }
|
||||
var viewDelegate: BubbleReactionsViewModelViewDelegate? { get set }
|
||||
|
||||
func process(viewAction: BubbleReactionsViewAction)
|
||||
}
|
||||
@@ -22,6 +22,8 @@
|
||||
#import "AvatarGenerator.h"
|
||||
#import "Tools.h"
|
||||
|
||||
#import "Riot-Swift.h"
|
||||
|
||||
static NSAttributedString *timestampVerticalWhitespace = nil;
|
||||
static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
||||
|
||||
@@ -357,11 +359,28 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
||||
{
|
||||
// Add vertical whitespace in case of read receipts.
|
||||
NSUInteger reactionCount = self.reactions[eventId].reactions.count;
|
||||
|
||||
MXAggregatedReactions *aggregatedReactions = self.reactions[eventId];
|
||||
|
||||
if (reactionCount)
|
||||
{
|
||||
// TODO: Set right height: 22 + 8
|
||||
// TODO: Set right dynamic line count: reactionCount / 6
|
||||
CGFloat height = (22 + 8) * ((reactionCount / 6) + 1);
|
||||
CGSize fittingSize = UILayoutFittingCompressedSize;
|
||||
fittingSize.width = self.maxTextViewWidth;
|
||||
|
||||
static BubbleReactionsView *bubbleReactionsView;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
bubbleReactionsView = [BubbleReactionsView new];
|
||||
});
|
||||
|
||||
bubbleReactionsView.frame = CGRectMake(0, 0, self.maxTextViewWidth, 1.0);
|
||||
BubbleReactionsViewModel *viemModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId];
|
||||
bubbleReactionsView.viewModel = viemModel;
|
||||
[bubbleReactionsView layoutIfNeeded];
|
||||
|
||||
CGFloat height = [bubbleReactionsView systemLayoutSizeFittingSize:fittingSize].height;
|
||||
|
||||
[attributedString appendAttributedString:[RoomBubbleCellData verticalWhitespaceForHeight: height]];
|
||||
}
|
||||
|
||||
@@ -503,7 +522,7 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
|
||||
|
||||
|
||||
return [[NSAttributedString alloc] initWithString:returnString attributes:@{NSForegroundColorAttributeName : [UIColor blackColor],
|
||||
NSFontAttributeName: [UIFont systemFontOfSize:4]}];
|
||||
NSFontAttributeName: [UIFont systemFontOfSize:6]}];
|
||||
}
|
||||
|
||||
- (BOOL)hasSameSenderAsBubbleCellData:(id<MXKRoomBubbleCellDataStoring>)bubbleCellData
|
||||
|
||||
@@ -27,7 +27,11 @@
|
||||
|
||||
#import "MXRoom+Riot.h"
|
||||
|
||||
@interface RoomDataSource()
|
||||
|
||||
static CGFloat kBubbleReactionsViewLeftMargin = 55.0;
|
||||
static CGFloat kBubbleReactionsViewRightMargin = 15.0;
|
||||
|
||||
@interface RoomDataSource() <BubbleReactionsViewModelDelegate>
|
||||
{
|
||||
// Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
|
||||
id kThemeServiceDidChangeThemeNotificationObserver;
|
||||
@@ -275,6 +279,7 @@
|
||||
while (index--)
|
||||
{
|
||||
MXKRoomBubbleComponent *component = bubbleComponents[index];
|
||||
NSString *componentEventId = component.event.eventId;
|
||||
|
||||
if (component.event.sentState != MXEventSentStateFailed)
|
||||
{
|
||||
@@ -379,54 +384,46 @@
|
||||
[NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, trailingConstraint]];
|
||||
}
|
||||
}
|
||||
|
||||
MXAggregatedReactions* reactions = cellData.reactions[component.event.eventId];
|
||||
|
||||
MXAggregatedReactions* reactions = cellData.reactions[componentEventId];
|
||||
|
||||
if (reactions && !isCollapsableCellCollapsed)
|
||||
{
|
||||
// TODO: Use final ReactionsView
|
||||
UITextView* reactionsContainer = [UITextView new];
|
||||
reactionsContainer.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[bubbleCell.contentView addSubview:reactionsContainer];
|
||||
|
||||
reactionsContainer.layer.borderColor = UIColor.orangeColor.CGColor;
|
||||
reactionsContainer.layer.borderWidth = 1;
|
||||
|
||||
BubbleReactionsViewModel *bubbleReactionsViewModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:reactions eventId:componentEventId];
|
||||
|
||||
BubbleReactionsView *reactionsView = [BubbleReactionsView new];
|
||||
reactionsView.viewModel = bubbleReactionsViewModel;
|
||||
[reactionsView updateWithTheme:ThemeService.shared.theme];
|
||||
|
||||
bubbleReactionsViewModel.viewModelDelegate = self;
|
||||
|
||||
reactionsView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[bubbleCell.contentView addSubview:reactionsView];
|
||||
|
||||
if (!bubbleCell.tmpSubviews)
|
||||
{
|
||||
bubbleCell.tmpSubviews = [NSMutableArray array];
|
||||
}
|
||||
[bubbleCell.tmpSubviews addObject:reactionsContainer];
|
||||
|
||||
[bubbleCell.tmpSubviews addObject:reactionsView];
|
||||
|
||||
// At the bottom, we have read receipts or nothing
|
||||
NSLayoutConstraint *bottomConstraint;
|
||||
if (avatarsContainer)
|
||||
{
|
||||
bottomConstraint = [reactionsContainer.bottomAnchor constraintEqualToAnchor:avatarsContainer.topAnchor];
|
||||
bottomConstraint = [reactionsView.bottomAnchor constraintEqualToAnchor:avatarsContainer.topAnchor];
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomConstraint = [reactionsContainer.bottomAnchor constraintEqualToAnchor:reactionsContainer.superview.topAnchor constant:bottomPositionY];
|
||||
bottomConstraint = [reactionsView.bottomAnchor constraintEqualToAnchor:reactionsView.superview.topAnchor constant:bottomPositionY];
|
||||
}
|
||||
|
||||
// TODO: To refine
|
||||
CGFloat viewHeight = 22;
|
||||
|
||||
|
||||
// Force receipts container size
|
||||
[NSLayoutConstraint activateConstraints:
|
||||
@[
|
||||
[reactionsContainer.leadingAnchor constraintEqualToAnchor:reactionsContainer.superview.leadingAnchor constant:50],
|
||||
[reactionsContainer.trailingAnchor constraintEqualToAnchor:reactionsContainer.superview.trailingAnchor constant:-6],
|
||||
[reactionsContainer.heightAnchor constraintEqualToConstant:viewHeight],
|
||||
bottomConstraint
|
||||
]];
|
||||
|
||||
// TODO: To remove
|
||||
NSMutableString *reactionsString = [NSMutableString string];
|
||||
for (MXReactionCount *reactionCount in reactions.reactions)
|
||||
{
|
||||
[reactionsString appendFormat:@"%@: %@ ", reactionCount.reaction, @(reactionCount.count)];
|
||||
}
|
||||
reactionsContainer.text = reactionsString;
|
||||
@[
|
||||
[reactionsView.leadingAnchor constraintEqualToAnchor:reactionsView.superview.leadingAnchor constant:kBubbleReactionsViewLeftMargin],
|
||||
[reactionsView.trailingAnchor constraintEqualToAnchor:reactionsView.superview.trailingAnchor constant:-kBubbleReactionsViewRightMargin],
|
||||
bottomConstraint
|
||||
]];
|
||||
}
|
||||
|
||||
// Check whether the read marker must be displayed here.
|
||||
@@ -439,7 +436,7 @@
|
||||
bubbleCell.bubbleOverlayContainer.userInteractionEnabled = NO;
|
||||
bubbleCell.bubbleOverlayContainer.hidden = NO;
|
||||
|
||||
if ([component.event.eventId isEqualToString:self.room.accountData.readMarkerEventId])
|
||||
if ([componentEventId isEqualToString:self.room.accountData.readMarkerEventId])
|
||||
{
|
||||
bubbleCell.readMarkerView = [[UIView alloc] initWithFrame:CGRectMake(0, bottomPositionY - 2, bubbleCell.bubbleOverlayContainer.frame.size.width, 2)];
|
||||
bubbleCell.readMarkerView.backgroundColor = ThemeService.shared.theme.tintColor;
|
||||
@@ -580,4 +577,24 @@
|
||||
return jitsiWidget;
|
||||
}
|
||||
|
||||
#pragma mark - BubbleReactionsViewModelDelegate
|
||||
|
||||
- (void)bubbleReactionsViewModel:(BubbleReactionsViewModel *)viewModel didAddReaction:(MXReactionCount *)reactionCount forEventId:(NSString *)eventId
|
||||
{
|
||||
[self.mxSession.aggregations sendReaction:reactionCount.reaction toEvent:eventId inRoom:self.roomId success:^(NSString * _Nonnull eventId) {
|
||||
|
||||
} failure:^(NSError * _Nonnull error) {
|
||||
NSLog(@"[MXKRoomDataSource] Fail to send reaction on eventId: %@", eventId);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)bubbleReactionsViewModel:(BubbleReactionsViewModel *)viewModel didRemoveReaction:(MXReactionCount * _Nonnull)reactionCount forEventId:(NSString * _Nonnull)eventId
|
||||
{
|
||||
[self.mxSession.aggregations unReactOnReaction:reactionCount.reaction toEvent:eventId inRoom:self.roomId success:^{
|
||||
|
||||
} failure:^(NSError * _Nonnull error) {
|
||||
NSLog(@"[MXKRoomDataSource] Fail to unreact on eventId: %@", eventId);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user