mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Add a LocationSharingSettingsScreen. (#6281)
This commit is contained in:
@@ -90,6 +90,7 @@ enum TestablePreviewsDictionary {
|
||||
"LocationPickerSheet_Previews" : LocationPickerSheet_Previews.self,
|
||||
"LocationRoomTimelineView_Previews" : LocationRoomTimelineView_Previews.self,
|
||||
"LocationSharingScreen_Previews" : LocationSharingScreen_Previews.self,
|
||||
"LocationSharingSettingsScreen_Previews" : LocationSharingSettingsScreen_Previews.self,
|
||||
"LongPressWithFeedback_Previews" : LongPressWithFeedback_Previews.self,
|
||||
"ManageAuthorizedSpacesScreen_Previews" : ManageAuthorizedSpacesScreen_Previews.self,
|
||||
"ManageRoomMemberSheetView_Previews" : ManageRoomMemberSheetView_Previews.self,
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct LocationSharingSettingsScreenCoordinatorParameters {
|
||||
let userSettings: UserSettings
|
||||
}
|
||||
|
||||
final class LocationSharingSettingsScreenCoordinator: CoordinatorProtocol {
|
||||
private var viewModel: LocationSharingSettingsScreenViewModelProtocol
|
||||
|
||||
init(parameters: LocationSharingSettingsScreenCoordinatorParameters) {
|
||||
viewModel = LocationSharingSettingsScreenViewModel(userSettings: parameters.userSettings)
|
||||
}
|
||||
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(LocationSharingSettingsScreen(context: viewModel.context))
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
struct LocationSharingSettingsScreenViewState: BindableState {
|
||||
init(bindings: LocationSharingSettingsScreenViewStateBindings) {
|
||||
self.bindings = bindings
|
||||
|
||||
let linkPlaceholder = "{link}"
|
||||
var footerString = AttributedString(L10n.screenAdvancedSettingsLiveLocationSectionFooter(linkPlaceholder))
|
||||
var linkString = AttributedString(L10n.screenAdvancedSettingsLiveLocationSectionFooterLink)
|
||||
linkString.link = URL(string: UIApplication.openSettingsURLString)
|
||||
linkString.bold()
|
||||
footerString.replace(linkPlaceholder, with: linkString)
|
||||
liveLocationUpdateFooterAttributedString = footerString
|
||||
}
|
||||
|
||||
let liveLocationUpdateFooterAttributedString: AttributedString
|
||||
var bindings: LocationSharingSettingsScreenViewStateBindings
|
||||
}
|
||||
|
||||
struct LocationSharingSettingsScreenViewStateBindings {
|
||||
private let userSettings: UserSettings
|
||||
|
||||
init(userSettings: UserSettings) {
|
||||
self.userSettings = userSettings
|
||||
}
|
||||
|
||||
var liveLocationMinimumDistanceUpdate: Int {
|
||||
get { userSettings.liveLocationMinimumDistanceUpdate }
|
||||
set { userSettings.liveLocationMinimumDistanceUpdate = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
enum LocationSharingSettingsScreenViewAction { }
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias LocationSharingSettingsScreenViewModelType = StateStoreViewModelV2<LocationSharingSettingsScreenViewState, LocationSharingSettingsScreenViewAction>
|
||||
|
||||
class LocationSharingSettingsScreenViewModel: LocationSharingSettingsScreenViewModelType, LocationSharingSettingsScreenViewModelProtocol {
|
||||
init(userSettings: UserSettings) {
|
||||
let state = LocationSharingSettingsScreenViewState(bindings: .init(userSettings: userSettings))
|
||||
super.init(initialViewState: state)
|
||||
}
|
||||
|
||||
override func process(viewAction: LocationSharingSettingsScreenViewAction) { }
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
|
||||
protocol LocationSharingSettingsScreenViewModelProtocol {
|
||||
var context: LocationSharingSettingsScreenViewModelType.Context { get }
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Compound
|
||||
import SwiftUI
|
||||
|
||||
struct LocationSharingSettingsScreen: View {
|
||||
static let measurementFormatter = {
|
||||
let formatter = MeasurementFormatter()
|
||||
formatter.unitOptions = .providedUnit
|
||||
formatter.unitStyle = .short
|
||||
return formatter
|
||||
}()
|
||||
|
||||
@Bindable var context: LocationSharingSettingsScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
liveLocationSection
|
||||
}
|
||||
.compoundList()
|
||||
.navigationTitle(L10n.commonLocationSharing)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var liveLocationSection: some View {
|
||||
let binding = Binding(get: {
|
||||
Double(context.liveLocationMinimumDistanceUpdate)
|
||||
}, set: { newValue in
|
||||
context.liveLocationMinimumDistanceUpdate = Int(newValue)
|
||||
})
|
||||
|
||||
Section {
|
||||
ListRow(kind: .custom {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text(L10n.screenAdvancedSettingsLiveLocationUpdateDistance(context.liveLocationMinimumDistanceUpdate))
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundStyle(.compound.textPrimary)
|
||||
// The internal hidden label of the slider will read voice over
|
||||
.accessibilityHidden(true)
|
||||
Slider(value: binding, in: 1...100) {
|
||||
Text(L10n.screenAdvancedSettingsLiveLocationUpdateDistance(context.liveLocationMinimumDistanceUpdate))
|
||||
} minimumValueLabel: {
|
||||
Text(Self.measurementFormatter.string(from: .init(value: 1,
|
||||
unit: UnitLength.meters)))
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundStyle(.compound.textSecondary)
|
||||
.padding(.trailing, 15)
|
||||
} maximumValueLabel: {
|
||||
Text(Self.measurementFormatter.string(from: .init(value: 100,
|
||||
unit: UnitLength.meters)))
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundStyle(.compound.textSecondary)
|
||||
.padding(.leading, 15)
|
||||
}
|
||||
.tint(.compound.iconAccentPrimary)
|
||||
}
|
||||
.padding(.horizontal, ListRowPadding.horizontal)
|
||||
.padding(.vertical, ListRowPadding.vertical)
|
||||
})
|
||||
} header: {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(L10n.screenAdvancedSettingsLiveLocationSectionTitle)
|
||||
.compoundListSectionHeader()
|
||||
Text(L10n.screenAdvancedSettingsLiveLocationSectionDescription)
|
||||
.font(.compound.bodyMD)
|
||||
.foregroundStyle(.compound.textSecondary)
|
||||
}
|
||||
} footer: {
|
||||
Text(context.viewState.liveLocationUpdateFooterAttributedString)
|
||||
.compoundListSectionFooter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct LocationSharingSettingsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = LocationSharingSettingsScreenViewModel(userSettings: .mock())
|
||||
|
||||
static var previews: some View {
|
||||
ElementNavigationStack {
|
||||
LocationSharingSettingsScreen(context: viewModel.context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension TimelineMediaVisibility {
|
||||
static var items: [(title: String, tag: TimelineMediaVisibility)] {
|
||||
[(title: L10n.screenAdvancedSettingsShowMediaTimelineAlwaysHide, tag: .never),
|
||||
(title: L10n.screenAdvancedSettingsShowMediaTimelinePrivateRooms, tag: .privateOnly),
|
||||
(title: L10n.screenAdvancedSettingsShowMediaTimelineAlwaysShow, tag: .always)]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user