From 42956f65355f13fd2d7d266da641bf92bd815678 Mon Sep 17 00:00:00 2001 From: Bliss Pisit Wetcha Date: Fri, 6 Jan 2023 17:34:03 +0700 Subject: [PATCH] [#26] Add Survey Detail with navigation --- iosApp/Survey.xcodeproj/project.pbxproj | 66 +++++++++++++- .../Constants/Constants+Animation.swift | 15 ++++ .../Constants/Double+AnimationDuration.swift | 2 + .../Coordinator/AppCoordinator.swift | 5 ++ .../Coordinator/RouteCoordinator.swift | 18 ++++ .../RouterCoordinator+WithoutAnimation.swift | 20 +++++ .../Coordinator/Screens/Screen.swift | 1 + .../Screens/ScreenParameters.swift | 17 ++++ .../SurveyDetail/SurveyDetailImage.swift | 37 ++++++++ .../SurveyDetail/SurveyDetailView.swift | 89 +++++++++++++++++++ .../SurveyItem/SurveyItemOverlayView.swift | 22 +++++ .../{ => SurveyItem}/SurveyItemView.swift | 10 +-- .../SurveySelectionContainerView.swift | 12 ++- .../SurveySelectionView+DataSource.swift | 16 +++- .../SurveySelection/SurveySelectionView.swift | 2 +- .../Presentation/ViewId/ViewId+General.swift | 1 + .../ViewId/ViewId+SurveyDetail.swift | 19 ++++ .../Sources/Presentation/ViewId/ViewId.swift | 2 + .../Extensions/SwiftUI/View+BackButton.swift | 11 ++- .../SwiftUI/View+ConditionalModifier.swift | 23 +++++ .../Sources/Screens/GenericScreen.swift | 4 + .../Sources/Screens/SurveyDetailScreen.swift | 14 +++ .../Sources/Screens/SurveyScreen.swift | 4 + .../Module/SurveyDetailSpec.swift | 60 +++++++++++++ .../SurveySelectionViewDataSourceSpec.swift | 17 +++- .../SurveySelectionViewModel.kt | 5 ++ .../commonMain/resources/MR/base/strings.xml | 1 + .../SurveySelectionViewModelTest.kt | 33 +++++++ 28 files changed, 508 insertions(+), 18 deletions(-) create mode 100644 iosApp/Survey/Sources/Constants/Constants+Animation.swift create mode 100644 iosApp/Survey/Sources/Presentation/Coordinator/RouterCoordinator+WithoutAnimation.swift create mode 100644 iosApp/Survey/Sources/Presentation/Coordinator/Screens/ScreenParameters.swift create mode 100644 iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailImage.swift create mode 100644 iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailView.swift create mode 100644 iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItem/SurveyItemOverlayView.swift rename iosApp/Survey/Sources/Presentation/Modules/SurveySelection/{ => SurveyItem}/SurveyItemView.swift (83%) create mode 100644 iosApp/Survey/Sources/Presentation/ViewId/ViewId+SurveyDetail.swift create mode 100644 iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+ConditionalModifier.swift create mode 100644 iosApp/SurveyKIFUITests/Sources/Screens/SurveyDetailScreen.swift create mode 100644 iosApp/SurveyKIFUITests/Sources/Specs/Presentation/Module/SurveyDetailSpec.swift diff --git a/iosApp/Survey.xcodeproj/project.pbxproj b/iosApp/Survey.xcodeproj/project.pbxproj index 0c6fe7e6..f89ccdd2 100644 --- a/iosApp/Survey.xcodeproj/project.pbxproj +++ b/iosApp/Survey.xcodeproj/project.pbxproj @@ -100,8 +100,20 @@ 09CE772728E2C44D00EAA9EE /* View+BackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE772628E2C44D00EAA9EE /* View+BackButton.swift */; }; 09CE773328E2ED2300EAA9EE /* KoinApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE773028E2ED2300EAA9EE /* KoinApplication.swift */; }; 09CE773428E2ED2300EAA9EE /* Typealias+Koin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE773128E2ED2300EAA9EE /* Typealias+Koin.swift */; }; - 09D09DB92963EC39009F88AF /* Image+Url.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DB82963EC39009F88AF /* Image+Url.swift */; }; 09D09DB2295C56A1009F88AF /* SurveySelectionSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DB1295C56A1009F88AF /* SurveySelectionSpec.swift */; }; + 09D09DB92963EC39009F88AF /* Image+Url.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DB82963EC39009F88AF /* Image+Url.swift */; }; + 09D09DBC2967E843009F88AF /* SurveyDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DBB2967E843009F88AF /* SurveyDetailView.swift */; }; + 09D09DBE2967EA5F009F88AF /* ViewId+SurveyDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DBD2967EA5F009F88AF /* ViewId+SurveyDetail.swift */; }; + 09D09DC02968039F009F88AF /* ScreenParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DBF2968039F009F88AF /* ScreenParameters.swift */; }; + 09D09DC429681214009F88AF /* RouterCoordinator+WithoutAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DC329681214009F88AF /* RouterCoordinator+WithoutAnimation.swift */; }; + 09D09DC6296812F6009F88AF /* View+ConditionalModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DC5296812F6009F88AF /* View+ConditionalModifier.swift */; }; + 09D09DC8296817E2009F88AF /* SurveyDetailImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DC7296817E2009F88AF /* SurveyDetailImage.swift */; }; + 09D09DCA29682810009F88AF /* Constants+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DC929682810009F88AF /* Constants+Animation.swift */; }; + 09D09DCE29682B78009F88AF /* SurveyItemOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DCD29682B78009F88AF /* SurveyItemOverlayView.swift */; }; + 09D09DD029682C19009F88AF /* SurveyDetailSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DCB29682965009F88AF /* SurveyDetailSpec.swift */; }; + 09D09DD329682CAE009F88AF /* SurveyDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DD129682C98009F88AF /* SurveyDetailScreen.swift */; }; + 09D09DD429682CBC009F88AF /* ViewId+SurveyDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DBD2967EA5F009F88AF /* ViewId+SurveyDetail.swift */; }; + 09D09DD529682CBF009F88AF /* ViewId+SurveyDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D09DBD2967EA5F009F88AF /* ViewId+SurveyDetail.swift */; }; 09E6ABF32951D105007F1EE3 /* KIF+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E6ABF12951D103007F1EE3 /* KIF+Swift.swift */; }; 09E6ABFD2951D32F007F1EE3 /* ViewId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09636B1428D8148C00A5CB97 /* ViewId.swift */; }; 09E6ABFE2951D333007F1EE3 /* ViewId+General.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09636B2F28D8267D00A5CB97 /* ViewId+General.swift */; }; @@ -274,8 +286,18 @@ 09CE772F28E2ED2300EAA9EE /* LazyKoin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyKoin.swift; sourceTree = ""; }; 09CE773028E2ED2300EAA9EE /* KoinApplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KoinApplication.swift; sourceTree = ""; }; 09CE773128E2ED2300EAA9EE /* Typealias+Koin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Typealias+Koin.swift"; sourceTree = ""; }; - 09D09DB82963EC39009F88AF /* Image+Url.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Image+Url.swift"; sourceTree = ""; }; 09D09DB1295C56A1009F88AF /* SurveySelectionSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveySelectionSpec.swift; sourceTree = ""; }; + 09D09DB82963EC39009F88AF /* Image+Url.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Image+Url.swift"; sourceTree = ""; }; + 09D09DBB2967E843009F88AF /* SurveyDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyDetailView.swift; sourceTree = ""; }; + 09D09DBD2967EA5F009F88AF /* ViewId+SurveyDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewId+SurveyDetail.swift"; sourceTree = ""; }; + 09D09DBF2968039F009F88AF /* ScreenParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenParameters.swift; sourceTree = ""; }; + 09D09DC329681214009F88AF /* RouterCoordinator+WithoutAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RouterCoordinator+WithoutAnimation.swift"; sourceTree = ""; }; + 09D09DC5296812F6009F88AF /* View+ConditionalModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ConditionalModifier.swift"; sourceTree = ""; }; + 09D09DC7296817E2009F88AF /* SurveyDetailImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyDetailImage.swift; sourceTree = ""; }; + 09D09DC929682810009F88AF /* Constants+Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Constants+Animation.swift"; sourceTree = ""; }; + 09D09DCB29682965009F88AF /* SurveyDetailSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyDetailSpec.swift; sourceTree = ""; }; + 09D09DCD29682B78009F88AF /* SurveyItemOverlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyItemOverlayView.swift; sourceTree = ""; }; + 09D09DD129682C98009F88AF /* SurveyDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyDetailScreen.swift; sourceTree = ""; }; 09E6ABE42951CF3E007F1EE3 /* SurveyKIFUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SurveyKIFUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 09E6ABF12951D103007F1EE3 /* KIF+Swift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KIF+Swift.swift"; sourceTree = ""; }; 09E6AC0B2951D5DD007F1EE3 /* AccountSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSpec.swift; sourceTree = ""; }; @@ -515,6 +537,7 @@ 09D09DB82963EC39009F88AF /* Image+Url.swift */, 09636AF828D47A4D00A5CB97 /* Font+Extensions.swift */, 09CE772428E2C1C600EAA9EE /* View+HideBackButtonTitle.swift */, + 09D09DC5296812F6009F88AF /* View+ConditionalModifier.swift */, 09CE772628E2C44D00EAA9EE /* View+BackButton.swift */, 09636B0E28D80B8500A5CB97 /* View+KeyboardDismiss.swift */, 09495FCA291107760036BDFB /* Image+Constants.swift */, @@ -556,6 +579,7 @@ children = ( 09636B1428D8148C00A5CB97 /* ViewId.swift */, 09CE771428E1AB0B00EAA9EE /* ViewId+ResetPassword.swift */, + 09D09DBD2967EA5F009F88AF /* ViewId+SurveyDetail.swift */, 09495F2928EC43760036BDFB /* ViewId+SurveyLoading.swift */, 09636B1628D815D100A5CB97 /* ViewId+Login.swift */, 09636B2F28D8267D00A5CB97 /* ViewId+General.swift */, @@ -672,7 +696,7 @@ 09E6AC112951D950007F1EE3 /* SurveySelectionContainerView.swift */, 09FE26CC294B1EE3005A7F85 /* SurveySelectionView+DataSource.swift */, 0982A7FB29278E9000FC1976 /* SurveyHeader */, - 0982A7FD29278E9000FC1976 /* SurveyItemView.swift */, + 09D09DCF29682B93009F88AF /* SurveyItem */, 0982A7FE29278E9000FC1976 /* SurveyLoading */, ); path = SurveySelection; @@ -702,6 +726,7 @@ 09A9F8D42952B3F8009DE583 /* LoginScreen.swift */, 09A9F8DA2952B54F009DE583 /* SurveyScreen.swift */, 09A9F8DD2952B582009DE583 /* AccountScreen.swift */, + 09D09DD129682C98009F88AF /* SurveyDetailScreen.swift */, 09A9F8D72952B42D009DE583 /* GenericScreen.swift */, ); path = Screens; @@ -771,6 +796,7 @@ children = ( 09CE770B28E191B400EAA9EE /* AppCoordinator.swift */, 0982A7E229222EFF00FC1976 /* RouteCoordinator.swift */, + 09D09DC329681214009F88AF /* RouterCoordinator+WithoutAnimation.swift */, 09CE770D28E1921700EAA9EE /* Screens */, ); path = Coordinator; @@ -780,6 +806,7 @@ isa = PBXGroup; children = ( 09CE770E28E1922000EAA9EE /* Screen.swift */, + 09D09DBF2968039F009F88AF /* ScreenParameters.swift */, ); path = Screens; sourceTree = ""; @@ -828,6 +855,24 @@ path = Koin; sourceTree = ""; }; + 09D09DBA2967E833009F88AF /* SurveyDetail */ = { + isa = PBXGroup; + children = ( + 09D09DBB2967E843009F88AF /* SurveyDetailView.swift */, + 09D09DC7296817E2009F88AF /* SurveyDetailImage.swift */, + ); + path = SurveyDetail; + sourceTree = ""; + }; + 09D09DCF29682B93009F88AF /* SurveyItem */ = { + isa = PBXGroup; + children = ( + 0982A7FD29278E9000FC1976 /* SurveyItemView.swift */, + 09D09DCD29682B78009F88AF /* SurveyItemOverlayView.swift */, + ); + path = SurveyItem; + sourceTree = ""; + }; 09E6ABE52951CF3E007F1EE3 /* SurveyKIFUITests */ = { isa = PBXGroup; children = ( @@ -891,6 +936,7 @@ children = ( 09E6AC0B2951D5DD007F1EE3 /* AccountSpec.swift */, 09D09DB1295C56A1009F88AF /* SurveySelectionSpec.swift */, + 09D09DCB29682965009F88AF /* SurveyDetailSpec.swift */, ); path = Module; sourceTree = ""; @@ -1090,6 +1136,7 @@ 71A1F95D20E1E58589F4CD31 /* Constants.swift */, 09495FC8291106A00036BDFB /* Constants+SystemImage.swift */, 0964B1CD294054B300946FA1 /* Double+AnimationDuration.swift */, + 09D09DC929682810009F88AF /* Constants+Animation.swift */, ); path = Constants; sourceTree = ""; @@ -1176,6 +1223,7 @@ B7707C4371EA10EA47E7E7B4 /* Modules */ = { isa = PBXGroup; children = ( + 09D09DBA2967E833009F88AF /* SurveyDetail */, 0982A7F929278E9000FC1976 /* SurveySelection */, 09CE771128E1A93600EAA9EE /* ResetPassword */, 09495F6D28FFDE8C0036BDFB /* Login */, @@ -1776,14 +1824,17 @@ 09E6AC032951D333007F1EE3 /* ViewId+Account.swift in Sources */, 09E6ABFE2951D333007F1EE3 /* ViewId+General.swift in Sources */, 09E6AC012951D333007F1EE3 /* ViewId+Login.swift in Sources */, + 09D09DD329682CAE009F88AF /* SurveyDetailScreen.swift in Sources */, 09E6ABFF2951D333007F1EE3 /* ViewId+SurveySelection.swift in Sources */, 09D09DB2295C56A1009F88AF /* SurveySelectionSpec.swift in Sources */, + 09D09DD429682CBC009F88AF /* ViewId+SurveyDetail.swift in Sources */, 09E6AC042951D333007F1EE3 /* ViewId+Splash.swift in Sources */, 09E6ABF32951D105007F1EE3 /* KIF+Swift.swift in Sources */, 09E6ABFD2951D32F007F1EE3 /* ViewId.swift in Sources */, 09A9F8DC2952B574009DE583 /* SurveyScreen.swift in Sources */, 09E6AC002951D333007F1EE3 /* ViewId+SurveyLoading.swift in Sources */, 09A9F8DF2952B585009DE583 /* AccountScreen.swift in Sources */, + 09D09DD029682C19009F88AF /* SurveyDetailSpec.swift in Sources */, 09A9F8D92952B431009DE583 /* GenericScreen.swift in Sources */, 09E6AC022951D333007F1EE3 /* ViewId+ResetPassword.swift in Sources */, ); @@ -1800,9 +1851,13 @@ 09636B0D28D4917200A5CB97 /* OverlayButton.swift in Sources */, 09495FC9291106A00036BDFB /* Constants+SystemImage.swift in Sources */, 09E6AC102951D8B5007F1EE3 /* AccountView.swift in Sources */, + 09D09DCE29682B78009F88AF /* SurveyItemOverlayView.swift in Sources */, + 09D09DC429681214009F88AF /* RouterCoordinator+WithoutAnimation.swift in Sources */, + 09D09DC8296817E2009F88AF /* SurveyDetailImage.swift in Sources */, 686B2C185816765B3E124776 /* IOSApp.swift in Sources */, 09CE771328E1A94600EAA9EE /* ResetPasswordView.swift in Sources */, 09FE26CD294B1EE3005A7F85 /* SurveySelectionView+DataSource.swift in Sources */, + 09D09DCA29682810009F88AF /* Constants+Animation.swift in Sources */, 09636B3028D8267D00A5CB97 /* ViewId+General.swift in Sources */, 09636B0228D4876100A5CB97 /* PrimaryButton.swift in Sources */, 09CE770C28E191B400EAA9EE /* AppCoordinator.swift in Sources */, @@ -1815,6 +1870,7 @@ 09495F0928E410A00036BDFB /* PageControlView.swift in Sources */, 09636AFD28D484CA00A5CB97 /* R+SwiftUI.swift in Sources */, 09495FCB291107760036BDFB /* Image+Constants.swift in Sources */, + 09D09DC02968039F009F88AF /* ScreenParameters.swift in Sources */, 09636B0F28D80B8500A5CB97 /* View+KeyboardDismiss.swift in Sources */, 09495F84290110640036BDFB /* AppDelegate.swift in Sources */, 09CE773428E2ED2300EAA9EE /* Typealias+Koin.swift in Sources */, @@ -1832,6 +1888,7 @@ 0982A880292F847900FC1976 /* ResetPassword+DataSource.swift in Sources */, 0964B1D92946FA8100946FA1 /* SplashView+DataSource.swift in Sources */, 0982A80429278E9000FC1976 /* SurveyItemView.swift in Sources */, + 09D09DBC2967E843009F88AF /* SurveyDetailView.swift in Sources */, 09636B1528D8148C00A5CB97 /* ViewId.swift in Sources */, 0982A80529278E9000FC1976 /* SurveyLoading.swift in Sources */, 0982A7E029222EB900FC1976 /* ViewId+Splash.swift in Sources */, @@ -1840,6 +1897,7 @@ 09CE770F28E1922000EAA9EE /* Screen.swift in Sources */, 09CE772528E2C1C600EAA9EE /* View+HideBackButtonTitle.swift in Sources */, 09CE771528E1AB0B00EAA9EE /* ViewId+ResetPassword.swift in Sources */, + 09D09DC6296812F6009F88AF /* View+ConditionalModifier.swift in Sources */, 09636B0B28D48CFD00A5CB97 /* Typealiases.swift in Sources */, 0982A7F6292371F000FC1976 /* StringResource+Localized.swift in Sources */, 0964B1CE294054B300946FA1 /* Double+AnimationDuration.swift in Sources */, @@ -1850,6 +1908,7 @@ 870924447B8C177450E77414 /* Optional+Unwrap.swift in Sources */, 0982A7E72922357C00FC1976 /* Font+Extensions.swift in Sources */, 0964B1C62940514000946FA1 /* LaunchArgument.swift in Sources */, + 09D09DBE2967EA5F009F88AF /* ViewId+SurveyDetail.swift in Sources */, 09CE772328E2B87700EAA9EE /* LoadingDialog.swift in Sources */, 09636AF628D47A1500A5CB97 /* R.generated.swift in Sources */, 09D09DB92963EC39009F88AF /* Image+Url.swift in Sources */, @@ -1868,6 +1927,7 @@ 098CC7AD294C266000C3A6A5 /* XCTestCase+PermissionInteruption.swift in Sources */, 09495F1828E4461C0036BDFB /* SurveySelectionScreen.swift in Sources */, 09636B3228D8272200A5CB97 /* ScreenProtocol.swift in Sources */, + 09D09DD529682CBF009F88AF /* ViewId+SurveyDetail.swift in Sources */, 0982A79E2921DF7E00FC1976 /* SurveySelectionSpec.swift in Sources */, 09C2F4032934588B00F44818 /* TimeInterval+Constants.swift in Sources */, 0964B1CA294051CE00946FA1 /* ArgumentedXCUIApplication.swift in Sources */, diff --git a/iosApp/Survey/Sources/Constants/Constants+Animation.swift b/iosApp/Survey/Sources/Constants/Constants+Animation.swift new file mode 100644 index 00000000..5aed2811 --- /dev/null +++ b/iosApp/Survey/Sources/Constants/Constants+Animation.swift @@ -0,0 +1,15 @@ +// +// Constants+Animation.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import SwiftUI + +extension Animation { + + /// ease in 500 ms + static var easeInViewTransition: Self { .easeIn(duration: .viewTransition) } +} diff --git a/iosApp/Survey/Sources/Constants/Double+AnimationDuration.swift b/iosApp/Survey/Sources/Constants/Double+AnimationDuration.swift index 018d531c..148aec24 100644 --- a/iosApp/Survey/Sources/Constants/Double+AnimationDuration.swift +++ b/iosApp/Survey/Sources/Constants/Double+AnimationDuration.swift @@ -16,4 +16,6 @@ extension Double { static var fast: Self { 0.2.speedModified } /// 0.3 static var `default`: Self { 0.3.speedModified } + /// 0.5 + static var viewTransition: Self { 0.5.speedModified } } diff --git a/iosApp/Survey/Sources/Presentation/Coordinator/AppCoordinator.swift b/iosApp/Survey/Sources/Presentation/Coordinator/AppCoordinator.swift index 2a2f1f3f..c0e74725 100644 --- a/iosApp/Survey/Sources/Presentation/Coordinator/AppCoordinator.swift +++ b/iosApp/Survey/Sources/Presentation/Coordinator/AppCoordinator.swift @@ -24,6 +24,11 @@ struct AppCoordinator: View { SplashView(coordinator: coordinator) case .surveySelection: SurveySelectionContainerView(coordinator: coordinator) + case let .surveyDetail(parameters): + SurveyDetailView( + survey: parameters.survey, + coordinator: coordinator + ) } } } diff --git a/iosApp/Survey/Sources/Presentation/Coordinator/RouteCoordinator.swift b/iosApp/Survey/Sources/Presentation/Coordinator/RouteCoordinator.swift index 096636ce..64ab2636 100644 --- a/iosApp/Survey/Sources/Presentation/Coordinator/RouteCoordinator.swift +++ b/iosApp/Survey/Sources/Presentation/Coordinator/RouteCoordinator.swift @@ -49,3 +49,21 @@ extension RouteCoordinator: LoginCoordinator { } extension RouteCoordinator: AccountCoordinator {} + +extension RouteCoordinator: SurveySelectionCoordinator { + + func showSurveyDetail(_ parameters: ScreenParameters.SurveyDetail) { + withoutAnimation { + self.routes.presentCover(.surveyDetail(parameters), embedInNavigationView: true) + } + } +} + +extension RouteCoordinator: SurveyDetailCoordinator { + + func backToHome() { + withoutAnimation { + self.routes.dismiss() + } + } +} diff --git a/iosApp/Survey/Sources/Presentation/Coordinator/RouterCoordinator+WithoutAnimation.swift b/iosApp/Survey/Sources/Presentation/Coordinator/RouterCoordinator+WithoutAnimation.swift new file mode 100644 index 00000000..cb0f6653 --- /dev/null +++ b/iosApp/Survey/Sources/Presentation/Coordinator/RouterCoordinator+WithoutAnimation.swift @@ -0,0 +1,20 @@ +// +// RouterCoordinator+WithoutAnimation.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import SwiftUI + +extension RouteCoordinator { + + func withoutAnimation(action: @escaping () -> Void) { + var transaction = Transaction() + transaction.disablesAnimations = true + withTransaction(transaction) { + action() + } + } +} diff --git a/iosApp/Survey/Sources/Presentation/Coordinator/Screens/Screen.swift b/iosApp/Survey/Sources/Presentation/Coordinator/Screens/Screen.swift index a2dea6db..5ab16153 100644 --- a/iosApp/Survey/Sources/Presentation/Coordinator/Screens/Screen.swift +++ b/iosApp/Survey/Sources/Presentation/Coordinator/Screens/Screen.swift @@ -12,4 +12,5 @@ enum Screen { case splash case resetPassword case surveySelection + case surveyDetail(_ parameters: ScreenParameters.SurveyDetail) } diff --git a/iosApp/Survey/Sources/Presentation/Coordinator/Screens/ScreenParameters.swift b/iosApp/Survey/Sources/Presentation/Coordinator/Screens/ScreenParameters.swift new file mode 100644 index 00000000..137a8626 --- /dev/null +++ b/iosApp/Survey/Sources/Presentation/Coordinator/Screens/ScreenParameters.swift @@ -0,0 +1,17 @@ +// +// ScreenParameters.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import Shared + +enum ScreenParameters { + + struct SurveyDetail { + + let survey: SurveyUiModel + } +} diff --git a/iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailImage.swift b/iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailImage.swift new file mode 100644 index 00000000..c94cf29e --- /dev/null +++ b/iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailImage.swift @@ -0,0 +1,37 @@ +// +// SurveyDetailImage.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import Shared +import SwiftUI + +struct SurveyDetailImage: View { + + @Binding var isAnimating: Bool + + let survey: SurveyUiModel + let scaleEffect = 1.42 + + var body: some View { + ZStack { + + GeometryReader { geometry in + Image.url(survey.largeImageUrl) + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: geometry.size.width, height: geometry.size.height) + .scaleEffect(isAnimating ? 1.0 : scaleEffect, anchor: .topTrailing) + .accessibility(.surveyDetail(.mainImage)) + } + .ignoresSafeArea() + + SurveyItemOverlayView() + .ignoresSafeArea() + } + .accessibilityElement(children: .contain) + } +} diff --git a/iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailView.swift b/iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailView.swift new file mode 100644 index 00000000..dab2e2a2 --- /dev/null +++ b/iosApp/Survey/Sources/Presentation/Modules/SurveyDetail/SurveyDetailView.swift @@ -0,0 +1,89 @@ +// +// SurveyDetailView.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import Shared +import SwiftUI + +protocol SurveyDetailCoordinator { + + func backToHome() +} + +struct SurveyDetailView: View { + + let survey: SurveyUiModel + let coordinator: SurveyDetailCoordinator + + @State var isAnimatingBack = false + @State var isAnimating = true + + var body: some View { + ZStack { + surveyView + } + .accessibilityElement(children: .contain) + .accessibility(.surveyDetail(.view)) + .backButton { + didPressBack() + } + .onLoad { + DispatchQueue.main.async { + withAnimation(.easeInViewTransition) { + isAnimating = false + } + } + } + } + + var surveyView: some View { + ZStack { + SurveyDetailImage(isAnimating: $isAnimating, survey: survey) + + VStack(alignment: .leading) { + Text(survey.title) + .lineLimit(3) + .padding(.top, .mediumPadding) + .foregroundColor(.white) + .font(.boldLarge) + .accessibility(.surveyDetail(.titleText)) + Text(survey.description_) + .lineLimit(.max) + .padding(.top, .lineSpacing) + .foregroundColor(.white) + .font(.regularBody) + .accessibility(.surveyDetail(.detailText)) + Spacer() + HStack { + Spacer() + Button { + // TODO: Add action when press next + } label: { + Text(String.localizeId.survey_detail_start_button()) + .primaryButton() + } + .padding(.bottom, .mediumPadding) + .accessibility(.surveyDetail(.startButton)) + } + } + .frame(maxWidth: .infinity) + .padding(.horizontal, .smallPadding) + .opacity(isAnimating ? 0.0 : 1.0) + } + } + + func didPressBack() { + guard !isAnimatingBack else { return } + isAnimatingBack = true + withAnimation(.easeInViewTransition) { + isAnimating = true + } + DispatchQueue.main.asyncAfter(deadline: .now() + .viewTransition) { + self.coordinator.backToHome() + } + } +} diff --git a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItem/SurveyItemOverlayView.swift b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItem/SurveyItemOverlayView.swift new file mode 100644 index 00000000..99c5990e --- /dev/null +++ b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItem/SurveyItemOverlayView.swift @@ -0,0 +1,22 @@ +// +// SurveyItemOverlayView.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import Shared +import SwiftUI + +struct SurveyItemOverlayView: View { + + var body: some View { + Rectangle() + .foregroundColor(.clear) + .background( + LinearGradient(colors: [.clear, .black], startPoint: .top, endPoint: .bottom) + ) + .opacity(0.6) + } +} diff --git a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItemView.swift b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItem/SurveyItemView.swift similarity index 83% rename from iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItemView.swift rename to iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItem/SurveyItemView.swift index 621c40b1..5008bfc7 100644 --- a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItemView.swift +++ b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveyItem/SurveyItemView.swift @@ -6,7 +6,6 @@ // Copyright © 2022 Nimble. All rights reserved. // -import Kingfisher import Shared import SwiftUI @@ -17,7 +16,7 @@ struct SurveyItemView: View { var body: some View { ZStack { GeometryReader { geo in - KFImage(survey.largeImageUrl.asURL) + Image.url(survey.largeImageUrl) .resizable() .scaledToFill() .frame(maxWidth: geo.size.width, maxHeight: geo.size.height) @@ -26,12 +25,7 @@ struct SurveyItemView: View { } .ignoresSafeArea() - Rectangle() - .foregroundColor(.clear) - .background( - LinearGradient(colors: [.clear, .black], startPoint: .top, endPoint: .bottom) - ) - .opacity(0.6) + SurveyItemOverlayView() .ignoresSafeArea() GeometryReader { geo in diff --git a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionContainerView.swift b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionContainerView.swift index 92bde4f5..7e120642 100644 --- a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionContainerView.swift +++ b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionContainerView.swift @@ -6,13 +6,14 @@ // Copyright © 2022 Nimble. All rights reserved. // +import Shared import SwiftUI struct SurveySelectionContainerView: View { - let coordinator: AccountCoordinator + let coordinator: AccountCoordinator & SurveySelectionCoordinator - @StateObject private var dataSource = SurveySelectionView.DataSource() + @StateObject private var dataSource: SurveySelectionView.DataSource @State var isShowingAccountView = false @@ -53,4 +54,11 @@ struct SurveySelectionContainerView: View { } } } + + init(coordinator: AccountCoordinator & SurveySelectionCoordinator) { + self.coordinator = coordinator + _dataSource = .init( + wrappedValue: SurveySelectionView.DataSource(coordinator: coordinator) + ) + } } diff --git a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView+DataSource.swift b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView+DataSource.swift index c9af1f5e..675fc1e9 100644 --- a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView+DataSource.swift +++ b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView+DataSource.swift @@ -10,11 +10,18 @@ import Combine import KMPNativeCoroutinesCombine import Shared +// sourcery: AutoMockable +protocol SurveySelectionCoordinator { + + func showSurveyDetail(_ parameters: ScreenParameters.SurveyDetail) +} + extension SurveySelectionView { final class DataSource: ObservableObject { let viewModel: SurveySelectionViewModel + let coordinator: SurveySelectionCoordinator @Published private(set) var viewState = SurveySelectionViewState() @Published var showingLoading = false @@ -23,9 +30,11 @@ extension SurveySelectionView { private var cancellables = Set() init( - viewModel: SurveySelectionViewModel = KoinApplication.shared.inject() + viewModel: SurveySelectionViewModel = KoinApplication.shared.inject(), + coordinator: SurveySelectionCoordinator ) { self.viewModel = viewModel + self.coordinator = coordinator createPublisher(for: viewModel.viewStateNative) .catch { _ -> Just in let surveySelectionViewState = SurveySelectionViewState() @@ -47,6 +56,11 @@ extension SurveySelectionView { viewModel.checkFetchMore(item: Int32(index)) } + func showSurveyDetail() { + guard let survey = viewModel.currentSurvey else { return } + coordinator.showSurveyDetail(.init(survey: survey)) + } + private func updateStates(_ state: SurveySelectionViewState) { viewState = state showingLoading = state.isLoading diff --git a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView.swift b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView.swift index cd5a45af..4c57c72e 100644 --- a/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView.swift +++ b/iosApp/Survey/Sources/Presentation/Modules/SurveySelection/SurveySelectionView.swift @@ -75,7 +75,7 @@ struct SurveySelectionView: View { HStack { Spacer() Button { - // TODO: Add action when press next + dataSource.showSurveyDetail() } label: { Assets.nextButton .image diff --git a/iosApp/Survey/Sources/Presentation/ViewId/ViewId+General.swift b/iosApp/Survey/Sources/Presentation/ViewId/ViewId+General.swift index 612c3052..94f2eb4f 100644 --- a/iosApp/Survey/Sources/Presentation/ViewId/ViewId+General.swift +++ b/iosApp/Survey/Sources/Presentation/ViewId/ViewId+General.swift @@ -12,5 +12,6 @@ extension ViewId { case keyboard = "general.keyboard" case loadingSpinner = "general.loading.spinner" + case backButton = "back.button" } } diff --git a/iosApp/Survey/Sources/Presentation/ViewId/ViewId+SurveyDetail.swift b/iosApp/Survey/Sources/Presentation/ViewId/ViewId+SurveyDetail.swift new file mode 100644 index 00000000..4a4eb2e0 --- /dev/null +++ b/iosApp/Survey/Sources/Presentation/ViewId/ViewId+SurveyDetail.swift @@ -0,0 +1,19 @@ +// +// ViewId+SurveyDetail.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +extension ViewId { + + enum SurveyDetail: String { + + case view = "survey.detail.view" + case startButton = "survey.detail.start.button" + case titleText = "survey.detail.title.text" + case detailText = "survey.detail.detail.text" + case mainImage = "survey.detail.main.image" + } +} diff --git a/iosApp/Survey/Sources/Presentation/ViewId/ViewId.swift b/iosApp/Survey/Sources/Presentation/ViewId/ViewId.swift index 324f8e27..705f898f 100644 --- a/iosApp/Survey/Sources/Presentation/ViewId/ViewId.swift +++ b/iosApp/Survey/Sources/Presentation/ViewId/ViewId.swift @@ -17,6 +17,7 @@ enum ViewId { case resetPassword(ResetPassword) case surveySelection(SurveySelection) case surveyLoading(SurveyLoading) + case surveyDetail(SurveyDetail) case account(Account) case general(General) @@ -27,6 +28,7 @@ enum ViewId { case let .resetPassword(resetPassword): return resetPassword.rawValue case let .surveySelection(surveySelection): return surveySelection.rawValue case let .surveyLoading(surveyLoading): return surveyLoading.rawValue + case let .surveyDetail(surveyDetail): return surveyDetail.rawValue case let .account(account): return account.rawValue case let .general(general): return general.rawValue } diff --git a/iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+BackButton.swift b/iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+BackButton.swift index 4d9cb7d1..825d47d2 100644 --- a/iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+BackButton.swift +++ b/iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+BackButton.swift @@ -10,10 +10,10 @@ import SwiftUI extension View { - func defaultBackButton(_ presentationMode: Binding) -> some View { + func backButton(action: @escaping () -> Void) -> some View { var backButton: some View { Button { - presentationMode.wrappedValue.dismiss() + action() } label: { HStack(spacing: 0) { Image(systemName: .backArrow) @@ -23,9 +23,16 @@ extension View { .offset(x: -8.0) } } + .accessibility(ViewId.general(.backButton)) } return navigationBarBackButtonHidden(true) .navigationBarItems(leading: backButton) } + + func defaultBackButton(_ presentationMode: Binding) -> some View { + return backButton { + presentationMode.wrappedValue.dismiss() + } + } } diff --git a/iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+ConditionalModifier.swift b/iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+ConditionalModifier.swift new file mode 100644 index 00000000..16d94a03 --- /dev/null +++ b/iosApp/Survey/Sources/Supports/Extensions/SwiftUI/View+ConditionalModifier.swift @@ -0,0 +1,23 @@ +// +// View+ConditionalModifier.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import SwiftUI + +extension View { + + @ViewBuilder func `if`( + _ condition: Bool, + transform: (Self) -> Content + ) -> some View { + if condition { + transform(self) + } else { + self + } + } +} diff --git a/iosApp/SurveyKIFUITests/Sources/Screens/GenericScreen.swift b/iosApp/SurveyKIFUITests/Sources/Screens/GenericScreen.swift index 07d1bc18..ffbda9e7 100644 --- a/iosApp/SurveyKIFUITests/Sources/Screens/GenericScreen.swift +++ b/iosApp/SurveyKIFUITests/Sources/Screens/GenericScreen.swift @@ -20,4 +20,8 @@ class GenericScreen { init(_ testCase: XCTestCase!) { self.testCase = testCase } + + func tapBackButton() { + tester.tapView(withAccessibilityIdentifier: ViewId.general(.backButton)()) + } } diff --git a/iosApp/SurveyKIFUITests/Sources/Screens/SurveyDetailScreen.swift b/iosApp/SurveyKIFUITests/Sources/Screens/SurveyDetailScreen.swift new file mode 100644 index 00000000..0e83b204 --- /dev/null +++ b/iosApp/SurveyKIFUITests/Sources/Screens/SurveyDetailScreen.swift @@ -0,0 +1,14 @@ +// +// SurveyDetailScreen.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +final class SurveyDetailScreen: GenericScreen { + + func waitForAppearance() { + tester.waitForView(withAccessibilityIdentifier: ViewId.surveyDetail(.view)()) + } +} diff --git a/iosApp/SurveyKIFUITests/Sources/Screens/SurveyScreen.swift b/iosApp/SurveyKIFUITests/Sources/Screens/SurveyScreen.swift index b29afa2b..130c5038 100644 --- a/iosApp/SurveyKIFUITests/Sources/Screens/SurveyScreen.swift +++ b/iosApp/SurveyKIFUITests/Sources/Screens/SurveyScreen.swift @@ -23,4 +23,8 @@ final class SurveyScreen: GenericScreen { in: .left ) } + + func tapNextButton() { + tester.tapView(withAccessibilityIdentifier: ViewId.surveySelection(.nextButton)()) + } } diff --git a/iosApp/SurveyKIFUITests/Sources/Specs/Presentation/Module/SurveyDetailSpec.swift b/iosApp/SurveyKIFUITests/Sources/Specs/Presentation/Module/SurveyDetailSpec.swift new file mode 100644 index 00000000..3bcc29f6 --- /dev/null +++ b/iosApp/SurveyKIFUITests/Sources/Specs/Presentation/Module/SurveyDetailSpec.swift @@ -0,0 +1,60 @@ +// +// SurveyDetailSpec.swift +// Survey +// +// Created by Bliss on 6/1/23. +// Copyright © 2023 Nimble. All rights reserved. +// + +import Nimble +import Quick + +final class SurveyDetailSpec: QuickSpec { + + override func spec() { + + var loginScreen: LoginScreen! + var surveyScreen: SurveyScreen! + var surveyDetailScreen: SurveyDetailScreen! + + describe("an Survey Detail screen") { + + beforeEach { + loginScreen = LoginScreen(self) + surveyScreen = SurveyScreen(self) + surveyDetailScreen = SurveyDetailScreen(self) + } + + describe("its open") { + + beforeEach { + loginScreen.loginIfNeeded() + surveyScreen.waitForAppearance() + surveyScreen.tapNextButton() + } + + afterEach { + surveyDetailScreen.tapBackButton() + surveyScreen.waitForAppearance() + } + + it("shows its ui components") { + surveyDetailScreen.waitForAppearance() + + self.tester().waitForView( + withAccessibilityIdentifier: ViewId.surveyDetail(.titleText)() + ) + self.tester().waitForView( + withAccessibilityIdentifier: ViewId.surveyDetail(.detailText)() + ) + self.tester().waitForView( + withAccessibilityIdentifier: ViewId.surveyDetail(.mainImage)() + ) + self.tester().waitForView( + withAccessibilityIdentifier: ViewId.surveyDetail(.startButton)() + ) + } + } + } + } +} diff --git a/iosApp/SurveyTests/Sources/Specs/Presentation/Modules/SurveySelection/SurveySelectionViewDataSourceSpec.swift b/iosApp/SurveyTests/Sources/Specs/Presentation/Modules/SurveySelection/SurveySelectionViewDataSourceSpec.swift index 36a19786..c7a446f8 100644 --- a/iosApp/SurveyTests/Sources/Specs/Presentation/Modules/SurveySelection/SurveySelectionViewDataSourceSpec.swift +++ b/iosApp/SurveyTests/Sources/Specs/Presentation/Modules/SurveySelection/SurveySelectionViewDataSourceSpec.swift @@ -20,6 +20,7 @@ final class SurveySelectionViewDataSourceSpec: QuickSpec { var getProfileUseCase: GetProfileUseCaseKMMMock! var getAppVersionUseCase: GetAppVersionUseCaseKMMMock! var surveyListUseCase: SurveyListUseCaseKMMMock! + var coordinator: SurveySelectionCoordinatorMock! var surveySelectionViewModel: SurveySelectionViewModel! var dataSource: SurveySelectionView.DataSource! @@ -30,6 +31,7 @@ final class SurveySelectionViewDataSourceSpec: QuickSpec { getProfileUseCase = GetProfileUseCaseKMMMock() getAppVersionUseCase = GetAppVersionUseCaseKMMMock() surveyListUseCase = SurveyListUseCaseKMMMock() + coordinator = SurveySelectionCoordinatorMock() surveySelectionViewModel = SurveySelectionViewModel( getCurrentDateUseCase: getCurrentDateUseCase, getProfileUseCase: getProfileUseCase, @@ -38,7 +40,8 @@ final class SurveySelectionViewDataSourceSpec: QuickSpec { dateTimeFormatter: DateTimeFormatterImpl() ) dataSource = .init( - viewModel: surveySelectionViewModel + viewModel: surveySelectionViewModel, + coordinator: coordinator ) } @@ -97,6 +100,18 @@ final class SurveySelectionViewDataSourceSpec: QuickSpec { expect(surveys?.count) == 6 } } + + describe("its showSurveyDetail") { + + beforeEach { + _ = try? self.awaitPublisher(dataSource.$surveys.collectNext(2)).last + dataSource.showSurveyDetail() + } + + it("calls coordinator to show survey detail") { + expect(coordinator.showSurveyDetailCallsCount) == 1 + } + } } } diff --git a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModel.kt b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModel.kt index b6b35250..0dd8b541 100644 --- a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModel.kt +++ b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModel.kt @@ -41,9 +41,13 @@ class SurveySelectionViewModel( private var currentPage = 1 private var fetchingSurvey = true + private var selectingItem = 0 val viewState: StateFlow = mutableViewState + val currentSurvey + get() = viewState.value.surveys.getOrNull(selectingItem) + fun fetch() { setStateLoading() viewModelScope.launch { @@ -63,6 +67,7 @@ class SurveySelectionViewModel( } fun checkFetchMore(item: Int) { + selectingItem = item if(item >= viewState.value.surveys.size - FETCH_MORE_TRIGGER) { fetchMoreSurvey() } diff --git a/shared/src/commonMain/resources/MR/base/strings.xml b/shared/src/commonMain/resources/MR/base/strings.xml index 714956c6..e1a0cac1 100644 --- a/shared/src/commonMain/resources/MR/base/strings.xml +++ b/shared/src/commonMain/resources/MR/base/strings.xml @@ -12,4 +12,5 @@ Check your email. We’ve email you instructions to reset your password. Logout + Start Survey diff --git a/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModelTest.kt b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModelTest.kt index 7b9e22b2..57e114c3 100644 --- a/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModelTest.kt +++ b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/presentation/modules/surveyselection/SurveySelectionViewModelTest.kt @@ -12,6 +12,7 @@ import co.nimblehq.blisskmmic.domain.usecase.GetCurrentDateUseCase import co.nimblehq.blisskmmic.domain.usecase.GetProfileUseCase import co.nimblehq.blisskmmic.domain.usecase.SurveyListUseCase import co.nimblehq.blisskmmic.helpers.flow.delayFlowOf +import co.nimblehq.blisskmmic.presentation.model.SurveyUiModel import io.kotest.matchers.shouldBe import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -262,4 +263,36 @@ class SurveySelectionViewModelTest : TestsWithMocks() { expectMostRecentItem().surveys.size shouldBe 1 } } + + + @Test + fun `When calling checkFetchMore - currentSurvey returns correct item`() = runTest { + val secondSurvey = Survey("second", "", "", "") + mocker.every { + getCurrentDateUseCase() + } returns delayFlowOf(TIME) + mocker.every { + getProfileUseCase() + } returns flowOf(user) + mocker.every { + getAppVersionUseCase() + } returns flowOf(appVersion) + mocker.every { + surveyListUseCase(isAny()) + } returns flowOf(listOf(survey, secondSurvey)) + + surveySelectionViewModel.fetch() + + surveySelectionViewModel + .viewState + .test { + skipItems(2) + surveySelectionViewModel.currentSurvey?.id shouldBe survey.id + surveySelectionViewModel.checkFetchMore(1) + surveySelectionViewModel.currentSurvey?.id shouldBe secondSurvey.id + surveySelectionViewModel.checkFetchMore(0) + surveySelectionViewModel.currentSurvey?.id shouldBe survey.id + cancelAndIgnoreRemainingEvents() + } + } }