mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Allow the services that are configured by secrets to be disabled. (#3961)
* Make the map tiler key optional. * Make the bug report URL optional. * Make the sentry URL optional. * Make the analytics configuration optional and handle consent taking Sentry into account. * Stop prompting users to report crashes when Sentry is disabled.
This commit is contained in:
+3
-1
@@ -10,6 +10,7 @@ import SwiftUI
|
||||
|
||||
struct AuthenticationStartScreenParameters {
|
||||
let webRegistrationEnabled: Bool
|
||||
let isBugReportServiceEnabled: Bool
|
||||
}
|
||||
|
||||
final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
|
||||
@@ -22,7 +23,8 @@ final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
init(parameters: AuthenticationStartScreenParameters) {
|
||||
viewModel = AuthenticationStartScreenViewModel(webRegistrationEnabled: parameters.webRegistrationEnabled)
|
||||
viewModel = AuthenticationStartScreenViewModel(webRegistrationEnabled: parameters.webRegistrationEnabled,
|
||||
isBugReportServiceEnabled: parameters.isBugReportServiceEnabled)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ enum AuthenticationStartScreenViewModelAction {
|
||||
struct AuthenticationStartScreenViewState: BindableState {
|
||||
let isWebRegistrationEnabled: Bool
|
||||
let isQRCodeLoginEnabled: Bool
|
||||
let isBugReportServiceEnabled: Bool
|
||||
}
|
||||
|
||||
enum AuthenticationStartScreenViewAction {
|
||||
|
||||
+3
-2
@@ -17,9 +17,10 @@ class AuthenticationStartScreenViewModel: AuthenticationStartScreenViewModelType
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(webRegistrationEnabled: Bool) {
|
||||
init(webRegistrationEnabled: Bool, isBugReportServiceEnabled: Bool) {
|
||||
super.init(initialViewState: AuthenticationStartScreenViewState(isWebRegistrationEnabled: webRegistrationEnabled,
|
||||
isQRCodeLoginEnabled: !ProcessInfo.processInfo.isiOSAppOnMac))
|
||||
isQRCodeLoginEnabled: !ProcessInfo.processInfo.isiOSAppOnMac,
|
||||
isBugReportServiceEnabled: isBugReportServiceEnabled))
|
||||
}
|
||||
|
||||
override func process(viewAction: AuthenticationStartScreenViewAction) {
|
||||
|
||||
+20
-9
@@ -34,15 +34,17 @@ struct AuthenticationStartScreen: View {
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
.safeAreaInset(edge: .bottom) {
|
||||
Button {
|
||||
context.send(viewAction: .reportProblem)
|
||||
} label: {
|
||||
Text(L10n.commonReportAProblem)
|
||||
.font(.compound.bodySM)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
.padding(.bottom)
|
||||
if context.viewState.isBugReportServiceEnabled {
|
||||
Button {
|
||||
context.send(viewAction: .reportProblem)
|
||||
} label: {
|
||||
Text(L10n.commonReportAProblem)
|
||||
.font(.compound.bodySM)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
.padding(.bottom)
|
||||
}
|
||||
.frame(width: geometry.size.width)
|
||||
}
|
||||
.frame(width: geometry.size.width)
|
||||
}
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
@@ -116,9 +118,18 @@ struct AuthenticationStartScreen: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct AuthenticationStartScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = AuthenticationStartScreenViewModel(webRegistrationEnabled: true)
|
||||
static let viewModel = makeViewModel()
|
||||
static let bugReportDisabledViewModel = makeViewModel(isBugReportServiceEnabled: false)
|
||||
|
||||
static var previews: some View {
|
||||
AuthenticationStartScreen(context: viewModel.context)
|
||||
.previewDisplayName("Default")
|
||||
AuthenticationStartScreen(context: bugReportDisabledViewModel.context)
|
||||
.previewDisplayName("Bug report disabled")
|
||||
}
|
||||
|
||||
static func makeViewModel(isBugReportServiceEnabled: Bool = true) -> AuthenticationStartScreenViewModel {
|
||||
AuthenticationStartScreenViewModel(webRegistrationEnabled: true,
|
||||
isBugReportServiceEnabled: isBugReportServiceEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ struct BugReportScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
let clientProxy = ClientProxyMock(.init(userID: "@mock:client.com", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))))
|
||||
BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
|
||||
BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(.init()),
|
||||
clientProxy: clientProxy,
|
||||
screenshot: nil,
|
||||
isModallyPresented: false).context)
|
||||
@@ -150,7 +150,7 @@ struct BugReportScreen_Previews: PreviewProvider, TestablePreview {
|
||||
|
||||
NavigationStack {
|
||||
let clientProxy = ClientProxyMock(.init(userID: "@mock:client.com", roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))))
|
||||
BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
|
||||
BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(.init()),
|
||||
clientProxy: clientProxy,
|
||||
screenshot: Asset.Images.appLogo.image,
|
||||
isModallyPresented: false).context)
|
||||
|
||||
@@ -87,7 +87,9 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
func start() {
|
||||
#if !DEBUG
|
||||
if bugReportService.crashedLastRun {
|
||||
// Note: bugReportService.isEnabled doesn't determine if a user has opted in to Analytics/Sentry.
|
||||
// Therefore we use lastCrashEventID as this will only be set if we have crash ID from Sentry.
|
||||
if bugReportService.crashedLastRun, bugReportService.lastCrashEventID != nil {
|
||||
viewModel.presentCrashedLastRunAlert()
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ final class AnalyticsPromptScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(analytics: AnalyticsService, termsURL: URL) {
|
||||
init(analytics: AnalyticsService, termsURL: URL?) {
|
||||
self.analytics = analytics
|
||||
viewModel = AnalyticsPromptScreenViewModel(termsURL: termsURL)
|
||||
}
|
||||
|
||||
+14
-10
@@ -33,17 +33,21 @@ struct AnalyticsPromptScreenStrings {
|
||||
let point2 = L10n.screenAnalyticsPromptThirdPartySharing
|
||||
let point3 = L10n.screenAnalyticsPromptSettings
|
||||
|
||||
init(termsURL: URL) {
|
||||
init(termsURL: URL?) {
|
||||
let content = AttributedString(L10n.screenAnalyticsPromptHelpUsImprove)
|
||||
|
||||
// Create the 'read terms' with a placeholder.
|
||||
let linkPlaceholder = "{link}"
|
||||
var readTerms = AttributedString(L10n.screenAnalyticsSettingsReadTerms(linkPlaceholder))
|
||||
var linkString = AttributedString(L10n.screenAnalyticsSettingsReadTermsContentLink)
|
||||
linkString.link = termsURL
|
||||
linkString.bold()
|
||||
readTerms.replace(linkPlaceholder, with: linkString)
|
||||
|
||||
optInContent = content + "\n\n" + readTerms
|
||||
if let termsURL {
|
||||
// Create the 'read terms' with a placeholder.
|
||||
let linkPlaceholder = "{link}"
|
||||
var readTerms = AttributedString(L10n.screenAnalyticsSettingsReadTerms(linkPlaceholder))
|
||||
var linkString = AttributedString(L10n.screenAnalyticsSettingsReadTermsContentLink)
|
||||
linkString.link = termsURL
|
||||
linkString.bold()
|
||||
readTerms.replace(linkPlaceholder, with: linkString)
|
||||
|
||||
optInContent = content + "\n\n" + readTerms
|
||||
} else {
|
||||
optInContent = content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ class AnalyticsPromptScreenViewModel: AnalyticsPromptScreenViewModelType, Analyt
|
||||
}
|
||||
|
||||
/// Initialize a view model with the specified prompt type and app display name.
|
||||
init(termsURL: URL) {
|
||||
init(termsURL: URL?) {
|
||||
let promptStrings = AnalyticsPromptScreenStrings(termsURL: termsURL)
|
||||
super.init(initialViewState: AnalyticsPromptScreenViewState(strings: promptStrings))
|
||||
}
|
||||
|
||||
+10
-1
@@ -91,8 +91,17 @@ struct AnalyticsPromptScreen: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct AnalyticsPromptScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = AnalyticsPromptScreenViewModel(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL)
|
||||
static let viewModel = makeViewModel()
|
||||
static let noTermsViewModel = makeViewModel(showTerms: false)
|
||||
|
||||
static var previews: some View {
|
||||
AnalyticsPromptScreen(context: viewModel.context)
|
||||
.previewDisplayName("Default")
|
||||
AnalyticsPromptScreen(context: noTermsViewModel.context)
|
||||
.previewDisplayName("No terms")
|
||||
}
|
||||
|
||||
static func makeViewModel(showTerms: Bool = true) -> AnalyticsPromptScreenViewModel {
|
||||
AnalyticsPromptScreenViewModel(termsURL: showTerms ? ServiceLocator.shared.settings.analyticsTermsURL : nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ struct ComposerToolbarViewState: BindableState {
|
||||
var audioRecorderState: AudioRecorderState
|
||||
|
||||
var isRoomEncrypted: Bool
|
||||
var isLocationSharingEnabled: Bool
|
||||
|
||||
var bindings: ComposerToolbarViewStateBindings
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
||||
completionSuggestionService: CompletionSuggestionServiceProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
mentionDisplayHelper: MentionDisplayHelper,
|
||||
appSettings: AppSettings,
|
||||
analyticsService: AnalyticsService,
|
||||
composerDraftService: ComposerDraftServiceProtocol) {
|
||||
self.initialText = initialText
|
||||
@@ -65,6 +66,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
||||
super.init(initialViewState: ComposerToolbarViewState(audioPlayerState: .init(id: .recorderPreview, title: L10n.commonVoiceMessage, duration: 0),
|
||||
audioRecorderState: .init(),
|
||||
isRoomEncrypted: roomProxy.infoPublisher.value.isEncrypted,
|
||||
isLocationSharingEnabled: appSettings.mapTilerConfiguration.isEnabled,
|
||||
bindings: .init()),
|
||||
mediaProvider: mediaProvider)
|
||||
|
||||
|
||||
@@ -319,6 +319,7 @@ struct ComposerToolbar_Previews: PreviewProvider, TestablePreview {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init(suggestions: suggestions)),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
|
||||
@@ -369,6 +370,7 @@ extension ComposerToolbar {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
model.state.composerEmpty = focused
|
||||
@@ -387,6 +389,7 @@ extension ComposerToolbar {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
model.state.composerEmpty = focused
|
||||
@@ -405,6 +408,7 @@ extension ComposerToolbar {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
model.state.composerMode = .recordVoiceMessage(state: AudioRecorderState())
|
||||
@@ -424,6 +428,7 @@ extension ComposerToolbar {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
model.state.composerMode = .previewVoiceMessage(state: AudioPlayerState(id: .recorderPreview,
|
||||
@@ -446,6 +451,7 @@ extension ComposerToolbar {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
model.state.composerMode = isLoading ? .reply(eventID: UUID().uuidString,
|
||||
@@ -470,6 +476,7 @@ extension ComposerToolbar {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
model.state.canSend = false
|
||||
|
||||
@@ -47,12 +47,14 @@ struct RoomAttachmentPicker: View {
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomScreen.attachmentPickerPoll)
|
||||
|
||||
Button {
|
||||
context.send(viewAction: .attach(.location))
|
||||
} label: {
|
||||
Label(L10n.screenRoomAttachmentSourceLocation, icon: \.locationPin)
|
||||
if context.viewState.isLocationSharingEnabled {
|
||||
Button {
|
||||
context.send(viewAction: .attach(.location))
|
||||
} label: {
|
||||
Label(L10n.screenRoomAttachmentSourceLocation, icon: \.locationPin)
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomScreen.attachmentPickerLocation)
|
||||
}
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomScreen.attachmentPickerLocation)
|
||||
|
||||
Button {
|
||||
context.send(viewAction: .attach(.file))
|
||||
@@ -91,6 +93,7 @@ struct RoomAttachmentPicker_Previews: PreviewProvider, TestablePreview {
|
||||
completionSuggestionService: CompletionSuggestionServiceMock(configuration: .init()),
|
||||
mediaProvider: MediaProviderMock(configuration: .init()),
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: ComposerDraftServiceMock())
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
mediaProvider: parameters.mediaProvider,
|
||||
ongoingCallRoomIDPublisher: parameters.ongoingCallRoomIDPublisher,
|
||||
appMediator: parameters.appMediator,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
appSettings: parameters.appSettings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
@@ -99,6 +99,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
completionSuggestionService: parameters.completionSuggestionService,
|
||||
mediaProvider: parameters.mediaProvider,
|
||||
mentionDisplayHelper: ComposerMentionDisplayHelper(timelineContext: timelineViewModel.context),
|
||||
appSettings: parameters.appSettings,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
composerDraftService: parameters.composerDraftService)
|
||||
self.composerViewModel = composerViewModel
|
||||
|
||||
+14
-10
@@ -24,17 +24,21 @@ enum AnalyticsSettingsScreenViewAction {
|
||||
struct AnalyticsSettingsScreenStrings {
|
||||
let sectionFooter: AttributedString
|
||||
|
||||
init(termsURL: URL) {
|
||||
init(termsURL: URL?) {
|
||||
let content = AttributedString(L10n.screenAnalyticsPromptHelpUsImprove)
|
||||
|
||||
// Create the 'read terms' with a placeholder.
|
||||
let linkPlaceholder = "{link}"
|
||||
var readTerms = AttributedString(L10n.screenAnalyticsSettingsReadTerms(linkPlaceholder))
|
||||
var linkString = AttributedString(L10n.screenAnalyticsSettingsReadTermsContentLink)
|
||||
linkString.link = termsURL
|
||||
linkString.bold()
|
||||
readTerms.replace(linkPlaceholder, with: linkString)
|
||||
|
||||
sectionFooter = content + "\n\n" + readTerms
|
||||
if let termsURL {
|
||||
// Create the 'read terms' with a placeholder.
|
||||
let linkPlaceholder = "{link}"
|
||||
var readTerms = AttributedString(L10n.screenAnalyticsSettingsReadTerms(linkPlaceholder))
|
||||
var linkString = AttributedString(L10n.screenAnalyticsSettingsReadTermsContentLink)
|
||||
linkString.link = termsURL
|
||||
linkString.bold()
|
||||
readTerms.replace(linkPlaceholder, with: linkString)
|
||||
|
||||
sectionFooter = content + "\n\n" + readTerms
|
||||
} else {
|
||||
sectionFooter = content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ class AnalyticsSettingsScreenViewModel: AnalyticsSettingsScreenViewModelType, An
|
||||
init(appSettings: AppSettings, analytics: AnalyticsService) {
|
||||
self.analytics = analytics
|
||||
|
||||
let strings = AnalyticsSettingsScreenStrings(termsURL: appSettings.analyticsConfiguration.termsURL)
|
||||
let strings = AnalyticsSettingsScreenStrings(termsURL: appSettings.analyticsTermsURL)
|
||||
let bindings = AnalyticsSettingsScreenViewStateBindings(enableAnalytics: analytics.isEnabled)
|
||||
let state = AnalyticsSettingsScreenViewState(strings: strings, bindings: bindings)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import SwiftUI
|
||||
struct SettingsScreenCoordinatorParameters {
|
||||
let userSession: UserSessionProtocol
|
||||
let appSettings: AppSettings
|
||||
let isBugReportServiceEnabled: Bool
|
||||
}
|
||||
|
||||
enum SettingsScreenCoordinatorAction {
|
||||
@@ -43,7 +44,9 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||
// MARK: - Setup
|
||||
|
||||
init(parameters: SettingsScreenCoordinatorParameters) {
|
||||
viewModel = SettingsScreenViewModel(userSession: parameters.userSession)
|
||||
viewModel = SettingsScreenViewModel(userSession: parameters.userSession,
|
||||
appSettings: parameters.appSettings,
|
||||
isBugReportServiceEnabled: parameters.isBugReportServiceEnabled)
|
||||
|
||||
viewModel.actions
|
||||
.sink { [weak self] action in
|
||||
|
||||
@@ -44,6 +44,9 @@ struct SettingsScreenViewState: BindableState {
|
||||
var showSecuritySectionBadge = false
|
||||
|
||||
var showBlockedUsers = false
|
||||
let showAnalyticsSettings: Bool
|
||||
|
||||
let isBugReportServiceEnabled: Bool
|
||||
|
||||
var bindings = SettingsScreenViewStateBindings()
|
||||
}
|
||||
|
||||
@@ -17,11 +17,13 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(userSession: UserSessionProtocol) {
|
||||
init(userSession: UserSessionProtocol, appSettings: AppSettings, isBugReportServiceEnabled: Bool) {
|
||||
super.init(initialViewState: .init(deviceID: userSession.clientProxy.deviceID,
|
||||
userID: userSession.clientProxy.userID,
|
||||
showAccountDeactivation: userSession.clientProxy.canDeactivateAccount,
|
||||
showDeveloperOptions: AppSettings.isDevelopmentBuild),
|
||||
showDeveloperOptions: AppSettings.isDevelopmentBuild,
|
||||
showAnalyticsSettings: appSettings.canPromptForAnalytics,
|
||||
isBugReportServiceEnabled: isBugReportServiceEnabled),
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
userSession.clientProxy.userAvatarURLPublisher
|
||||
|
||||
@@ -140,19 +140,23 @@ struct SettingsScreen: View {
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.about)
|
||||
|
||||
ListRow(label: .default(title: L10n.commonReportAProblem,
|
||||
icon: \.chatProblem),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .reportBug)
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.reportBug)
|
||||
if context.viewState.isBugReportServiceEnabled {
|
||||
ListRow(label: .default(title: L10n.commonReportAProblem,
|
||||
icon: \.chatProblem),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .reportBug)
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.reportBug)
|
||||
}
|
||||
|
||||
ListRow(label: .default(title: L10n.commonAnalytics,
|
||||
icon: \.chart),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .analytics)
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.analytics)
|
||||
if context.viewState.showAnalyticsSettings {
|
||||
ListRow(label: .default(title: L10n.commonAnalytics,
|
||||
icon: \.chart),
|
||||
kind: .navigationLink {
|
||||
context.send(viewAction: .analytics)
|
||||
})
|
||||
.accessibilityIdentifier(A11yIdentifiers.settingsScreen.analytics)
|
||||
}
|
||||
|
||||
ListRow(label: .default(title: L10n.commonAdvancedSettings,
|
||||
icon: \.settings),
|
||||
@@ -230,18 +234,32 @@ struct SettingsScreen: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct SettingsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = {
|
||||
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com",
|
||||
deviceID: "AAAAAAAAAAA"))))
|
||||
return SettingsScreenViewModel(userSession: userSession)
|
||||
}()
|
||||
static let viewModel = makeViewModel()
|
||||
static let bugReportDisabledViewModel = makeViewModel(isBugReportServiceEnabled: false)
|
||||
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
SettingsScreen(context: viewModel.context)
|
||||
.snapshotPreferences(expect: viewModel.context.$viewState.map { state in
|
||||
state.accountSessionsListURL != nil
|
||||
})
|
||||
}
|
||||
.snapshotPreferences(expect: viewModel.context.$viewState.map { state in
|
||||
state.accountSessionsListURL != nil
|
||||
})
|
||||
.previewDisplayName("Default")
|
||||
|
||||
NavigationStack {
|
||||
SettingsScreen(context: bugReportDisabledViewModel.context)
|
||||
}
|
||||
.snapshotPreferences(expect: bugReportDisabledViewModel.context.$viewState.map { state in
|
||||
state.accountSessionsListURL != nil
|
||||
})
|
||||
.previewDisplayName("Bug report disabled")
|
||||
}
|
||||
|
||||
static func makeViewModel(isBugReportServiceEnabled: Bool = true) -> SettingsScreenViewModel {
|
||||
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com",
|
||||
deviceID: "AAAAAAAAAAA"))))
|
||||
return SettingsScreenViewModel(userSession: userSession,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
isBugReportServiceEnabled: isBugReportServiceEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ struct TimelineViewState: BindableState {
|
||||
|
||||
var emojiProvider: EmojiProviderProtocol
|
||||
|
||||
var mapURLBuilder: MapTilerURLBuilderProtocol
|
||||
var mapTilerConfiguration: MapTilerConfiguration
|
||||
|
||||
var bindings: TimelineViewStateBindings
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
hideTimelineMedia: appSettings.hideTimelineMedia,
|
||||
pinnedEventIDs: roomProxy.infoPublisher.value.pinnedEventIDs,
|
||||
emojiProvider: emojiProvider,
|
||||
mapURLBuilder: appSettings.mapTilerConfiguration,
|
||||
mapTilerConfiguration: appSettings.mapTilerConfiguration,
|
||||
bindings: .init(reactionsCollapsed: [:])),
|
||||
mediaProvider: mediaProvider)
|
||||
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ struct LocationRoomTimelineView: View {
|
||||
.accessibilityElement(children: .ignore)
|
||||
.accessibilityLabel(accessibilityLabel)
|
||||
.onTapGesture {
|
||||
guard context.viewState.mapTilerConfiguration.isEnabled else { return }
|
||||
context.send(viewAction: .mediaTapped(itemID: timelineItem.id))
|
||||
}
|
||||
}
|
||||
@@ -30,7 +31,7 @@ struct LocationRoomTimelineView: View {
|
||||
.frame(maxWidth: mapAspectRatio * mapMaxHeight, alignment: .leading)
|
||||
|
||||
MapLibreStaticMapView(geoURI: geoURI,
|
||||
mapURLBuilder: context.viewState.mapURLBuilder,
|
||||
mapURLBuilder: context.viewState.mapTilerConfiguration,
|
||||
mapSize: .init(width: mapAspectRatio * mapMaxHeight, height: mapMaxHeight)) {
|
||||
LocationMarkerView()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user