diff --git a/sample/iosApp/KMPObservableViewModelSample/ContentView.swift b/sample/iosApp/KMPObservableViewModelSample/ContentView.swift index 9a18d24..1bed4e6 100644 --- a/sample/iosApp/KMPObservableViewModelSample/ContentView.swift +++ b/sample/iosApp/KMPObservableViewModelSample/ContentView.swift @@ -8,61 +8,35 @@ import SwiftUI import KMPObservableViewModelSwiftUI + struct ContentView: View { - @StateViewModel var viewModel = TimeTravelViewModel() - private var isFixedTimeBinding: Binding { - Binding { viewModel.isFixedTime } set: { isFixedTime in - if isFixedTime { - viewModel.stopTime() - } else { - viewModel.startTime() - } - } - } + @State private var input: String = "" + @Environment(\.dismiss) private var dismiss var body: some View { VStack{ Spacer() Group { - Text("Actual time:") - Text(viewModel.actualTime) - .font(.system(size: 20)) - } - Group { - Spacer().frame(height: 24) - Text("Travel effect:") - Text(viewModel.travelEffect?.description ?? "nil") - .font(.system(size: 20)) - } - Group { - Spacer().frame(height: 24) - Text("Current time:") - Text(viewModel.currentTime) - .font(.system(size: 20)) - } - Group { - Spacer().frame(height: 24) - HStack { - Toggle("", isOn: isFixedTimeBinding).labelsHidden() - Text("Fixed time") + Button(action: { + dismiss() + }) { + Text("Dismiss") } - } - Group { - Spacer().frame(height: 24) - Button("Time travel") { - viewModel.timeTravel() + ShortMessagesRow() + if useTextInput { + TextField("type_something", text: $input) } } - Group { - Spacer().frame(height: 24) - Button("Reset") { - viewModel.resetTime() - }.foregroundColor(viewModel.isResetDisabled ? Color.red : Color.green) - } Spacer() } + .onAppear { + print("TimeTravelViewModel", "onAppear") + } + .onDisappear { + print("TimeTravelViewModel", "onDisappear") + } } } @@ -71,3 +45,26 @@ struct ContentView_Previews: PreviewProvider { ContentView() } } + +struct ShortMessagesRow: View { + var content: some View { + HStack(spacing: 8) { + ForEach( + ["1", "2", "3"], + id:\.self + ) { message in + Text(message) + } + }.padding(.horizontal, 8) + } + var body: some View { + if useScrollView { + ScrollView(.horizontal, showsIndicators: false) { + content + } + } else { + content + } + } +} + diff --git a/sample/iosApp/KMPObservableViewModelSample/KMPObservableViewModelSampleApp.swift b/sample/iosApp/KMPObservableViewModelSample/KMPObservableViewModelSampleApp.swift index deaa703..ff9a19e 100644 --- a/sample/iosApp/KMPObservableViewModelSample/KMPObservableViewModelSampleApp.swift +++ b/sample/iosApp/KMPObservableViewModelSample/KMPObservableViewModelSampleApp.swift @@ -7,16 +7,68 @@ import SwiftUI +let useNavigationStack = false +let useScrollView = true +let useTextInput = true + @main struct KMPObservableViewModelSampleApp: App { + @State private var shouldPresentContent: Bool = false + var body: some Scene { WindowGroup { - NavigationStack { - NavigationLink("SwiftUI", destination: ContentView()) - Spacer().frame(height: 24) - NavigationLink("Compose MP", destination: ContentViewMP()) + NavigationStackCompat(useNavigationStack: useNavigationStack) { + Button { + shouldPresentContent = true + } label: { + Text("Next Screen") + } + .navigationDestinationCompat(useNavigationStack: useNavigationStack, isPresented: $shouldPresentContent) { + ContentView() + } } } } } + +struct NavigationStackCompat: View where Content: View { + + let useNavigationStack: Bool + @ViewBuilder var content: () -> Content + + var body: some View { + if useNavigationStack { + NavigationStack(root: content) + } else { + NavigationView(content: content) + .navigationViewStyle(.stack) + } + } +} + +fileprivate struct NavigationDestinationModifier: ViewModifier { + let useNavigationStack: Bool + let isPresented: Binding + let destination: Destination + + func body(content: Content) -> some View { + if useNavigationStack { + content.navigationDestination(isPresented: isPresented) { + destination + } + } else { + content.background( + NavigationLink(destination: destination, isActive: isPresented) { + EmptyView() + } + ) + } + } +} + +extension View { + func navigationDestinationCompat(useNavigationStack: Bool, isPresented: Binding, @ViewBuilder destination: () -> Destination) -> some View { + modifier(NavigationDestinationModifier(useNavigationStack: useNavigationStack, isPresented: isPresented, destination: destination())) + } +} diff --git a/sample/shared/build.gradle.kts b/sample/shared/build.gradle.kts index aef3fdf..7fd45c3 100644 --- a/sample/shared/build.gradle.kts +++ b/sample/shared/build.gradle.kts @@ -32,6 +32,7 @@ kotlin { dependencies { implementation(libs.kotlinx.coroutines.core) api("com.rickclephas.kmp:kmp-observableviewmodel-core") + implementation("co.touchlab:kermit:2.0.4") implementation(compose.runtime) implementation(compose.ui) diff --git a/sample/shared/src/commonMain/kotlin/com/rickclephas/kmp/observableviewmodel/sample/shared/TimeTravelViewModel.kt b/sample/shared/src/commonMain/kotlin/com/rickclephas/kmp/observableviewmodel/sample/shared/TimeTravelViewModel.kt index 596a966..3562fb1 100644 --- a/sample/shared/src/commonMain/kotlin/com/rickclephas/kmp/observableviewmodel/sample/shared/TimeTravelViewModel.kt +++ b/sample/shared/src/commonMain/kotlin/com/rickclephas/kmp/observableviewmodel/sample/shared/TimeTravelViewModel.kt @@ -1,11 +1,21 @@ package com.rickclephas.kmp.observableviewmodel.sample.shared +import co.touchlab.kermit.Logger import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesState import com.rickclephas.kmp.observableviewmodel.* import kotlinx.coroutines.flow.* import kotlin.random.Random open class TimeTravelViewModel: ViewModel() { + + init { + Logger.i("TimeTravelViewModel") { "init $this" } + } + + override fun onCleared() { + Logger.i("TimeTravelViewModel") { "clear $this" } + super.onCleared() + } private val clockTime = Clock.time