Skip to content

Commit

Permalink
Add Konnectivity library to access and monitor network state changes (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
marcantoinefortier authored Dec 8, 2023
1 parent 680deae commit 8baf0d7
Show file tree
Hide file tree
Showing 14 changed files with 111 additions and 9 deletions.
2 changes: 2 additions & 0 deletions androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,6 @@ dependencies {
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.tooling)
implementation(libs.androidx.compose.material)

implementation(libs.androidx.startup.runtime)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.tooling.preview.Preview
import com.mirego.kmp.boilerplate.previews.PreviewContext
import kotlinx.coroutines.flow.Flow

@Composable
Expand All @@ -17,5 +18,7 @@ fun Greeting(textFlow: Flow<String>) {
@Preview(showSystemUi = true)
@Composable
fun PreviewGreeting() {
Greeting(Greeting().greeting())
PreviewContext {
Greeting(Greeting().greeting())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.mirego.kmp.boilerplate.previews

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.startup.AppInitializer
import com.mirego.kmp.boilerplate.platform.AppContextInitializer

@Composable
fun PreviewContext(content: @Composable () -> Unit) {
// @Composable previews do not call AppInitializer. We must initialize our components manually.
AppInitializer.getInstance(LocalContext.current)
.initializeComponent(AppContextInitializer::class.java)

content()
}
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
[versions]
androidComposeCompiler = "1.5.6"
androidGradlePlugin = "8.2.0"
androidxStartup = "1.1.1"
androidxActivityCompose = "1.8.1"
androidxAppcompat = "1.6.1"
androidxComposeBom = "2023.10.01"
konnectivity = "0.3.0"
kotlin = "1.9.21"
kotlinxCoroutines = "1.7.3"
kotlinxSerialization = "1.6.0"
Expand All @@ -16,6 +18,8 @@ androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", versi
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-compose-material = { group = "androidx.compose.material", name = "material" }
androidx-startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "androidxStartup" }
konnectivity = { module = "com.mirego:konnectivity", version.ref = "konnectivity" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
Expand Down
8 changes: 6 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
PODS:
- Shared (0.0.1)
- Reachability (3.2)
- Shared (0.0.1):
- Reachability (~> 3.2)
- SwiftLint (0.52.4)

DEPENDENCIES:
Expand All @@ -8,14 +10,16 @@ DEPENDENCIES:

SPEC REPOS:
trunk:
- Reachability
- SwiftLint

EXTERNAL SOURCES:
Shared:
:path: "../shared"

SPEC CHECKSUMS:
Shared: 4d22deb908e7a9ed9a64ea2d3fcc53255a207993
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
Shared: 394ccbb1a148f40e374cb91aa5b75c96b121a775
SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3

PODFILE CHECKSUM: 83ebf5d7b61ce65029f18160027c7392430ee27f
Expand Down
4 changes: 4 additions & 0 deletions ios/iosApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
7555FF83242A565900829871 /* GreetingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* GreetingView.swift */; };
9B8ACFDB4E332DFCA8B97CBB /* Pods_iosApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E4E1328B104D05A50A097EE /* Pods_iosApp.framework */; };
BC5700EB2B1A94D200525C22 /* PreviewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5700EA2B1A94D200525C22 /* PreviewContext.swift */; };
BC83B466276E4F080053E064 /* FlowUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC83B465276E4F080053E064 /* FlowUtils.swift */; };
/* End PBXBuildFile section */

