diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index d53c72914..13e1ccdd6 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -398,11 +398,12 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, encryptionKeyProvider: EncryptionKeyProvider(), appSettings: appSettings) authenticationCoordinator = AuthenticationCoordinator(authenticationService: authenticationService, + appLockService: appLockFlowCoordinator.appLockService, + bugReportService: ServiceLocator.shared.bugReportService, navigationStackCoordinator: authenticationNavigationStackCoordinator, appSettings: appSettings, analytics: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - appLockService: appLockFlowCoordinator.appLockService) + userIndicatorController: ServiceLocator.shared.userIndicatorController) authenticationCoordinator?.delegate = self authenticationCoordinator?.start() diff --git a/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift b/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift index 980d3023b..a8a682c9a 100644 --- a/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift @@ -24,11 +24,12 @@ protocol AuthenticationCoordinatorDelegate: AnyObject { class AuthenticationCoordinator: CoordinatorProtocol { private let authenticationService: AuthenticationServiceProxyProtocol + private let appLockService: AppLockServiceProtocol + private let bugReportService: BugReportServiceProtocol private let navigationStackCoordinator: NavigationStackCoordinator private let appSettings: AppSettings private let analytics: AnalyticsService private let userIndicatorController: UserIndicatorControllerProtocol - private let appLockService: AppLockServiceProtocol private var cancellables = Set() @@ -39,17 +40,19 @@ class AuthenticationCoordinator: CoordinatorProtocol { weak var delegate: AuthenticationCoordinatorDelegate? init(authenticationService: AuthenticationServiceProxyProtocol, + appLockService: AppLockServiceProtocol, + bugReportService: BugReportServiceProtocol, navigationStackCoordinator: NavigationStackCoordinator, appSettings: AppSettings, analytics: AnalyticsService, - userIndicatorController: UserIndicatorControllerProtocol, - appLockService: AppLockServiceProtocol) { + userIndicatorController: UserIndicatorControllerProtocol) { self.authenticationService = authenticationService + self.appLockService = appLockService + self.bugReportService = bugReportService self.navigationStackCoordinator = navigationStackCoordinator self.appSettings = appSettings self.analytics = analytics self.userIndicatorController = userIndicatorController - self.appLockService = appLockService } func start() { @@ -81,6 +84,8 @@ class AuthenticationCoordinator: CoordinatorProtocol { switch action { case .login: Task { await self.startAuthentication() } + case .reportProblem: + showReportProblemScreen() } } .store(in: &cancellables) @@ -88,6 +93,27 @@ class AuthenticationCoordinator: CoordinatorProtocol { navigationStackCoordinator.setRootCoordinator(coordinator) } + private func showReportProblemScreen() { + let feedbackNavigationStackCoordinator = NavigationStackCoordinator() + + let parameters = BugReportScreenCoordinatorParameters(bugReportService: bugReportService, + userID: nil, + deviceID: nil, + userIndicatorController: ServiceLocator.shared.userIndicatorController, + screenshot: nil, + isModallyPresented: true) + + let coordinator = BugReportScreenCoordinator(parameters: parameters) + + coordinator.completion = { [weak self] _ in + self?.navigationStackCoordinator.setSheetCoordinator(nil) + } + + feedbackNavigationStackCoordinator.setRootCoordinator(coordinator) + + navigationStackCoordinator.setSheetCoordinator(feedbackNavigationStackCoordinator, animated: true) + } + private func startAuthentication() async { startLoading() diff --git a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift index 705309bcd..c50a7d5fa 100644 --- a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift +++ b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift @@ -24,7 +24,7 @@ enum BugReportScreenCoordinatorResult { struct BugReportScreenCoordinatorParameters { let bugReportService: BugReportServiceProtocol - let userID: String + let userID: String? let deviceID: String? let userIndicatorController: UserIndicatorControllerProtocol? diff --git a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenViewModel.swift b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenViewModel.swift index 6cc9a72e0..27f12000f 100644 --- a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenViewModel.swift +++ b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenViewModel.swift @@ -21,7 +21,7 @@ typealias BugReportScreenViewModelType = StateStoreViewModel = .init() // periphery:ignore - when set to nil this is automatically cancelled @@ -32,7 +32,7 @@ class BugReportScreenViewModel: BugReportScreenViewModelType, BugReportScreenVie } init(bugReportService: BugReportServiceProtocol, - userID: String, + userID: String?, deviceID: String?, screenshot: UIImage?, isModallyPresented: Bool) { diff --git a/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenCoordinator.swift b/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenCoordinator.swift index ea008ccc8..af5a1a84d 100644 --- a/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenCoordinator.swift +++ b/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenCoordinator.swift @@ -40,6 +40,8 @@ final class OnboardingScreenCoordinator: CoordinatorProtocol { switch action { case .login: actionsSubject.send(.login) + case .reportProblem: + actionsSubject.send(.reportProblem) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenModels.swift b/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenModels.swift index 2395298ff..900bb7f28 100644 --- a/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenModels.swift +++ b/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenModels.swift @@ -20,14 +20,17 @@ import SwiftUI enum OnboardingScreenCoordinatorAction { case login + case reportProblem } enum OnboardingScreenViewModelAction { case login + case reportProblem } struct OnboardingScreenViewState: BindableState { } enum OnboardingScreenViewAction { case login + case reportProblem } diff --git a/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenViewModel.swift b/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenViewModel.swift index c34acf7df..b44ac2bc2 100644 --- a/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenViewModel.swift +++ b/ElementX/Sources/Screens/OnboardingScreen/OnboardingScreenViewModel.swift @@ -34,6 +34,8 @@ class OnboardingScreenViewModel: OnboardingScreenViewModelType, OnboardingScreen switch viewAction { case .login: actionsSubject.send(.login) + case .reportProblem: + actionsSubject.send(.reportProblem) } } } diff --git a/ElementX/Sources/Screens/OnboardingScreen/View/OnboardingScreen.swift b/ElementX/Sources/Screens/OnboardingScreen/View/OnboardingScreen.swift index 712d4c9d3..f32f13c19 100644 --- a/ElementX/Sources/Screens/OnboardingScreen/View/OnboardingScreen.swift +++ b/ElementX/Sources/Screens/OnboardingScreen/View/OnboardingScreen.swift @@ -42,6 +42,16 @@ struct OnboardingScreen: View { .frame(height: UIConstants.spacerHeight(in: geometry)) } .frame(maxHeight: .infinity) + .safeAreaInset(edge: .bottom) { + Button { + context.send(viewAction: .reportProblem) + } label: { + Text(L10n.commonReportAProblem) + .font(.compound.bodySM) + .foregroundColor(.compound.textSecondary) + } + .frame(width: geometry.size.width) + } } .navigationBarHidden(true) .background { diff --git a/ElementX/Sources/Services/BugReport/BugReportService.swift b/ElementX/Sources/Services/BugReport/BugReportService.swift index f6509252d..9a68c4af1 100644 --- a/ElementX/Sources/Services/BugReport/BugReportService.swift +++ b/ElementX/Sources/Services/BugReport/BugReportService.swift @@ -119,11 +119,14 @@ class BugReportService: NSObject, BugReportServiceProtocol { func submitBugReport(_ bugReport: BugReport, progressListener: CurrentValueSubject) async -> Result { var params = [ - MultipartFormData(key: "user_id", type: .text(value: bugReport.userID)), MultipartFormData(key: "text", type: .text(value: bugReport.text)), MultipartFormData(key: "can_contact", type: .text(value: "\(bugReport.canContact)")) ] + if let userID = bugReport.userID { + params.append(.init(key: "user_id", type: .text(value: userID))) + } + if let deviceID = bugReport.deviceID { params.append(.init(key: "device_id", type: .text(value: deviceID))) } diff --git a/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift b/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift index dea9d99fb..77645dbc1 100644 --- a/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift +++ b/ElementX/Sources/Services/BugReport/BugReportServiceProtocol.swift @@ -19,7 +19,7 @@ import Foundation import UIKit struct BugReport: Equatable { - let userID: String + let userID: String? let deviceID: String? let text: String let includeLogs: Bool diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index e37a84f0a..564012289 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -137,11 +137,12 @@ class MockScreen: Identifiable { case .authenticationFlow: let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = AuthenticationCoordinator(authenticationService: MockAuthenticationServiceProxy(), + appLockService: AppLockServiceMock(), + bugReportService: BugReportServiceMock(), navigationStackCoordinator: navigationStackCoordinator, appSettings: ServiceLocator.shared.settings, analytics: ServiceLocator.shared.analytics, - userIndicatorController: ServiceLocator.shared.userIndicatorController, - appLockService: AppLockServiceMock()) + userIndicatorController: ServiceLocator.shared.userIndicatorController) retainedState.append(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.onboarding.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.onboarding.png index 4dbb83f11..94ae8ff48 100644 --- a/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.onboarding.png +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.onboarding.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce9979e0f1ad3ae45fac19da8d790a4b92de31ad56d07d7735b88407c354e48e -size 1276288 +oid sha256:b0df6a86517b6c8c5e45d7a77ad323c7730178fdc6523f52068748b5d81eca3b +size 1276372 diff --git a/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.onboarding.png b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.onboarding.png index 921696197..b0585fcf7 100644 --- a/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.onboarding.png +++ b/UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.onboarding.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:392d7264ceb22146a4a066ccd46a75a37c06789966bc49f23fb2fe0c23358a2b -size 990811 +oid sha256:279e06e9fbfb8670fecd2ad88f6486402067e5eb1788a5db2f7420a88adaf2d4 +size 1000272 diff --git a/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.onboarding.png b/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.onboarding.png index ef2a3b950..b1b8ea036 100644 --- a/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.onboarding.png +++ b/UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.onboarding.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3480e47e56d9487354e552fd2dc8236d48781d6f9f8dfed2b7b63c5cbe2a9448 -size 1296599 +oid sha256:d2de5fced9093eeef584c2c1ee3b2296e9201cb0c8132672bce778389bbae036 +size 1298519 diff --git a/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.onboarding.png b/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.onboarding.png index 17f27d99f..824423fcc 100644 --- a/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.onboarding.png +++ b/UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.onboarding.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e8c2594242d3ea72a46202703f84c0920d41491c36f12c85aeb9d54fd3f9625 -size 1013586 +oid sha256:b829d6b34f1bb1600e5ccefbf4f7c04fba4b1fad73671cf648ab72ae49e012de +size 1025995 diff --git a/UnitTests/__Snapshots__/PreviewTests/test_onboardingScreen.1.png b/UnitTests/__Snapshots__/PreviewTests/test_onboardingScreen.1.png index 0be0c8aed..549f8ea7a 100644 --- a/UnitTests/__Snapshots__/PreviewTests/test_onboardingScreen.1.png +++ b/UnitTests/__Snapshots__/PreviewTests/test_onboardingScreen.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f932bf95aeacda33b053111d5db67dacc992eb8cf3daedd193bc54c3edfc658 -size 828166 +oid sha256:2413b7707aa285dd909981b20f7d5dbcb421ab469c217de1c1facb9bdd5b517b +size 832592