Skip to content

Commit 44066ec

Browse files
authored
Merge pull request #341 from joreilly/dep_updates
dep updates + iOS code cleanup
2 parents 61c0b89 + 188c8f8 commit 44066ec

File tree

10 files changed

+91
-59
lines changed

10 files changed

+91
-59
lines changed

.junie/guidelines.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Project Guidelines
2+
3+
## Project Structure
4+
This is a Kotlin Multiplatform project with Compose Multiplatform that includes:
5+
* `composeApp` - Shared Kotlin code with Compose UI
6+
* `iosApp` - iOS application
7+
8+
## Building the Project
9+
When building this project, Junie should use the following Gradle task:
10+
```
11+
:compose-desktop:jar
12+
```

common/src/commonMain/kotlin/dev/johnoreilly/common/viewmodel/CountriesViewModelShared.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import software.amazon.lastmile.kotlin.inject.anvil.SingleIn
1616
data class Country(val code: String, val displayName: String)
1717

1818
@Inject
19-
@SingleIn(AppScope::class)
2019
open class CountriesViewModelShared(cityBikesRepository: CityBikesRepository) : ViewModel() {
2120

2221
/**

common/src/commonMain/kotlin/dev/johnoreilly/common/viewmodel/NetworksViewModelShared.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import software.amazon.lastmile.kotlin.inject.anvil.AppScope
1515
import software.amazon.lastmile.kotlin.inject.anvil.SingleIn
1616

1717
@Inject
18-
@SingleIn(AppScope::class)
1918
open class NetworksViewModelShared(cityBikesRepository: CityBikesRepository) : ViewModel() {
2019
private val countryCode = MutableStateFlow<String?>(viewModelScope, null)
2120

common/src/commonMain/kotlin/dev/johnoreilly/common/viewmodel/StationsViewModelShared.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@ import kotlinx.coroutines.flow.filterNotNull
1313
import kotlinx.coroutines.flow.flatMapLatest
1414
import me.tatarka.inject.annotations.Inject
1515
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
16-
import software.amazon.lastmile.kotlin.inject.anvil.ContributesBinding
1716
import software.amazon.lastmile.kotlin.inject.anvil.SingleIn
1817

1918
@OptIn(ExperimentalCoroutinesApi::class)
2019
@Inject
21-
@SingleIn(AppScope::class)
2220
open class StationsViewModelShared(cityBikesRepository: CityBikesRepository) : ViewModel() {
2321
private val network = MutableStateFlow<String?>(viewModelScope, null)
2422

gradle/libs.versions.toml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
[versions]
2-
kotlin = "2.2.21"
3-
ksp = "2.3.0"
2+
kotlin = "2.3.0"
3+
ksp = "2.3.3"
44

5-
androidGradlePlugin = "8.13.1"
6-
androidxActivity = "1.11.0"
7-
androidxComposeBom = "2025.11.00"
8-
androidxLifecycle = "2.9.4"
5+
androidGradlePlugin = "8.12.3"
6+
androidxActivity = "1.12.2"
7+
androidxComposeBom = "2025.12.01"
8+
androidxLifecycle = "2.10.0"
99
androidxNavigationCompose = "2.9.6"
10-
androidxRoom = "2.8.3"
10+
androidxRoom = "2.8.4"
1111
circuit = "0.31.0"
1212
composeLifecyleRuntime="2.9.6"
1313
compose-multiplatform = "1.9.3"
1414
composeAdaptiveLayout = "1.2.0"
1515
coroutines = "1.10.2"
1616
junit = "4.13.2"
17-
kmpNativeCoroutines = "1.0.0-ALPHA-48"
18-
kmpObservableViewModel = "1.0.0-BETA-15"
17+
kmpNativeCoroutines = "1.0.0"
18+
kmpObservableViewModel = "1.0.1"
1919
kotlin-inject-anvil = "0.1.6"
20-
kotlininject = "0.8.0"
20+
kotlininject = "0.9.0"
2121
kotlinxSerialization = "1.9.0"
22-
ktor = "3.3.2"
23-
okhttp = "5.3.0"
22+
ktor = "3.3.3"
23+
okhttp = "5.3.2"
2424
runner = "1.7.0"
2525
slf4j = "2.0.17"
2626
slf4jAndroid = "2.0.17-0"
27-
sqlite = "2.6.1"
27+
sqlite = "2.6.2"
2828

2929
minSdk = "24"
3030
targetSdk = "36"

ios/BikeShare/BikeShare.xcodeproj/project.pbxproj

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
1A47335B2F0DB98000842388 /* KMPObservableViewModelCore in Frameworks */ = {isa = PBXBuildFile; productRef = 1A47335A2F0DB98000842388 /* KMPObservableViewModelCore */; };
11+
1A47335D2F0DB98000842388 /* KMPObservableViewModelSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 1A47335C2F0DB98000842388 /* KMPObservableViewModelSwiftUI */; };
12+
1A47335F2F0EE25700842388 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A47335E2F0EE25400842388 /* Theme.swift */; };
1013
1A56764C24D351FC0047F88F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56764B24D351FC0047F88F /* AppDelegate.swift */; };
1114
1A56764E24D351FC0047F88F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56764D24D351FC0047F88F /* SceneDelegate.swift */; };
1215
1A56765024D351FC0047F88F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A56764F24D351FC0047F88F /* ContentView.swift */; };
1316
1A56765224D351FF0047F88F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A56765124D351FF0047F88F /* Assets.xcassets */; };
1417
1A56765524D351FF0047F88F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A56765424D351FF0047F88F /* Preview Assets.xcassets */; };
1518
1A56765824D351FF0047F88F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A56765624D351FF0047F88F /* LaunchScreen.storyboard */; };
1619
1A59905929579788006DD8F2 /* KMMiewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A59905829579788006DD8F2 /* KMMiewModel.swift */; };
17-
1A68CB7B2BEEAD6600F4AA1B /* KMPObservableViewModelCore in Frameworks */ = {isa = PBXBuildFile; productRef = 1A68CB7A2BEEAD6600F4AA1B /* KMPObservableViewModelCore */; };
18-
1A68CB7D2BEEAD6600F4AA1B /* KMPObservableViewModelSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 1A68CB7C2BEEAD6600F4AA1B /* KMPObservableViewModelSwiftUI */; };
1920
/* End PBXBuildFile section */
2021

