Skip to content

Commit

Permalink
(wip) Router push & pop new screen with viewModels integration
Browse files Browse the repository at this point in the history
  • Loading branch information
marcantoinefortier committed Apr 27, 2022
1 parent e8d9bd5 commit 409148c
Show file tree
Hide file tree
Showing 19 changed files with 377 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
Expand All @@ -12,7 +13,7 @@ import kotlinx.coroutines.flow.flowOf
fun Greeting(textFlow: Flow<String>) {
val text: String by textFlow.collectAsState("initial")

Text(text = text)
Text(text = text, textAlign = TextAlign.Center)
}

@Preview
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@ package com.mirego.kmp.boilerplate.android.composables
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import com.mirego.kmp.boilerplate.routing.MainRouter
import com.mirego.kmp.boilerplate.routing.Screen
import com.mirego.kmp.boilerplate.android.composables.example.Example
import com.mirego.kmp.boilerplate.android.composables.home.Home
import com.mirego.kmp.boilerplate.presentation.routing.MainRouter
import com.mirego.kmp.boilerplate.presentation.routing.Router
import com.mirego.kmp.boilerplate.presentation.routing.Screen
import com.mirego.kmp.boilerplate.presentation.viewmodel.MobileViewModelFactory
import com.mirego.kmp.boilerplate.presentation.viewmodel.ViewModelFactory

