Skip to content

Commit

Permalink
Fixes #1699 - Introduce a new advanced settings screen (#1700)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanceriu authored Sep 14, 2023
1 parent 21856e9 commit 761d508
Show file tree
Hide file tree
Showing 18 changed files with 309 additions and 75 deletions.
60 changes: 48 additions & 12 deletions ElementX.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions ElementX/Resources/Localizations/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"action_yes" = "Yes";
"common_about" = "About";
"common_acceptable_use_policy" = "Acceptable use policy";
"common_advanced_settings" = "Advanced settings";
"common_analytics" = "Analytics";
"common_audio" = "Audio";
"common_bubbles" = "Bubbles";
Expand Down Expand Up @@ -108,6 +109,7 @@
"common_replying_to" = "Replying to %1$@";
"common_report_a_bug" = "Report a bug";
"common_report_submitted" = "Report submitted";
"common_rich_text_editor" = "Rich text editor";
"common_room_name" = "Room name";
"common_room_name_placeholder" = "e.g. your project name";
"common_search_for_someone" = "Search for someone";
Expand Down
4 changes: 4 additions & 0 deletions ElementX/Sources/Application/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ final class AppSettings {
case pusherProfileTag
case logLevel
case otlpTracingEnabled
case viewSourceEnabled

// Feature flags
case shouldCollapseRoomStateEvents
Expand Down Expand Up @@ -188,6 +189,9 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.shouldCollapseRoomStateEvents, defaultValue: true, storageType: .volatile)
var shouldCollapseRoomStateEvents

@UserPreference(key: UserDefaultsKeys.viewSourceEnabled, defaultValue: false, storageType: .userDefaults(store))
var viewSourceEnabled

// MARK: - Notifications

