Minimal Settings screen UI (#85)

* #37 Remove sign out button from home screen

* #37 Move crash button visibility flag to BuildSettings, import BuildSettings from test targets

* #37 Add log out button into the settings screen

* #37 Add version into the settings screen

* #37 enhance bug report parameters

* #37 Remove sign out button from home screen

* #37 Move crash button visibility flag to BuildSettings, import BuildSettings from test targets

* #37 Add log out button into the settings screen

* #37 Add version into the settings screen

* #37 enhance bug report parameters

* #37 Add changelog

* #37 Fix code smells and PR remarks
This commit is contained in:
ismailgulek
2022-06-20 15:27:02 +03:00
committed by GitHub
parent 40e51fb157
commit 591f835811
17 changed files with 104 additions and 64 deletions
+7 -2
View File
@@ -197,8 +197,6 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
guard let self = self else { return }
switch action {
case .logout:
self.stateMachine.processEvent(.attemptSignOut)
case .presentRoom(let roomIdentifier):
self.stateMachine.processEvent(.showRoomScreen(roomId: roomIdentifier))
case .presentSettings:
@@ -218,6 +216,13 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
let parameters = SettingsCoordinatorParameters(navigationRouter: navigationRouter,
bugReportService: bugReportService)
let coordinator = SettingsCoordinator(parameters: parameters)
coordinator.callback = { [weak self] action in
guard let self = self else { return }
switch action {
case .logout:
self.stateMachine.processEvent(.attemptSignOut)
}
}
add(childCoordinator: coordinator)
coordinator.start()
@@ -80,10 +80,10 @@ class AppCoordinatorStateMachine {
machine.addRoutes(event: .succeededRestoringSession, transitions: [ .restoringSession => .homeScreen ])
machine.addRoutes(event: .failedRestoringSession, transitions: [ .restoringSession => .signedOut ])
machine.addRoutes(event: .attemptSignOut, transitions: [ .homeScreen => .signingOut ])
machine.addRoutes(event: .attemptSignOut, transitions: [ .settingsScreen => .signingOut ])
machine.addRoutes(event: .succeededSigningOut, transitions: [ .signingOut => .signedOut ])
machine.addRoutes(event: .failedSigningOut, transitions: [ .signingOut => .homeScreen ])
machine.addRoutes(event: .failedSigningOut, transitions: [ .signingOut => .settingsScreen ])
machine.addRoutes(event: .showSettingsScreen, transitions: [ .homeScreen => .settingsScreen ])
machine.addRoutes(event: .dismissedSettingsScreen, transitions: [ .settingsScreen => .homeScreen ])
+3
View File
@@ -19,4 +19,7 @@ final class BuildSettings {
static let bugReportGHLabels: [String] = ["Element-X"]
// MARK: - Settings screen
static let settingsCrashButtonVisible: Bool = true
}
@@ -24,7 +24,6 @@ struct HomeScreenCoordinatorParameters {
}
enum HomeScreenCoordinatorAction {
case logout
case presentRoom(roomIdentifier: String)
case presentSettings
}
@@ -63,8 +62,6 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
guard let self = self else { return }
switch action {
case .logout:
self.callback?(.logout)
case .selectRoom(let roomIdentifier):
self.callback?(.presentRoom(roomIdentifier: roomIdentifier))
case .tapUserAvatar:
@@ -18,13 +18,11 @@ import Foundation
import UIKit
enum HomeScreenViewModelAction {
case logout
case selectRoom(roomIdentifier: String)
case tapUserAvatar
}
enum HomeScreenViewAction {
case logout
case loadRoomData(roomIdentifier: String)
case selectRoom(roomIdentifier: String)
case tapUserAvatar
@@ -45,8 +45,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
override func process(viewAction: HomeScreenViewAction) async {
switch viewAction {
case .logout:
callback?(.logout)
case .loadRoomData(let roomIdentifier):
loadRoomDataForIdentifier(roomIdentifier)
case .selectRoom(let roomIdentifier):
@@ -106,11 +106,6 @@ struct HomeScreen: View {
.transition(.opacity)
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button("Logout") {
context.send(viewAction: .logout)
}
}
}
}
}
@@ -21,6 +21,10 @@ struct SettingsCoordinatorParameters {
let bugReportService: BugReportServiceProtocol
}
enum SettingsCoordinatorAction {
case logout
}
final class SettingsCoordinator: Coordinator, Presentable {
// MARK: - Properties
@@ -39,6 +43,7 @@ final class SettingsCoordinator: Coordinator, Presentable {
// Must be used only internally
var childCoordinators: [Coordinator] = []
var callback: ((SettingsCoordinatorAction) -> Void)?
// MARK: - Setup
@@ -60,6 +65,8 @@ final class SettingsCoordinator: Coordinator, Presentable {
self.presentBugReportScreen()
case .crash:
self.parameters.bugReportService.crash()
case .logout:
self.callback?(.logout)
}
}
}
@@ -23,12 +23,12 @@ import Foundation
enum SettingsViewModelAction {
case reportBug
case crash
case logout
}
// MARK: View
struct SettingsViewState: BindableState {
var crashButtonVisible: Bool
var bindings: SettingsViewStateBindings
}
@@ -39,4 +39,5 @@ struct SettingsViewStateBindings {
enum SettingsViewAction {
case reportBug
case crash
case logout
}
@@ -34,7 +34,7 @@ class SettingsViewModel: SettingsViewModelType, SettingsViewModelProtocol {
init() {
let bindings = SettingsViewStateBindings()
super.init(initialViewState: .init(crashButtonVisible: true, bindings: bindings))
super.init(initialViewState: .init(bindings: bindings))
}
// MARK: - Public
@@ -45,6 +45,8 @@ class SettingsViewModel: SettingsViewModelType, SettingsViewModelProtocol {
callback?(.reportBug)
case .crash:
callback?(.crash)
case .logout:
callback?(.logout)
}
}
}
@@ -19,6 +19,8 @@ import SwiftUI
struct Settings: View {
// MARK: Private
@State private var showingLogoutConfirmation = false
// MARK: Public
@@ -28,24 +30,45 @@ struct Settings: View {
var body: some View {
Form {
Button { context.send(viewAction: .reportBug) } label: {
Text(ElementL10n.sendBugReport)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.accessibilityIdentifier("reportBugButton")
Section {
Button { context.send(viewAction: .reportBug) } label: {
Text(ElementL10n.sendBugReport)
}
.foregroundColor(Color.element.primaryContent)
.accessibilityIdentifier("reportBugButton")
if context.viewState.crashButtonVisible {
Button { context.send(viewAction: .crash) } label: {
Text("Crash the app")
if BuildSettings.settingsCrashButtonVisible {
Button("Crash the app",
role: .destructive) { context.send(viewAction: .crash)
}
.accessibilityIdentifier("crashButton")
}
}
Section {
Button { showingLogoutConfirmation = true } label: {
Text(ElementL10n.actionSignOut)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.accessibilityIdentifier("crashButton")
.foregroundColor(Color.element.primaryContent)
.accessibilityIdentifier("logoutButton")
.confirmationDialog(ElementL10n.actionSignOutConfirmationSimple,
isPresented: $showingLogoutConfirmation,
titleVisibility: .visible) {
Button(ElementL10n.actionSignOut,
role: .destructive) { context.send(viewAction: .logout)
}
}
} footer: {
versionText
}
}
.navigationTitle(ElementL10n.settings)
}
var versionText: some View {
Text(ElementL10n.settingsVersion + ": " + ElementInfoPlist.cfBundleShortVersionString + " (" + ElementInfoPlist.cfBundleVersion + ")")
}
}
// MARK: - Previews
@@ -141,23 +141,34 @@ class BugReportService: BugReportServiceProtocol {
// MARK: - Private
private var defaultParams: [MultipartFormData] {
[
let (localTime, utcTime) = localAndUTCTime(for: Date())
return [
MultipartFormData(key: "user_agent", type: .text(value: "iOS")),
MultipartFormData(key: "app", type: .text(value: applicationId)),
MultipartFormData(key: "version", type: .text(value: version)),
MultipartFormData(key: "version", type: .text(value: ElementInfoPlist.cfBundleShortVersionString)),
MultipartFormData(key: "build", type: .text(value: ElementInfoPlist.cfBundleVersion)),
MultipartFormData(key: "os", type: .text(value: os)),
MultipartFormData(key: "client", type: .text(value: "Element-X"))
MultipartFormData(key: "resolved_language", type: .text(value: Bundle.preferredLanguages[0])),
MultipartFormData(key: "user_language", type: .text(value: Bundle.elementLanguage ?? "null")),
MultipartFormData(key: "fallback_language", type: .text(value: Bundle.elementFallbackLanguage ?? "null")),
MultipartFormData(key: "local_time", type: .text(value: localTime)),
MultipartFormData(key: "utc_time", type: .text(value: utcTime))
]
}
private func localAndUTCTime(for date: Date) -> (String, String) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let localTime = dateFormatter.string(from: date)
dateFormatter.timeZone = TimeZone(identifier: "UTC")
let utcTime = dateFormatter.string(from: date)
return (localTime, utcTime)
}
private var os: String {
"\(UIDevice.current.systemName) \(UIDevice.current.systemVersion)"
}
private var version: String {
ElementInfoPlist.cfBundleShortVersionString
}
private func zipFiles(includeLogs: Bool,
includeCrashLog: Bool) async throws -> [URL] {
MXLog.debug("[BugReportService] zipFiles: includeLogs: \(includeLogs), includeCrashLog: \(includeCrashLog)")