Skip to content

Commit

Permalink
Merge pull request #5859 from vector-im/maximee/5720_location_sharing…
Browse files Browse the repository at this point in the history
…_UI_change

Update UI in location sharing view #5720
  • Loading branch information
MaximeEvrard42 authored Mar 24, 2022
2 parents 46e0bce + 064c974 commit 5a4c5e5
Show file tree
Hide file tree
Showing 34 changed files with 301 additions and 49 deletions.
1 change: 0 additions & 1 deletion DesignKit/Source/Colors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,4 @@ public protocol Colors {
/// - Names in chat timeline
/// - Avatars default states that include first name letter
var namesAndAvatars: [ColorType] { get }

}
2 changes: 1 addition & 1 deletion DesignKit/Source/ColorsUIkit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import UIKit
public let background: UIColor

public let namesAndAvatars: [UIColor]

init(values: ColorValues) {
accent = values.accent
alert = values.alert
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "location_live_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "location_pin_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,8 @@
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
6 changes: 3 additions & 3 deletions Riot/Assets/en.lproj/Vector.strings
Original file line number Diff line number Diff line change
Expand Up @@ -2068,8 +2068,6 @@ Tap the + to start adding people.";

"location_sharing_close_action" = "Close";

"location_sharing_share_action" = "Share";

"location_sharing_post_failure_title" = "We couldn’t send your location";

"location_sharing_post_failure_subtitle" = "%@ could not send your location. Please try again later.";
Expand All @@ -2096,9 +2094,11 @@ Tap the + to start adding people.";

// MARK: Live location sharing

"location_sharing_live_share_title" = "Share live location";
"live_location_sharing_banner_title" = "Live location enabled";
"live_location_sharing_banner_stop" = "Stop";

"location_sharing_static_share_title" = "Send my current location";
"location_sharing_pin_drop_share_title" = "Send this location";

// MARK: - MatrixKit

Expand Down
2 changes: 2 additions & 0 deletions Riot/Generated/Images.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ internal class Asset: NSObject {
internal static let voiceCallHangonIcon = ImageAsset(name: "voice_call_hangon_icon")
internal static let voiceCallHangupIcon = ImageAsset(name: "voice_call_hangup_icon")
internal static let liveLocationIcon = ImageAsset(name: "live_location_icon")
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")
internal static let locationShareIcon = ImageAsset(name: "location_share_icon")
internal static let locationUserMarker = ImageAsset(name: "location_user_marker")
internal static let pollCheckboxDefault = ImageAsset(name: "poll_checkbox_default")
Expand Down
14 changes: 11 additions & 3 deletions Riot/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2751,6 +2751,10 @@ public class VectorL10n: NSObject {
public static var locationSharingInvalidAuthorizationSettings: String {
return VectorL10n.tr("Vector", "location_sharing_invalid_authorization_settings")
}
/// Share live location
public static var locationSharingLiveShareTitle: String {
return VectorL10n.tr("Vector", "location_sharing_live_share_title")
}
/// %@ could not load the map. Please try again later.
public static func locationSharingLoadingMapErrorTitle(_ p1: String) -> String {
return VectorL10n.tr("Vector", "location_sharing_loading_map_error_title", p1)
Expand All @@ -2771,6 +2775,10 @@ public class VectorL10n: NSObject {
public static var locationSharingOpenOpenStreetMaps: String {
return VectorL10n.tr("Vector", "location_sharing_open_open_street_maps")
}
/// Send this location
public static var locationSharingPinDropShareTitle: String {
return VectorL10n.tr("Vector", "location_sharing_pin_drop_share_title")
}
/// %@ could not send your location. Please try again later.
public static func locationSharingPostFailureSubtitle(_ p1: String) -> String {
return VectorL10n.tr("Vector", "location_sharing_post_failure_subtitle", p1)
Expand All @@ -2787,9 +2795,9 @@ public class VectorL10n: NSObject {
public static var locationSharingSettingsToggleTitle: String {
return VectorL10n.tr("Vector", "location_sharing_settings_toggle_title")
}
/// Share
public static var locationSharingShareAction: String {
return VectorL10n.tr("Vector", "location_sharing_share_action")
/// Send my current location
public static var locationSharingStaticShareTitle: String {
return VectorL10n.tr("Vector", "location_sharing_static_share_title")
}
/// Location
public static var locationSharingTitle: String {
Expand Down
5 changes: 4 additions & 1 deletion Riot/Modules/Room/Location/LocationMarkerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ import Mapbox

class LocationMarkerView: MGLAnnotationView, NibLoadable {

@IBOutlet private var backgroundImageView: UIImageView!
@IBOutlet private var avatarView: UserAvatarView!

override func awakeFromNib() {
super.awakeFromNib()
translatesAutoresizingMaskIntoConstraints = false
}

func setAvatarData(_ avatarData: AvatarViewDataProtocol) {
func setAvatarData(_ avatarData: AvatarViewDataProtocol, avatarBackgroundColor: UIColor) {
backgroundImageView.image = Asset.Images.locationUserMarker.image
backgroundImageView.tintColor = avatarBackgroundColor
avatarView.fill(with: avatarData)
}
}
7 changes: 3 additions & 4 deletions Riot/Modules/Room/Location/LocationMarkerView.xib
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
Expand Down Expand Up @@ -65,6 +63,7 @@
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="avatarView" destination="qut-wn-BX3" id="wHA-bz-A2y"/>
<outlet property="backgroundImageView" destination="ldO-kc-R5W" id="52a-Fs-iu7"/>
</connections>
<point key="canvasLocation" x="58.695652173913047" y="4.6875"/>
</view>
Expand Down
5 changes: 4 additions & 1 deletion Riot/Modules/Room/Location/RoomTimelineLocationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat

private var mapView: MGLMapView!
private var annotationView: LocationMarkerView?
private static var usernameColorGenerator = UserNameColorGenerator()

// MARK: Public

Expand Down Expand Up @@ -82,7 +83,8 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
annotationView = LocationMarkerView.loadFromNib()

if let userAvatarData = userAvatarData {
annotationView?.setAvatarData(userAvatarData)
let avatarBackgroundColor = Self.usernameColorGenerator.color(from: userAvatarData.matrixItemId)
annotationView?.setAvatarData(userAvatarData, avatarBackgroundColor: avatarBackgroundColor)
}

if let annotations = mapView.annotations {
Expand All @@ -99,6 +101,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
// MARK: - Themable

func update(theme: Theme) {
Self.usernameColorGenerator.update(theme: theme)
descriptionLabel.textColor = theme.colors.primaryContent
descriptionLabel.font = theme.fonts.footnote
descriptionIcon.tintColor = theme.colors.accent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ extension ThreadTableViewCell: Themable {

func update(theme: Theme) {
self.theme = theme
Self.usernameColorGenerator.defaultColor = theme.colors.primaryContent
Self.usernameColorGenerator.userNameColors = theme.colors.namesAndAvatars
Self.usernameColorGenerator.update(theme: theme)
updateRootMessageSenderColor()
rootMessageAvatarView.backgroundColor = .clear
if let attributedText = rootMessageContentLabel.attributedText {
Expand Down
9 changes: 9 additions & 0 deletions Riot/Utils/UserNameColorGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,12 @@ final class UserNameColorGenerator: NSObject {
return self.userNameColors[senderNameColorIndex]
}
}

// MARK: - Themable
extension UserNameColorGenerator: Themable {

func update(theme: Theme) {
self.defaultColor = theme.colors.primaryContent
self.userNameColors = theme.colors.namesAndAvatars
}
}
15 changes: 14 additions & 1 deletion RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct AvatarImage: View {
.resizable()
}
}
.frame(width: CGFloat(size.rawValue), height: CGFloat(size.rawValue))
.frame(maxWidth: CGFloat(size.rawValue), maxHeight: CGFloat(size.rawValue))
.clipShape(Circle())
.onAppear {
viewModel.inject(dependencies: dependencies)
Expand All @@ -69,6 +69,19 @@ extension AvatarImage {
}
}

@available(iOS 14.0, *)
extension AvatarImage {
func border(color: Color) -> some View {
modifier(BorderModifier(color: color, borderWidth: 3, shape: Circle()))
}

/// Use display name color as border color by default
func border() -> some View {
let borderColor = theme.userColor(for: matrixItemId)
return self.border(color: borderColor)
}
}

@available(iOS 14.0, *)
struct AvatarImage_Previews: PreviewProvider {
static let mxContentUri = "fakeUri"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class AvatarViewModel: InjectableObject, ObservableObject {
return
}

avatarService.avatarImage(mxContentUri: mxContentUri, avatarSize: avatarSize)
avatarService.avatarImage(mxContentUri: mxContentUri, avatarSize: avatarSize)
.sink { completion in
guard case let .failure(error) = completion else { return }
UILog.error("[AvatarService] Failed to retrieve avatar: \(error)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import SwiftUI
@available(iOS 14.0, *)
extension ThemeSwiftUI {

/// Get the stable display name color based on userId.
/// Get the stable display user color based on userId.
/// - Parameter userId: The user id used to hash.
/// - Returns: The SwiftUI color for the associated userId.
func displayNameColor(for userId: String) -> Color {
func userColor(for userId: String) -> Color {
let senderNameColorIndex = Int(userId.vc_hashCode % Int32(colors.namesAndAvatars.count))
return colors.namesAndAvatars[senderNameColorIndex]
}
Expand Down
37 changes: 37 additions & 0 deletions RiotSwiftUI/Modules/Common/Util/BorderModifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Copyright 2022 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 SwiftUI

@available(iOS 14.0, *)
struct BorderModifier<Shape: InsettableShape>: ViewModifier {

var color: Color
var borderWidth: CGFloat
var shape: Shape

func body(content: Content) -> some View {
content
.overlay(shape.stroke(color, lineWidth: borderWidth))
}
}

@available(iOS 14.0, *)
extension View {
func shapedBorder<Shape: InsettableShape>(color: Color, borderWidth: CGFloat, shape: Shape) -> some View {
modifier(BorderModifier(color: color, borderWidth: borderWidth, shape: shape))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ final class LocationSharingCoordinator: Coordinator, Presentable {

let viewModel = LocationSharingViewModel(mapStyleURL: BuildSettings.tileServerMapStyleURL,
avatarData: parameters.avatarData,
location: parameters.location)
location: parameters.location,
isLiveLocationSharingEnabled: BuildSettings.liveLocationSharingEnabled)
let view = LocationSharingView(context: viewModel.context)
.addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,17 @@ struct LocationSharingViewState: BindableState {
/// Map annotation to focus on
var highlightedAnnotation: UserLocationAnnotation?

/// Indicates whether the user has moved around the map to drop a pin somewhere other than their current location
var isPinDropSharing: Bool = false

var showLoadingIndicator: Bool = false

/// True to indicate to show and follow current user location
var showsUserLocation: Bool = false

/// Used to hide live location sharing features until is finished
var isLiveLocationSharingEnabled: Bool = false

var shareButtonVisible: Bool {
return self.displayExistingLocation == false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ enum MockLocationSharingScreenState: MockScreenState, CaseIterable {

let mapStyleURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx")!
let viewModel = LocationSharingViewModel(mapStyleURL: mapStyleURL,
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "", displayName: "Alice"),
location: location)
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "alice:matrix.org", displayName: "Alice"),
location: location,
isLiveLocationSharingEnabled: true)
return ([viewModel],
AnyView(LocationSharingView(context: viewModel.context)
.addDependency(MockAvatarService.example)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie

// MARK: - Setup

init(mapStyleURL: URL, avatarData: AvatarInputProtocol, location: CLLocationCoordinate2D? = nil) {
init(mapStyleURL: URL, avatarData: AvatarInputProtocol, location: CLLocationCoordinate2D? = nil, isLiveLocationSharingEnabled: Bool = false) {

var userAnnotation: UserLocationAnnotation?
var annotations: [UserLocationAnnotation] = []
Expand All @@ -60,7 +60,8 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie
userAnnotation: userAnnotation,
annotations: annotations,
highlightedAnnotation: highlightedAnnotation,
showsUserLocation: showsUserLocation)
showsUserLocation: showsUserLocation,
isLiveLocationSharingEnabled: isLiveLocationSharingEnabled)

super.init(initialViewState: viewState)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class LocationSharingUITests: XCTestCase {
goToScreenWithIdentifier(MockLocationSharingScreenState.shareUserLocation.title)

XCTAssertTrue(app.buttons["Cancel"].exists)
XCTAssertTrue(app.buttons["Share"].exists)
XCTAssertTrue(app.otherElements["Map"].exists)
}

Expand Down
Loading

0 comments on commit 5a4c5e5

Please sign in to comment.