@Composable
fun Main() {
val screen: Screen by MainRouter.screen.collectAsState(initial = Screen.Home)
fun Main(
router: Router = MainRouter,
viewModelFactory: ViewModelFactory = MobileViewModelFactory
) {
val screen: Screen by router.screen.collectAsState(initial = Screen.Home)

when (screen) {
is Screen.Home -> Home()
screen.let {
when (it) {
Screen.Home -> Home(viewModel = viewModelFactory.homeViewModel)
is Screen.Example -> Example(viewModel = viewModelFactory.exampleViewModel(it.origin))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.mirego.kmp.boilerplate.android.composables.example

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.mirego.kmp.boilerplate.presentation.viewmodel.example.ExampleViewModel

@Composable
fun Example(viewModel: ExampleViewModel) {
val exampleText: String by viewModel.exampleMessage.collectAsState(initial = "")
val backButtonText: String by viewModel.backButtonText.collectAsState(initial = "")

Box(modifier = Modifier.fillMaxSize(1.0f), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = exampleText)

Spacer(modifier = Modifier.height(8.dp))

Button(onClick = viewModel::onBackButtonClick) {
Text(text = backButtonText)
}
}
}
}

@Preview
@Composable
fun PreviewExample() {
Example(viewModel = ExampleViewModel.Preview)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.mirego.kmp.boilerplate.android.composables.home

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.mirego.kmp.boilerplate.android.composables.Greeting
import com.mirego.kmp.boilerplate.presentation.viewmodel.home.HomeViewModel

@Composable
fun Home(viewModel: HomeViewModel) {
Box(modifier = Modifier.fillMaxSize(1.0f), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Greeting(textFlow = viewModel.greetingMessage)

Spacer(modifier = Modifier.height(8.dp))

val buttonText: String by viewModel.buttonText.collectAsState("")

Button(onClick = viewModel::onButtonClick) {
Text(text = buttonText)
}
}
}
}

@Preview
@Composable
fun PreviewHome() {
Home(viewModel = HomeViewModel.Preview)
}
22 changes: 21 additions & 1 deletion iosApp/iosApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
BC5CC7B427760F2C00426C97 /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* Home.swift */; };
BC64D820278C9DD700FAF397 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC64D81F278C9DD700FAF397 /* Main.swift */; };
BC83B466276E4F080053E064 /* FlowUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC83B465276E4F080053E064 /* FlowUtils.swift */; };
BCFFCFD9278F551300EAA9BA /* Example.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCFFCFD8278F550800EAA9BA /* Example.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -27,6 +28,7 @@
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BC64D81F278C9DD700FAF397 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = "<group>"; };
BC83B465276E4F080053E064 /* FlowUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowUtils.swift; sourceTree = "<group>"; };
BCFFCFD8278F550800EAA9BA /* Example.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Example.swift; sourceTree = "<group>"; };
E232C917135C2C1E3BC8748A /* Pods-iosApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iosApp.release.xcconfig"; path = "Target Support Files/Pods-iosApp/Pods-iosApp.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -84,8 +86,9 @@
BC5CC7B327760ED800426C97 /* Views */ = {
isa = PBXGroup;
children = (
BCFFCFD7278F550400EAA9BA /* Example */,
BCFFCFD6278F54FA00EAA9BA /* Home */,
BC64D81F278C9DD700FAF397 /* Main.swift */,
7555FF82242A565900829871 /* Home.swift */,
);
path = Views;
sourceTree = "<group>";
Expand All @@ -98,6 +101,22 @@
path = Utils;
sourceTree = "<group>";
};
BCFFCFD6278F54FA00EAA9BA /* Home */ = {
isa = PBXGroup;
children = (
7555FF82242A565900829871 /* Home.swift */,
);
path = Home;
sourceTree = "<group>";
};
BCFFCFD7278F550400EAA9BA /* Example */ = {
isa = PBXGroup;
children = (
BCFFCFD8278F550800EAA9BA /* Example.swift */,
);
path = Example;
sourceTree = "<group>";
};
C8C629BFDC2144230B71E3BC /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -215,6 +234,7 @@
BC83B466276E4F080053E064 /* FlowUtils.swift in Sources */,
BC64D820278C9DD700FAF397 /* Main.swift in Sources */,
BC5CC7B427760F2C00426C97 /* Home.swift in Sources */,
BCFFCFD9278F551300EAA9BA /* Example.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
78 changes: 78 additions & 0 deletions iosApp/iosApp.xcworkspace/xcshareddata/xcschemes/iosApp.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7555FF7A242A565900829871"
BuildableName = "iosApp.app"
BlueprintName = "iosApp"
ReferencedContainer = "container:iosApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7555FF7A242A565900829871"
BuildableName = "iosApp.app"
BlueprintName = "iosApp"
ReferencedContainer = "container:iosApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7555FF7A242A565900829871"
BuildableName = "iosApp.app"
BlueprintName = "iosApp"
ReferencedContainer = "container:iosApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
32 changes: 32 additions & 0 deletions iosApp/iosApp/Views/Example/Example.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import SwiftUI
import shared

struct Example: View {

private let viewModel: ExampleViewModel

@ObservedObject var message: ObservableFlowWrapper<NSString>
@ObservedObject var backButtonText: ObservableFlowWrapper<NSString>

init(viewModel: ExampleViewModel) {
self.viewModel = viewModel

message = ObservableFlowWrapper<NSString>(viewModel.exampleMessage, initial: "")
backButtonText = ObservableFlowWrapper<NSString>(viewModel.backButtonText, initial: "")
}

var body: some View {
VStack(alignment: .center, spacing: 16) {
Text("\(message.value)")

Button("\(backButtonText.value)", action: viewModel.onBackButtonClick)
}
}

}

struct Example_Previews: PreviewProvider {
static var previews: some View {
Example(viewModel: ExampleViewModelPreview())
}
}
17 changes: 0 additions & 17 deletions iosApp/iosApp/Views/Home.swift

This file was deleted.

31 changes: 31 additions & 0 deletions iosApp/iosApp/Views/Home/Home.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import SwiftUI
import shared

struct Home: View {

private let viewModel: HomeViewModel

@ObservedObject var message: ObservableFlowWrapper<NSString>
@ObservedObject var buttonText: ObservableFlowWrapper<NSString>

init(viewModel: HomeViewModel) {
self.viewModel = viewModel

message = ObservableFlowWrapper<NSString>(viewModel.greetingMessage, initial: "")
buttonText = ObservableFlowWrapper<NSString>(viewModel.buttonText, initial: "")
}

var body: some View {
VStack(alignment: .center, spacing: 16) {
Text("\(message.value)")

Button("\(buttonText.value)", action: viewModel.onButtonClick)
}
}
}

struct Home_Previews: PreviewProvider {
static var previews: some View {
Home(viewModel: HomeViewModelPreview())
}
}
17 changes: 15 additions & 2 deletions iosApp/iosApp/Views/Main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,25 @@ import shared

struct Main: View {

private let router: Router
private let viewModelFactory: ViewModelFactory

init(router: Router = MainRouter(),
viewModelFactory: ViewModelFactory = MobileViewModelFactory()) {
self.router = router
self.viewModelFactory = viewModelFactory
}

@ObservedObject var screen = ObservableFlowWrapper<Screen>(MainRouter().screen, initial: Screen.Home())

var body: some View {
switch screen.value {
case is Screen.Home:
Home()
case _ as Screen.Home:
Home(viewModel: viewModelFactory.homeViewModel)
case let screen as Screen.Example:
Example(viewModel: viewModelFactory.exampleViewModel(origin: screen.origin))
default:
fatalError("Unsupported screen \(screen.value)")
}
}
}
Loading

0 comments on commit 409148c

Please sign in to comment.