@UserPreference(key: UserDefaultsKeys.enableNotifications, defaultValue: true, storageType: .userDefaults(store))
Expand Down
4 changes: 4 additions & 0 deletions ElementX/Sources/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ public enum L10n {
public static var commonAbout: String { return L10n.tr("Localizable", "common_about") }
/// Acceptable use policy
public static var commonAcceptableUsePolicy: String { return L10n.tr("Localizable", "common_acceptable_use_policy") }
/// Advanced settings
public static var commonAdvancedSettings: String { return L10n.tr("Localizable", "common_advanced_settings") }
/// Analytics
public static var commonAnalytics: String { return L10n.tr("Localizable", "common_analytics") }
/// Audio
Expand Down Expand Up @@ -248,6 +250,8 @@ public enum L10n {
public static var commonReportABug: String { return L10n.tr("Localizable", "common_report_a_bug") }
/// Report submitted
public static var commonReportSubmitted: String { return L10n.tr("Localizable", "common_report_submitted") }
/// Rich text editor
public static var commonRichTextEditor: String { return L10n.tr("Localizable", "common_rich_text_editor") }
/// Room name
public static var commonRoomName: String { return L10n.tr("Localizable", "common_room_name") }
/// e.g. your project name
Expand Down
1 change: 1 addition & 0 deletions ElementX/Sources/Other/AccessibilityIdentifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ struct A11yIdentifiers {
let analytics = "settings-analytics"
let reportBug = "settings-report_bug"
let about = "settings_about"
let advancedSettings = "settings_advanced-settings"
let developerOptions = "settings_developer-options"
let logout = "settings-logout"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
return nil
}

var debugActions: [TimelineItemMenuAction] = appSettings.canShowDeveloperOptions ? [.viewSource] : []
var debugActions: [TimelineItemMenuAction] = []
if appSettings.canShowDeveloperOptions || appSettings.viewSourceEnabled {
debugActions.append(.viewSource)
}

if let encryptedItem = timelineItem as? EncryptedRoomTimelineItem {
switch encryptedItem.encryptionType {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// 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

enum AdvancedSettingsScreenCoordinatorAction {
case clearCache
}

final class AdvancedSettingsScreenCoordinator: CoordinatorProtocol {
private var viewModel: AdvancedSettingsScreenViewModelProtocol

var callback: ((AdvancedSettingsScreenCoordinatorAction) -> Void)?

init() {
viewModel = AdvancedSettingsScreenViewModel(advancedSettings: ServiceLocator.shared.settings)
}

func toPresentable() -> AnyView {
AnyView(AdvancedSettingsScreen(context: viewModel.context))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// 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 Foundation

enum AdvancedSettingsScreenViewModelAction { }

struct AdvancedSettingsScreenViewState: BindableState {
var bindings: AdvancedSettingsScreenViewStateBindings
}

@dynamicMemberLookup
struct AdvancedSettingsScreenViewStateBindings {
private let advancedSettings: AdvancedSettingsProtocol

init(advancedSettings: AdvancedSettingsProtocol) {
self.advancedSettings = advancedSettings
}

subscript<Setting>(dynamicMember keyPath: ReferenceWritableKeyPath<AdvancedSettingsProtocol, Setting>) -> Setting {
get { advancedSettings[keyPath: keyPath] }
set { advancedSettings[keyPath: keyPath] = newValue }
}
}

enum AdvancedSettingsScreenViewAction { }

protocol AdvancedSettingsProtocol: AnyObject {
var timelineStyle: TimelineStyle { get set }
var viewSourceEnabled: Bool { get set }
var richTextEditorEnabled: Bool { get set }
}

extension AppSettings: AdvancedSettingsProtocol { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// 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

typealias AdvancedSettingsScreenViewModelType = StateStoreViewModel<AdvancedSettingsScreenViewState, AdvancedSettingsScreenViewAction>

class AdvancedSettingsScreenViewModel: AdvancedSettingsScreenViewModelType, AdvancedSettingsScreenViewModelProtocol {
var callback: ((AdvancedSettingsScreenViewModelAction) -> Void)?

init(advancedSettings: AdvancedSettingsProtocol) {
let bindings = AdvancedSettingsScreenViewStateBindings(advancedSettings: advancedSettings)
let state = AdvancedSettingsScreenViewState(bindings: bindings)

super.init(initialViewState: state)
}

override func process(viewAction: AdvancedSettingsScreenViewAction) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// 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 Foundation

@MainActor
protocol AdvancedSettingsScreenViewModelProtocol {
var callback: ((AdvancedSettingsScreenViewModelAction) -> Void)? { get set }
var context: AdvancedSettingsScreenViewModelType.Context { get }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// 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 Compound
import SwiftUI

struct AdvancedSettingsScreen: View {
@ObservedObject var context: AdvancedSettingsScreenViewModel.Context
@State private var showConfetti = false

var body: some View {
Form {
Section {
ListRow(label: .default(title: L10n.commonMessageLayout,
systemIcon: .rectangleGrid1x2),
kind: .picker(selection: $context.timelineStyle,
items: TimelineStyle.allCases.map { (title: $0.name, tag: $0) }))

ListRow(label: .default(title: L10n.actionViewSource, systemIcon: .mailAndTextMagnifyingglass),
kind: .toggle($context.viewSourceEnabled))

ListRow(label: .default(title: L10n.commonRichTextEditor, icon: Image(asset: Asset.Images.textFormat)),
kind: .toggle($context.richTextEditorEnabled))
}
}
.compoundList()
.navigationTitle(L10n.commonAdvancedSettings)
.navigationBarTitleDisplayMode(.inline)
}
}

private extension TimelineStyle {
var name: String {
switch self {
case .plain:
return L10n.commonModern
case .bubbles:
return L10n.commonBubbles
}
}
}

// MARK: - Previews

struct AdvancedSettingsScreen_Previews: PreviewProvider {
static let viewModel = AdvancedSettingsScreenViewModel(advancedSettings: ServiceLocator.shared.settings)
static var previews: some View {
NavigationStack {
AdvancedSettingsScreen(context: viewModel.context)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ protocol DeveloperOptionsProtocol: AnyObject {
var userSuggestionsEnabled: Bool { get set }
var readReceiptsEnabled: Bool { get set }
var swiftUITimelineEnabled: Bool { get set }
var richTextEditorEnabled: Bool { get set }
}

extension AppSettings: DeveloperOptionsProtocol { }
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,6 @@ struct DeveloperOptionsScreen: View {
}
}

Section("Rich Text Editor") {
Toggle(isOn: $context.richTextEditorEnabled) {
Text("Use the Rich Text Editor")
}
}

Section {
Button {
showConfetti = true
Expand Down Expand Up @@ -86,7 +80,7 @@ struct DeveloperOptionsScreen: View {
}
}
.overlay(effectsView)
.compoundForm()
.compoundList()
.navigationTitle(L10n.commonDeveloperOptions)
.navigationBarTitleDisplayMode(.inline)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
verifySession()
case .accountSessionsList:
presentAccountSessionsListURL()
case .notifications:
presentNotificationSettings()
case .advancedSettings:
self.presentAdvancedSettings()
case .developerOptions:
presentDeveloperOptions()
case .logout:
callback?(.logout)
case .notifications:
presentNotificationSettings()
}
}
}
Expand Down Expand Up @@ -159,6 +161,21 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
}
}

private func presentNotificationSettings() {
let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator,
userSession: parameters.userSession,
userNotificationCenter: UNUserNotificationCenter.current(),
notificationSettings: parameters.notificationSettings,
isModallyPresented: false)
let coordinator = NotificationSettingsScreenCoordinator(parameters: notificationParameters)
parameters.navigationStackCoordinator?.push(coordinator)
}

private func presentAdvancedSettings() {
let coordinator = AdvancedSettingsScreenCoordinator()
parameters.navigationStackCoordinator?.push(coordinator)
}

private func presentDeveloperOptions() {
let coordinator = DeveloperOptionsScreenCoordinator()

Expand All @@ -175,14 +192,4 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
private func showSuccess(label: String) {
parameters.userIndicatorController?.submitIndicator(UserIndicator(title: label))
}

private func presentNotificationSettings() {
let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator,
userSession: parameters.userSession,
userNotificationCenter: UNUserNotificationCenter.current(),
notificationSettings: parameters.notificationSettings,
isModallyPresented: false)
let coordinator = NotificationSettingsScreenCoordinator(parameters: notificationParameters)
parameters.navigationStackCoordinator?.push(coordinator)
}
}
Loading

0 comments on commit 761d508

Please sign in to comment.