diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Contents.json new file mode 100644 index 000000000..ad6d3af55 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1.png new file mode 100644 index 000000000..d1087e6b3 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1@2x.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1@2x.png new file mode 100644 index 000000000..ffad58d65 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1@3x.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1@3x.png new file mode 100644 index 000000000..cad21b28e Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_ended_image.imageset/Group 1@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Contents.json new file mode 100644 index 000000000..188a203cc --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "Subtract.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Subtract@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Subtract@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract.png new file mode 100644 index 000000000..16be3b51b Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract@2x.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract@2x.png new file mode 100644 index 000000000..4e20a1517 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract@3x.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract@3x.png new file mode 100644 index 000000000..61ea2a528 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_icon.imageset/Subtract@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Contents.json new file mode 100644 index 000000000..ad6d3af55 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1.png new file mode 100644 index 000000000..19c9bd1c3 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1@2x.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1@2x.png new file mode 100644 index 000000000..f8054f3d4 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1@3x.png b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1@3x.png new file mode 100644 index 000000000..482496d25 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Room/Location/location_live_cell_loading_image.imageset/Group 1@3x.png differ diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 83f855569..9c0a6f89a 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2145,6 +2145,8 @@ Tap the + to start adding people."; "location_sharing_live_map_callout_title" = "Share location"; "location_sharing_live_timer_outgoing" = "%@ left"; "location_sharing_live_timer_incoming" = "Live until %@"; +"location_sharing_live_loading" = "Loading Live location..."; +"location_sharing_live_error" = "Live location error"; // MARK: - MatrixKit diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index d9c9dadb8..6e39159cc 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -174,6 +174,9 @@ internal class Asset: NSObject { internal static let voiceCallHangupIcon = ImageAsset(name: "voice_call_hangup_icon") internal static let liveLocationIcon = ImageAsset(name: "live_location_icon") internal static let locationCenterMapIcon = ImageAsset(name: "location_center_map_icon") + internal static let locationLiveCellEndedImage = ImageAsset(name: "location_live_cell_ended_image") + internal static let locationLiveCellIcon = ImageAsset(name: "location_live_cell_icon") + internal static let locationLiveCellLoadingImage = ImageAsset(name: "location_live_cell_loading_image") internal static let locationLiveIcon = ImageAsset(name: "location_live_icon") internal static let locationMarkerIcon = ImageAsset(name: "location_marker_icon") internal static let locationPinIcon = ImageAsset(name: "location_pin_icon") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 13aecc0c7..2c5e2c007 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -2763,6 +2763,14 @@ public class VectorL10n: NSObject { public static var locationSharingInvalidAuthorizationSettings: String { return VectorL10n.tr("Vector", "location_sharing_invalid_authorization_settings") } + /// Live location error + public static var locationSharingLiveError: String { + return VectorL10n.tr("Vector", "location_sharing_live_error") + } + /// Loading Live location... + public static var locationSharingLiveLoading: String { + return VectorL10n.tr("Vector", "location_sharing_live_loading") + } /// Share location public static var locationSharingLiveMapCalloutTitle: String { return VectorL10n.tr("Vector", "location_sharing_live_map_callout_title") diff --git a/Riot/Managers/Theme/Theme.swift b/Riot/Managers/Theme/Theme.swift index 93d9cb2a9..039175371 100644 --- a/Riot/Managers/Theme/Theme.swift +++ b/Riot/Managers/Theme/Theme.swift @@ -104,6 +104,16 @@ import DesignKit var roomCellOutgoingBubbleBackgroundColor: UIColor { get } + // Localisation Cells + + var roomCellLocalisationTextColor: UIColor { get } + + var roomCellLocalisationStartedColor: UIColor { get } + + var roomCellLocalisationEndedColor: UIColor { get } + + var roomCellLocalisationErrorColor: UIColor { get } + // MARK: - Customisation methods diff --git a/Riot/Managers/Theme/Themes/DarkTheme.swift b/Riot/Managers/Theme/Themes/DarkTheme.swift index d61ed3954..6d076e037 100644 --- a/Riot/Managers/Theme/Themes/DarkTheme.swift +++ b/Riot/Managers/Theme/Themes/DarkTheme.swift @@ -98,6 +98,14 @@ class DarkTheme: NSObject, Theme { } var roomCellOutgoingBubbleBackgroundColor: UIColor = UIColor(rgb: 0x133A34) + + var roomCellLocalisationTextColor: UIColor = UIColor(rgb: 0x17191C) + + var roomCellLocalisationStartedColor: UIColor = UIColor(rgb: 0x5C56F5) + + var roomCellLocalisationEndedColor: UIColor = UIColor(rgb: 0xC1C6CD) + + var roomCellLocalisationErrorColor: UIColor = UIColor(rgb: 0xFF5B55) func applyStyle(onTabBar tabBar: UITabBar) { tabBar.unselectedItemTintColor = self.tabBarUnselectedItemTintColor diff --git a/Riot/Managers/Theme/Themes/DefaultTheme.swift b/Riot/Managers/Theme/Themes/DefaultTheme.swift index e2afd9339..5eaee1185 100644 --- a/Riot/Managers/Theme/Themes/DefaultTheme.swift +++ b/Riot/Managers/Theme/Themes/DefaultTheme.swift @@ -105,6 +105,14 @@ class DefaultTheme: NSObject, Theme { var roomCellOutgoingBubbleBackgroundColor: UIColor = UIColor(rgb: 0xE7F8F3) + var roomCellLocalisationTextColor: UIColor = UIColor(rgb: 0x17191C) + + var roomCellLocalisationStartedColor: UIColor = UIColor(rgb: 0x5C56F5) + + var roomCellLocalisationEndedColor: UIColor = UIColor(rgb: 0xC1C6CD) + + var roomCellLocalisationErrorColor: UIColor = UIColor(rgb: 0xFF5B55) + func applyStyle(onTabBar tabBar: UITabBar) { tabBar.unselectedItemTintColor = self.tabBarUnselectedItemTintColor tabBar.tintColor = self.tintColor diff --git a/Riot/Modules/Room/Location/RoomTimelineLocationView.swift b/Riot/Modules/Room/Location/RoomTimelineLocationView.swift index 4eb372b2d..c500bf87d 100644 --- a/Riot/Modules/Room/Location/RoomTimelineLocationView.swift +++ b/Riot/Modules/Room/Location/RoomTimelineLocationView.swift @@ -19,26 +19,60 @@ import Reusable import Mapbox import SwiftUI -struct LiveLocationParameter { - let bannerImage: UIImage - let bannerTitle: String - let timer: String? - let shouldShowStopButton: Bool - let isLive: Bool +protocol RoomTimelineLocationViewDelegate: AnyObject { + func didTapStopButton() + func didTapRetryButton() } -enum LiveLocationState { - case incomingLive(String?) - case outgoingLive(String?) +struct RoomTimelineLocationViewData { + let location: CLLocationCoordinate2D + let userAvatarData: AvatarViewData? + let mapStyleURL: URL +} + +struct LiveLocationBannerViewData { + let placeholderImage: UIImage? + let iconTint: UIColor + let title: String + let titleColor: UIColor + let timeLeftString: String? + let rightButtonTitle: String? + let rightButtonTag: RightButtonTag - func values() -> LiveLocationParameter { - switch self { - case .incomingLive(let timerString): - return LiveLocationParameter(bannerImage: Asset.Images.locationLiveIcon.image, bannerTitle: VectorL10n.liveLocationSharingBannerTitle, timer: timerString, shouldShowStopButton: false, isLive: true) - case .outgoingLive(let timerString): - return LiveLocationParameter(bannerImage: Asset.Images.locationLiveIcon.image, bannerTitle: VectorL10n.liveLocationSharingBannerTitle, timer: timerString, shouldShowStopButton: true, isLive: true) - } + var showTimer: Bool { + return timeLeftString != nil } + + var showRightButton: Bool { + return rightButtonTitle != nil + } + + var showPlaceholderImage: Bool { + return placeholderImage != nil + } +} + +enum TimelineLiveLocationViewState { + case incoming(_ status: IncomingLiveLocationSharingStatus) // live location started by other users + case outgoing(_ status: OutgoingLiveLocationSharingStatus) // live location started from current user +} + + +enum OutgoingLiveLocationSharingStatus { + case starting + case started(_ timeleft: TimeInterval) + case failure + case stopped +} + +enum IncomingLiveLocationSharingStatus { + case started(_ timeleft: TimeInterval) + case stopped +} + +enum RightButtonTag: Int { + case stopSharing = 0 + case retrySharing } class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegate { @@ -61,11 +95,12 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat @IBOutlet private var attributionLabel: UILabel! // MARK: - Live Location + @IBOutlet private var placeholderImage: UIImageView! @IBOutlet private var liveLocationContainerView: UIView! @IBOutlet private var liveLocationImageView: UIImageView! @IBOutlet private var liveLocationStatusLabel: UILabel! @IBOutlet private var liveLocationTimerLabel: UILabel! - @IBOutlet private var stopSharingButton: UIButton! + @IBOutlet private var rightButton: UIButton! @@ -73,6 +108,22 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat private var annotationView: LocationMarkerView? private static var usernameColorGenerator = UserNameColorGenerator() + private lazy var incomingTimerFormatter: DateFormatter = { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "HH:mm" + return dateFormatter + }() + + private lazy var outgoingTimerFormatter: DateComponentsFormatter = { + let formatter = DateComponentsFormatter() + formatter.zeroFormattingBehavior = .dropAll + formatter.allowedUnits = [.hour, .minute, .second] + formatter.unitsStyle = .brief + return formatter + }() + + weak var delegate: RoomTimelineLocationViewDelegate? + // MARK: Public var locationDescription: String? { @@ -84,7 +135,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat descriptionContainerView.isHidden = (newValue?.count ?? 0 == 0) } } - + override func awakeFromNib() { super.awakeFromNib() @@ -104,12 +155,12 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat layer.cornerRadius = Constants.cellCornerRadius } - // MARK: - Public + // MARK: - Private - public func displayLocation(_ location: CLLocationCoordinate2D, - userAvatarData: AvatarViewData? = nil, - mapStyleURL: URL, - liveLocationState: LiveLocationState? = nil) { + private func displayLocation(_ location: CLLocationCoordinate2D, + userAvatarData: AvatarViewData? = nil, + mapStyleURL: URL, + bannerViewData: LiveLocationBannerViewData? = nil) { mapView.styleURL = mapStyleURL @@ -131,23 +182,116 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat mapView.addAnnotation(pointAnnotation) // Configure live location banner - guard let liveLocationParameters = liveLocationState?.values() else { + guard let bannerViewData = bannerViewData else { liveLocationContainerView.isHidden = true return } liveLocationContainerView.isHidden = false - liveLocationImageView.image = liveLocationParameters.bannerImage - liveLocationStatusLabel.text = liveLocationParameters.bannerTitle - if let timerString = liveLocationParameters.timer { - liveLocationTimerLabel.isHidden = false - liveLocationTimerLabel.text = timerString - } else { - liveLocationTimerLabel.isHidden = true - } - stopSharingButton.isHidden = !liveLocationParameters.shouldShowStopButton + + liveLocationImageView.image = Asset.Images.locationLiveCellIcon.image + liveLocationImageView.tintColor = bannerViewData.iconTint + + liveLocationStatusLabel.text = bannerViewData.title + liveLocationStatusLabel.textColor = bannerViewData.titleColor + + liveLocationTimerLabel.text = bannerViewData.timeLeftString + liveLocationTimerLabel.isHidden = !bannerViewData.showTimer + + rightButton.setTitle(bannerViewData.rightButtonTitle, for: .normal) + rightButton.isHidden = !bannerViewData.showRightButton + rightButton.tag = bannerViewData.rightButtonTag.rawValue + + placeholderImage.image = bannerViewData.placeholderImage + placeholderImage.isHidden = !bannerViewData.showPlaceholderImage + mapView.isHidden = bannerViewData.showPlaceholderImage } + private func liveLocationBannerViewData(from viewState: TimelineLiveLocationViewState) -> LiveLocationBannerViewData { + let theme = ThemeService.shared().theme + + let iconTint: UIColor + let title: String + var titleColor: UIColor = theme.roomCellLocalisationTextColor + var placeholderImage: UIImage? + var timeLeftString: String? + var rightButtonTitle: String? + var rightButtonTag: RightButtonTag = .stopSharing + + switch viewState { + case .incoming(let liveLocationSharingStatus): + switch liveLocationSharingStatus { + case .started(let timeLeft): + iconTint = theme.roomCellLocalisationStartedColor + title = VectorL10n.liveLocationSharingBannerTitle + timeLeftString = generateTimerString(for: timeLeft, isIncomingLocation: true) + case .stopped: + iconTint = theme.roomCellLocalisationEndedColor + title = VectorL10n.liveLocationSharingEnded + titleColor = theme.roomCellLocalisationEndedColor + placeholderImage = Asset.Images.locationLiveCellEndedImage.image + } + case .outgoing(let liveLocationSharingStatus): + switch liveLocationSharingStatus { + case .starting: + iconTint = theme.roomCellLocalisationEndedColor + title = VectorL10n.locationSharingLiveLoading + titleColor = theme.roomCellLocalisationEndedColor + placeholderImage = Asset.Images.locationLiveCellLoadingImage.image + case .started(let timeLeft): + iconTint = theme.roomCellLocalisationStartedColor + title = VectorL10n.liveLocationSharingBannerTitle + timeLeftString = generateTimerString(for: timeLeft, isIncomingLocation: false) + rightButtonTitle = VectorL10n.stop + case .failure: + iconTint = theme.roomCellLocalisationErrorColor + title = VectorL10n.locationSharingLiveError + titleColor = theme.roomCellLocalisationEndedColor + rightButtonTitle = VectorL10n.retry + rightButtonTag = .retrySharing + case .stopped: + iconTint = theme.roomCellLocalisationEndedColor + title = VectorL10n.liveLocationSharingEnded + titleColor = theme.roomCellLocalisationEndedColor + placeholderImage = Asset.Images.locationLiveCellEndedImage.image + } + } + + return LiveLocationBannerViewData(placeholderImage: placeholderImage, iconTint: iconTint, title: title, titleColor: titleColor, timeLeftString: timeLeftString, rightButtonTitle: rightButtonTitle, rightButtonTag: rightButtonTag) + } + + private func generateTimerString(for timestamp: Double, + isIncomingLocation: Bool) -> String? { + let timerString: String? + if isIncomingLocation { + timerString = VectorL10n.locationSharingLiveTimerIncoming(incomingTimerFormatter.string(from: Date(timeIntervalSince1970: timestamp))) + } else if let outgoingTimer = outgoingTimerFormatter.string(from: Date(timeIntervalSince1970: timestamp).timeIntervalSinceNow) { + timerString = VectorL10n.locationSharingLiveTimerOutgoing(outgoingTimer) + } else { + timerString = nil + } + return timerString + } + + // MARK: - Public + + public func displayStaticLocation(with viewData: RoomTimelineLocationViewData) { + displayLocation(viewData.location, + userAvatarData: viewData.userAvatarData, + mapStyleURL: viewData.mapStyleURL, + bannerViewData: nil) + } + + public func displayLiveLocation(with viewData: RoomTimelineLocationViewData, liveLocationViewState: TimelineLiveLocationViewState) { + let bannerViewData = liveLocationBannerViewData(from: liveLocationViewState) + displayLocation(viewData.location, + userAvatarData: viewData.userAvatarData, + mapStyleURL: viewData.mapStyleURL, + bannerViewData: bannerViewData) + + } + + // MARK: - Themable func update(theme: Theme) { @@ -167,7 +311,11 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat // MARK: - Action - @IBAction private func stopSharingAction(_ sender: Any) { - // TODO: - Stop sharing action + @IBAction private func didTapTightButton(_ sender: Any) { + if rightButton.tag == RightButtonTag.stopSharing.rawValue { + delegate?.didTapStopButton() + } else if rightButton.tag == RightButtonTag.retrySharing.rawValue { + delegate?.didTapRetryButton() + } } } diff --git a/Riot/Modules/Room/Location/RoomTimelineLocationView.xib b/Riot/Modules/Room/Location/RoomTimelineLocationView.xib index c6cdf2ed3..a149fcead 100644 --- a/Riot/Modules/Room/Location/RoomTimelineLocationView.xib +++ b/Riot/Modules/Room/Location/RoomTimelineLocationView.xib @@ -4,7 +4,6 @@ - @@ -15,6 +14,9 @@ + @@ -41,7 +43,7 @@ - + @@ -77,7 +79,7 @@ - + @@ -129,11 +131,14 @@ - + + + + @@ -148,13 +153,14 @@ - + + - + diff --git a/Riot/Modules/Room/MXKRoomViewController.m b/Riot/Modules/Room/MXKRoomViewController.m index a8d79f084..ba1dd3e21 100644 --- a/Riot/Modules/Room/MXKRoomViewController.m +++ b/Riot/Modules/Room/MXKRoomViewController.m @@ -3045,6 +3045,22 @@ [self promptUserToResendEvent:selectedEvent.eventId]; } } + else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellStopShareButtonPressed]) + { + MXEvent *selectedEvent = userInfo[kMXKRoomBubbleCellEventKey]; + if (selectedEvent) + { + // TODO: - Implement stop live location action + } + } + else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellRetryShareButtonPressed]) + { + MXEvent *selectedEvent = userInfo[kMXKRoomBubbleCellEventKey]; + if (selectedEvent) + { + // TODO: - Implement retry live location action + } + } } #pragma mark - Clipboard diff --git a/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.h b/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.h index 8e247835f..15e18f89b 100644 --- a/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.h +++ b/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.h @@ -83,6 +83,20 @@ extern NSString *const kMXKRoomBubbleCellTapOnContentView; */ extern NSString *const kMXKRoomBubbleCellUnsentButtonPressed; +/** + Action identifier used when the user pressed stop share button displayed in live location cell. + + The `userInfo` dictionary contains an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the live location event to stop. + */ +extern NSString *const kMXKRoomBubbleCellStopShareButtonPressed; + +/** + Action identifier used when the user pressed retry share button displayed in live location cell. + + The `userInfo` dictionary contains an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the live location event to retry. + */ +extern NSString *const kMXKRoomBubbleCellRetryShareButtonPressed; + /** Action identifier used when the user long pressed on a displayed event. diff --git a/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.m b/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.m index c4367d598..f5fcdc4ff 100644 --- a/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.m +++ b/Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.m @@ -41,7 +41,10 @@ NSString *const kMXKRoomBubbleCellTapOnAttachmentView = @"kMXKRoomBubbleCellTapO NSString *const kMXKRoomBubbleCellTapOnOverlayContainer = @"kMXKRoomBubbleCellTapOnOverlayContainer"; NSString *const kMXKRoomBubbleCellTapOnContentView = @"kMXKRoomBubbleCellTapOnContentView"; + NSString *const kMXKRoomBubbleCellUnsentButtonPressed = @"kMXKRoomBubbleCellUnsentButtonPressed"; +NSString *const kMXKRoomBubbleCellStopShareButtonPressed = @"kMXKRoomBubbleCellStopShareButtonPressed"; +NSString *const kMXKRoomBubbleCellRetryShareButtonPressed = @"kMXKRoomBubbleCellRetryShareButtonPressed"; NSString *const kMXKRoomBubbleCellLongPressOnEvent = @"kMXKRoomBubbleCellLongPressOnEvent"; NSString *const kMXKRoomBubbleCellLongPressOnProgressView = @"kMXKRoomBubbleCellLongPressOnProgressView"; diff --git a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Location/LocationPlainCell.swift b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Location/LocationPlainCell.swift index 4d47dd775..a8f752f59 100644 --- a/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Location/LocationPlainCell.swift +++ b/Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Location/LocationPlainCell.swift @@ -20,6 +20,7 @@ import MatrixSDK class LocationPlainCell: SizableBaseRoomCell, RoomCellReactionsDisplayable, RoomCellReadMarkerDisplayable { private var locationView: RoomTimelineLocationView! + private var event: MXEvent? override func render(_ cellData: MXKCellData!) { super.render(cellData) @@ -31,6 +32,7 @@ class LocationPlainCell: SizableBaseRoomCell, RoomCellReactionsDisplayable, Room return } + self.event = event locationView.update(theme: ThemeService.shared().theme) // Comment this line and uncomment next one to test UI of live location tile @@ -49,17 +51,19 @@ class LocationPlainCell: SizableBaseRoomCell, RoomCellReactionsDisplayable, Room let mapStyleURL = bubbleData.mxSession.vc_homeserverConfiguration().tileServer.mapStyleURL + let avatarViewData: AvatarViewData? + if locationContent.assetType == .user { - let avatarViewData = AvatarViewData(matrixItemId: bubbleData.senderId, + avatarViewData = AvatarViewData(matrixItemId: bubbleData.senderId, displayName: bubbleData.senderDisplayName, avatarUrl: bubbleData.senderAvatarUrl, mediaManager: bubbleData.mxSession.mediaManager, fallbackImage: .matrixItem(bubbleData.senderId, bubbleData.senderDisplayName)) - - locationView.displayLocation(location, userAvatarData: avatarViewData, mapStyleURL: mapStyleURL) } else { - locationView.displayLocation(location, mapStyleURL: mapStyleURL) + avatarViewData = nil } + + locationView.displayStaticLocation(with: RoomTimelineLocationViewData(location: location, userAvatarData: avatarViewData, mapStyleURL: mapStyleURL)) } private func renderLiveLocation(_ event: MXEvent) { @@ -84,36 +88,11 @@ class LocationPlainCell: SizableBaseRoomCell, RoomCellReactionsDisplayable, Room mediaManager: bubbleData.mxSession.mediaManager, fallbackImage: .matrixItem(bubbleData.senderId, bubbleData.senderDisplayName)) let futurDateTimeInterval = Date(timeIntervalSinceNow: 3734).timeIntervalSince1970 - locationView.displayLocation(location, userAvatarData: avatarViewData, mapStyleURL: mapStyleURL, liveLocationState: .outgoingLive(generateTimerString(for: futurDateTimeInterval, isIncomingLocation: false))) + + locationView.displayLiveLocation(with: RoomTimelineLocationViewData(location: location, userAvatarData: avatarViewData, mapStyleURL: mapStyleURL), + liveLocationViewState: .outgoing(.failure)) } - private func generateTimerString(for timestamp: Double, - isIncomingLocation: Bool) -> String? { - let timerString: String? - if isIncomingLocation { - timerString = VectorL10n.locationSharingLiveTimerIncoming(incomingTimerFormatter.string(from: Date(timeIntervalSince1970: timestamp))) - } else if let outgoingTimer = outgoingTimerFormatter.string(from: Date(timeIntervalSince1970: timestamp).timeIntervalSinceNow) { - timerString = VectorL10n.locationSharingLiveTimerOutgoing(outgoingTimer) - } else { - timerString = nil - } - return timerString - } - - private lazy var incomingTimerFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "HH:mm" - return dateFormatter - }() - - private lazy var outgoingTimerFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - formatter.zeroFormattingBehavior = .dropAll - formatter.allowedUnits = [.hour, .minute, .second] - formatter.unitsStyle = .brief - return formatter - }() - override func setupViews() { super.setupViews() @@ -131,3 +110,21 @@ class LocationPlainCell: SizableBaseRoomCell, RoomCellReactionsDisplayable, Room contentView.vc_addSubViewMatchingParent(locationView) } } + +extension LocationPlainCell: RoomTimelineLocationViewDelegate { + func didTapStopButton() { + guard let event = self.event else { + return + } + + delegate.cell(self, didRecognizeAction: kMXKRoomBubbleCellStopShareButtonPressed, userInfo: [kMXKRoomBubbleCellEventKey: event]) + } + + func didTapRetryButton() { + guard let event = self.event else { + return + } + + delegate.cell(self, didRecognizeAction: kMXKRoomBubbleCellRetryShareButtonPressed, userInfo: [kMXKRoomBubbleCellEventKey: event]) + } +}