2122
/* Begin PBXCopyFilesBuildPhase section */
@@ -37,6 +38,7 @@
3738
1A11F79C2732AE86006E20C5 /* BikeShareWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BikeShareWidget.swift; sourceTree = "<group>"; };
3839
1A11F79E2732AE87006E20C5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
3940
1A11F7A02732AE87006E20C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
41+
1A47335E2F0EE25400842388 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
4042
1A56764824D351FC0047F88F /* BikeShare.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BikeShare.app; sourceTree = BUILT_PRODUCTS_DIR; };
4143
1A56764B24D351FC0047F88F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4244
1A56764D24D351FC0047F88F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
@@ -53,8 +55,8 @@
5355
isa = PBXFrameworksBuildPhase;
5456
buildActionMask = 2147483647;
5557
files = (
56-
1A68CB7B2BEEAD6600F4AA1B /* KMPObservableViewModelCore in Frameworks */,
57-
1A68CB7D2BEEAD6600F4AA1B /* KMPObservableViewModelSwiftUI in Frameworks */,
58+
1A47335B2F0DB98000842388 /* KMPObservableViewModelCore in Frameworks */,
59+
1A47335D2F0DB98000842388 /* KMPObservableViewModelSwiftUI in Frameworks */,
5860
);
5961
runOnlyForDeploymentPostprocessing = 0;
6062
};
@@ -93,6 +95,7 @@
9395
1A56764A24D351FC0047F88F /* BikeShare */ = {
9496
isa = PBXGroup;
9597
children = (
98+
1A47335E2F0EE25400842388 /* Theme.swift */,
9699
1A56764B24D351FC0047F88F /* AppDelegate.swift */,
97100
1A56764D24D351FC0047F88F /* SceneDelegate.swift */,
98101
1A56764F24D351FC0047F88F /* ContentView.swift */,
@@ -149,8 +152,8 @@
149152
);
150153
name = BikeShare;
151154
packageProductDependencies = (
152-
1A68CB7A2BEEAD6600F4AA1B /* KMPObservableViewModelCore */,
153-
1A68CB7C2BEEAD6600F4AA1B /* KMPObservableViewModelSwiftUI */,
155+
1A47335A2F0DB98000842388 /* KMPObservableViewModelCore */,
156+
1A47335C2F0DB98000842388 /* KMPObservableViewModelSwiftUI */,
154157
);
155158
productName = BikeShare;
156159
productReference = 1A56764824D351FC0047F88F /* BikeShare.app */;
@@ -181,7 +184,7 @@
181184
);
182185
mainGroup = 1A56763F24D351FC0047F88F;
183186
packageReferences = (
184-
1A68CB792BEEAD6600F4AA1B /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */,
187+
1A4733592F0DB98000842388 /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */,
185188
);
186189
productRefGroup = 1A56764924D351FC0047F88F /* Products */;
187190
projectDirPath = "";
@@ -232,6 +235,7 @@
232235
files = (
233236
1A56764C24D351FC0047F88F /* AppDelegate.swift in Sources */,
234237
1A56764E24D351FC0047F88F /* SceneDelegate.swift in Sources */,
238+
1A47335F2F0EE25700842388 /* Theme.swift in Sources */,
235239
1A56765024D351FC0047F88F /* ContentView.swift in Sources */,
236240
1A59905929579788006DD8F2 /* KMMiewModel.swift in Sources */,
237241
);
@@ -371,13 +375,13 @@
371375
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
372376
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
373377
CODE_SIGN_STYLE = Automatic;
374-
CURRENT_PROJECT_VERSION = 2;
378+
CURRENT_PROJECT_VERSION = 5;
375379
DEVELOPMENT_ASSET_PATHS = "\"BikeShare/Preview Content\"";
376380
DEVELOPMENT_TEAM = NT77748GS8;
377381
ENABLE_PREVIEWS = YES;
378382
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../../common/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
379383
INFOPLIST_FILE = BikeShare/Info.plist;
380-
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
384+
IPHONEOS_DEPLOYMENT_TARGET = 18.6;
381385
LD_RUNPATH_SEARCH_PATHS = (
382386
"$(inherited)",
383387
"@executable_path/Frameworks",
@@ -401,13 +405,13 @@
401405
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
402406
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
403407
CODE_SIGN_STYLE = Automatic;
404-
CURRENT_PROJECT_VERSION = 2;
408+
CURRENT_PROJECT_VERSION = 5;
405409
DEVELOPMENT_ASSET_PATHS = "\"BikeShare/Preview Content\"";
406410
DEVELOPMENT_TEAM = NT77748GS8;
407411
ENABLE_PREVIEWS = YES;
408412
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../.../common/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
409413
INFOPLIST_FILE = BikeShare/Info.plist;
410-
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
414+
IPHONEOS_DEPLOYMENT_TARGET = 18.6;
411415
LD_RUNPATH_SEARCH_PATHS = (
412416
"$(inherited)",
413417
"@executable_path/Frameworks",
@@ -449,25 +453,25 @@
449453
/* End XCConfigurationList section */
450454

451455
/* Begin XCRemoteSwiftPackageReference section */
452-
1A68CB792BEEAD6600F4AA1B /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */ = {
456+
1A4733592F0DB98000842388 /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */ = {
453457
isa = XCRemoteSwiftPackageReference;
454-
repositoryURL = "https://github.com/rickclephas/KMP-ObservableViewModel.git";
458+
repositoryURL = "https://github.com/rickclephas/KMP-ObservableViewModel";
455459
requirement = {
456-
kind = exactVersion;
457-
version = "1.0.0-BETA-1";
460+
kind = upToNextMajorVersion;
461+
minimumVersion = 1.0.0;
458462
};
459463
};
460464
/* End XCRemoteSwiftPackageReference section */
461465

462466
/* Begin XCSwiftPackageProductDependency section */
463-
1A68CB7A2BEEAD6600F4AA1B /* KMPObservableViewModelCore */ = {
467+
1A47335A2F0DB98000842388 /* KMPObservableViewModelCore */ = {
464468
isa = XCSwiftPackageProductDependency;
465-
package = 1A68CB792BEEAD6600F4AA1B /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */;
469+
package = 1A4733592F0DB98000842388 /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */;
466470
productName = KMPObservableViewModelCore;
467471
};
468-
1A68CB7C2BEEAD6600F4AA1B /* KMPObservableViewModelSwiftUI */ = {
472+
1A47335C2F0DB98000842388 /* KMPObservableViewModelSwiftUI */ = {
469473
isa = XCSwiftPackageProductDependency;
470-
package = 1A68CB792BEEAD6600F4AA1B /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */;
474+
package = 1A4733592F0DB98000842388 /* XCRemoteSwiftPackageReference "KMP-ObservableViewModel" */;
471475
productName = KMPObservableViewModelSwiftUI;
472476
};
473477
/* End XCSwiftPackageProductDependency section */

ios/BikeShare/BikeShare.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ios/BikeShare/BikeShare/ContentView.swift

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,49 +4,50 @@ import BikeShareKit
44
import KMPObservableViewModelCore
55
import KMPObservableViewModelSwiftUI
66

7-
// BikeShare theme colors matching Compose
8-
let BikeGreen = Color(red: 0x1E/255.0, green: 0x8E/255.0, blue: 0x3E/255.0)
9-
let BikeGreenLight = Color(red: 0x7C/255.0, green: 0xB3/255.0, blue: 0x42/255.0)
10-
let BikeGreenDark = Color(red: 0x00/255.0, green: 0x5D/255.0, blue: 0x1B/255.0)
11-
let BikeBlue = Color(red: 0x19/255.0, green: 0x76/255.0, blue: 0xD2/255.0)
12-
let BikeBlueDark = Color(red: 0x0D/255.0, green: 0x47/255.0, blue: 0xA1/255.0)
137

14-
// Availability colors matching Compose
15-
let lowAvailabilityColor = Color(red: 0xE6/255.0, green: 0x51/255.0, blue: 0x00/255.0)
16-
let mediumAvailabilityColor = Color(red: 0xFF/255.0, green: 0xA0/255.0, blue: 0x00/255.0)
17-
let highAvailabilityColor = Color(red: 0x2E/255.0, green: 0x7D/255.0, blue: 0x32/255.0)
8+
enum Route: Hashable {
9+
case networks(countryCode: String)
10+
case stations(network: Network)
11+
}
1812

1913
struct ContentView : View {
2014
let applicationComponent: IosApplicationComponent
2115

2216
@ObservedViewModel var viewModel: CountriesViewModelShared
2317
@State var query: String = ""
18+
@State private var path = NavigationPath()
2419

2520
init(applicationComponent: IosApplicationComponent) {
2621
self.applicationComponent = applicationComponent
2722
self.viewModel = applicationComponent.countriesViewModel
2823
}
2924

3025
var body: some View {
31-
NavigationView {
26+
NavigationStack(path: $path) {
3227
ScrollView {
3328
LazyVStack(spacing: 8) {
3429
ForEach(viewModel.countryList.filter { query.isEmpty || $0.displayName.contains(query)}, id: \.self) { country in
35-
NavigationLink(destination: NetworkListView(applicationComponent: applicationComponent, countryCode: country.code)) {
30+
NavigationLink(value: Route.networks(countryCode: country.code)) {
3631
CountryCardView(country: country)
3732
}
38-
.buttonStyle(PlainButtonStyle())
3933
}
4034
}
4135
.padding(.horizontal, 12)
4236
.padding(.vertical, 8)
4337
}
4438
.background(Color(UIColor.systemGroupedBackground))
4539
.searchable(text: $query)
46-
.navigationTitle("BikeShare")
40+
.navigationTitle("BikeShareLive")
4741
.navigationBarTitleDisplayMode(.large)
42+
.navigationDestination(for: Route.self) { route in
43+
switch route {
44+
case .networks(let countryCode):
45+
NetworkListView(applicationComponent: applicationComponent, countryCode: countryCode)
46+
case .stations(let network):
47+
StationListTabView(applicationComponent: applicationComponent, network: network)
48+
}
49+
}
4850
}
49-
.navigationViewStyle(StackNavigationViewStyle())
5051
}
5152
}
5253

@@ -58,7 +59,7 @@ struct CountryCardView: View {
5859
// Flag
5960
Text(countryFlag(from: country.code))
6061
.font(.system(size: 40))
61-
.frame(width: 48, height: 48)
62+
.frame(width: 24, height: 24)
6263
.background(Color(UIColor.secondarySystemGroupedBackground))
6364
.cornerRadius(4)
6465
.padding(4)
@@ -97,7 +98,7 @@ struct NetworkListView: View {
9798
ScrollView {
9899
LazyVStack(spacing: 8) {
99100
ForEach(viewModel.networkList) { network in
100-
NavigationLink(destination: StationListTabView(applicationComponent: applicationComponent, network: network)) {
101+
NavigationLink(value: Route.stations(network: network)) {
101102
NetworkCardView(network: network)
102103
}
103104
.buttonStyle(PlainButtonStyle())
@@ -366,6 +367,8 @@ func countryFlag(from countryCode: String) -> String {
366367
}
367368

368369

369-
extension Station: Identifiable { }
370-
extension Network: Identifiable { }
370+
extension Station: @retroactive Identifiable { }
371+
extension Network: @retroactive Identifiable { }
371372

373+
374+
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import BikeShareKit
22
import KMPObservableViewModelCore
33

4-
extension Kmp_observableviewmodel_coreViewModel: ViewModel { }
4+
extension Kmp_observableviewmodel_coreViewModel: @retroactive ViewModel { }
5+
6+
extension Kmp_observableviewmodel_coreViewModel: @retroactive Observable { }
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import SwiftUI
2+
3+
4+
// BikeShare theme colors matching Compose
5+
let BikeGreen = Color(red: 0x1E/255.0, green: 0x8E/255.0, blue: 0x3E/255.0)
6+
let BikeGreenLight = Color(red: 0x7C/255.0, green: 0xB3/255.0, blue: 0x42/255.0)
7+
let BikeGreenDark = Color(red: 0x00/255.0, green: 0x5D/255.0, blue: 0x1B/255.0)
8+
let BikeBlue = Color(red: 0x19/255.0, green: 0x76/255.0, blue: 0xD2/255.0)
9+
let BikeBlueDark = Color(red: 0x0D/255.0, green: 0x47/255.0, blue: 0xA1/255.0)
10+
11+
// Availability colors matching Compose
12+
let lowAvailabilityColor = Color(red: 0xE6/255.0, green: 0x51/255.0, blue: 0x00/255.0)
13+
let mediumAvailabilityColor = Color(red: 0xFF/255.0, green: 0xA0/255.0, blue: 0x00/255.0)
14+
let highAvailabilityColor = Color(red: 0x2E/255.0, green: 0x7D/255.0, blue: 0x32/255.0)

0 commit comments

Comments
 (0)