Expand All @@ -24,6 +25,7 @@
7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF82242A565900829871 /* GreetingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GreetingView.swift; sourceTree = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BC5700EA2B1A94D200525C22 /* PreviewContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewContext.swift; sourceTree = "<group>"; };
BC83B465276E4F080053E064 /* FlowUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowUtils.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 All @@ -44,6 +46,7 @@
isa = PBXGroup;
children = (
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */,
BC5700EA2B1A94D200525C22 /* PreviewContext.swift */,
);
path = "Preview Content";
sourceTree = "<group>";
Expand Down Expand Up @@ -240,6 +243,7 @@
files = (
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
7555FF83242A565900829871 /* GreetingView.swift in Sources */,
BC5700EB2B1A94D200525C22 /* PreviewContext.swift in Sources */,
BC83B466276E4F080053E064 /* FlowUtils.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
4 changes: 3 additions & 1 deletion ios/iosApp/GreetingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ struct GreetingView: View {
}

#Preview {
GreetingView()
PreviewContext {
GreetingView()
}
}
10 changes: 10 additions & 0 deletions ios/iosApp/Preview Content/PreviewContext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Shared
import SwiftUI

struct PreviewContext<Content>: View where Content: View {
let content: @MainActor () -> Content

var body: some View {
content()
}
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://s3.amazonaws.com/mirego-maven/public")
}
}

Expand Down
4 changes: 2 additions & 2 deletions shared/Shared.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ Pod::Spec.new do |spec|
spec.summary = 'Project summary'
spec.vendored_frameworks = 'build/cocoapods/framework/Shared.framework'
spec.libraries = 'c++'
spec.ios.deployment_target = '15.0'
spec.dependency 'Reachability', '~> 3.2'

if !Dir.exist?('build/cocoapods/framework/Shared.framework') || Dir.empty?('build/cocoapods/framework/Shared.framework')
raise "
Expand Down
10 changes: 10 additions & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ kotlin {
framework {
baseName = "Shared"
}
ios.deploymentTarget = "15.0"

pod("Reachability", "~> 3.2")
}

sourceSets {
Expand All @@ -45,6 +48,7 @@ kotlin {
dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
api(libs.konnectivity)
}
}

Expand All @@ -54,6 +58,12 @@ kotlin {
implementation(libs.kotlinx.coroutines.test)
}
}

androidMain {
dependencies {
implementation(libs.androidx.startup.runtime)
}
}
}

@OptIn(ExperimentalKotlinGradlePluginApi::class)
Expand Down
16 changes: 15 additions & 1 deletion shared/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.mirego.kmp.boilerplate.platform.AppContextInitializer"
android:value="androidx.startup" />
</provider>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mirego.kmp.boilerplate.platform

import android.content.Context
import androidx.startup.Initializer
import com.mirego.konnectivity.KonnectivityInitializer

internal lateinit var appContext: Context

class AppContextInitializer : Initializer<Unit> {
override fun create(context: Context) {
appContext = context
}

override fun dependencies() = listOf(
KonnectivityInitializer::class.java
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,33 @@ package com.mirego.kmp.boilerplate
import com.mirego.kmp.boilerplate.platform.Platform
import com.mirego.kmp.boilerplate.utils.CFlow
import com.mirego.kmp.boilerplate.utils.wrap
import kotlinx.coroutines.flow.flowOf
import com.mirego.konnectivity.Konnectivity
import com.mirego.konnectivity.NetworkState
import kotlinx.coroutines.flow.map

class Greeting {
private val platform = Platform()
private val konnectivity = Konnectivity()

private val greetingText = buildString {
appendLine("Hello! 👋")
appendLine(platform.system)
appendLine(platform.locale)
appendLine(platform.version)
appendLine()
}

fun greeting(): CFlow<String> = flowOf(greetingText).wrap()
fun greeting(): CFlow<String> = konnectivity.networkState
.map { networkState ->
greetingText + networkState.asGreetingInfo()
}
.wrap()

private fun NetworkState.asGreetingInfo(): String = "By the way, you're " + when (this) {
NetworkState.Unreachable -> "offline. 🔌"
is NetworkState.Reachable -> when (metered) {
true -> "online, but your connection is metered. 📶"
else -> "online! 🛜"
}
}
}

0 comments on commit 8baf0d7

Please sign in to comment.