Skip to content

Commit 2a54af2

Browse files
authored
Merge pull request #601 from ooni/desktop-with-jar
Desktop support with temporary engine JAR
2 parents 443b568 + b0dd19c commit 2a54af2

File tree

23 files changed

+521
-70
lines changed

23 files changed

+521
-70
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ captures
1818
/iosApp/Pods/
1919
.kotlin
2020
Gemfile.lock
21+
temp

composeApp/build.gradle.kts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import com.android.build.api.variant.FilterConfiguration.FilterType.ABI
22
import org.jetbrains.compose.ExperimentalComposeLibrary
3+
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
34
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
45
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
56
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree
@@ -60,6 +61,8 @@ kotlin {
6061
iosArm64()
6162
iosSimulatorArm64()
6263

64+
jvm("desktop")
65+
6366
cocoapods {
6467
ios.deploymentTarget = "14.0"
6568

@@ -85,6 +88,7 @@ kotlin {
8588
androidMain.dependencies {
8689
implementation(compose.preview)
8790
implementation(libs.bundles.android)
91+
implementation(libs.bundles.mobile)
8892
}
8993
commonMain {
9094
dependencies {
@@ -109,7 +113,16 @@ kotlin {
109113
}
110114
iosMain.dependencies {
111115
implementation(libs.sqldelight.native)
116+
implementation(libs.bundles.mobile)
112117
}
118+
val desktopMain by getting {
119+
dependencies {
120+
implementation(files("./src/desktopMain/libs/oonimkall.jar"))
121+
implementation(compose.desktop.currentOs)
122+
implementation(libs.bundles.desktop)
123+
}
124+
}
125+
// Testing
113126
commonTest.dependencies {
114127
implementation(kotlin("test"))
115128
@OptIn(ExperimentalComposeLibrary::class)
@@ -287,6 +300,18 @@ android {
287300
flavorDimensions += "license"
288301
}
289302

303+
compose.desktop {
304+
application {
305+
mainClass = "org.ooni.probe.MainKt"
306+
307+
nativeDistributions {
308+
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
309+
packageName = "org.ooni.probe"
310+
packageVersion = android.defaultConfig.versionName
311+
}
312+
}
313+
}
314+
290315
sqldelight {
291316
databases {
292317
create("Database") {

composeApp/src/androidMain/kotlin/org/ooni/probe/AndroidApplication.kt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,17 @@ class AndroidApplication : Application() {
7777
}
7878

7979
private val platformInfo by lazy {
80-
object : PlatformInfo {
81-
override val buildName: String = BuildConfig.VERSION_NAME
82-
override val buildNumber: String = BuildConfig.VERSION_CODE.toString()
83-
override val platform = Platform.Android
84-
override val osVersion = Build.VERSION.SDK_INT.toString()
85-
override val model = "${Build.MANUFACTURER} ${Build.MODEL}"
86-
override val needsToRequestNotificationsPermission =
87-
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
88-
override val sentryDsn =
89-
"https://7a49ffedcb48b9b69705d1ac2c032c69@o155150.ingest.sentry.io/4508325642764288"
90-
}
80+
PlatformInfo(
81+
buildName = BuildConfig.VERSION_NAME,
82+
buildNumber = BuildConfig.VERSION_CODE.toString(),
83+
platform = Platform.Android,
84+
osVersion = Build.VERSION.SDK_INT.toString(),
85+
model = "${Build.MANUFACTURER} ${Build.MODEL}",
86+
needsToRequestNotificationsPermission =
87+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU,
88+
sentryDsn =
89+
"https://7a49ffedcb48b9b69705d1ac2c032c69@o155150.ingest.sentry.io/4508325642764288",
90+
)
9191
}
9292

9393
private fun readAssetFile(path: String) = assets.open(path).bufferedReader().use { it.readText() }
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.ooni.probe.ui.shared
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.remember
5+
import dev.icerock.moko.permissions.DeniedAlwaysException
6+
import dev.icerock.moko.permissions.DeniedException
7+
import dev.icerock.moko.permissions.RequestCanceledException
8+
import dev.icerock.moko.permissions.compose.BindEffect
9+
import dev.icerock.moko.permissions.compose.PermissionsControllerFactory
10+
import dev.icerock.moko.permissions.compose.rememberPermissionsControllerFactory
11+
import dev.icerock.moko.permissions.notifications.REMOTE_NOTIFICATION
12+
13+
@Composable
14+
actual fun buildPermissionsController(): PermissionsController {
15+
val mokoFactory: PermissionsControllerFactory = rememberPermissionsControllerFactory()
16+
val mokoController = remember(mokoFactory) { mokoFactory.createPermissionsController() }
17+
BindEffect(mokoController)
18+
val controller = remember(mokoController) {
19+
object : PermissionsController {
20+
override suspend fun providePermission(permission: Permission) {
21+
try {
22+
mokoController.providePermission(
23+
when (permission) {
24+
Permission.RemoteNotification ->
25+
dev.icerock.moko.permissions.Permission.REMOTE_NOTIFICATION
26+
},
27+
)
28+
} catch (e: DeniedException) {
29+
throw PermissionDeniedException()
30+
} catch (e: DeniedAlwaysException) {
31+
throw PermissionDeniedAlwaysException()
32+
} catch (e: RequestCanceledException) {
33+
throw PermissionRequestCanceledException()
34+
}
35+
}
36+
}
37+
}
38+
return controller
39+
}

composeApp/src/commonMain/kotlin/org/ooni/engine/Engine.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import org.ooni.probe.config.OrganizationConfig
2020
import org.ooni.probe.data.models.InstalledTestDescriptorModel
2121
import org.ooni.probe.data.models.NetTest
2222
import org.ooni.probe.shared.PlatformInfo
23-
import org.ooni.probe.shared.value
2423
import kotlin.coroutines.CoroutineContext
2524

2625
const val MAX_RUNTIME_DISABLED = -1
Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
package org.ooni.probe.shared
22

3-
interface PlatformInfo {
4-
val version: String
5-
get() = "$buildName ($buildNumber)"
6-
val buildName: String
7-
val buildNumber: String
8-
val platform: Platform
9-
val osVersion: String
10-
val model: String
11-
val needsToRequestNotificationsPermission: Boolean
12-
val sentryDsn: String
3+
data class PlatformInfo(
4+
val buildName: String,
5+
val buildNumber: String,
6+
val platform: Platform,
7+
val osVersion: String,
8+
val model: String,
9+
val needsToRequestNotificationsPermission: Boolean,
10+
val sentryDsn: String,
11+
) {
12+
val version get() = "$buildName ($buildNumber)"
1313
}
1414

1515
enum class Platform {
1616
Android,
1717
Ios,
18-
}
18+
Desktop,
19+
;
1920

20-
val Platform.value
21-
get() =
22-
when (this) {
23-
Platform.Android -> "android"
24-
Platform.Ios -> "ios"
21+
val value
22+
get() = when (this) {
23+
Android -> "android"
24+
Ios -> "ios"
25+
Desktop -> "desktop"
2526
}
27+
}

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/onboarding/OnboardingScreen.kt

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@ import androidx.compose.ui.text.style.TextAlign
4848
import androidx.compose.ui.unit.dp
4949
import androidx.compose.ui.window.DialogProperties
5050
import co.touchlab.kermit.Logger
51-
import dev.icerock.moko.permissions.DeniedAlwaysException
52-
import dev.icerock.moko.permissions.DeniedException
53-
import dev.icerock.moko.permissions.Permission
54-
import dev.icerock.moko.permissions.RequestCanceledException
55-
import dev.icerock.moko.permissions.compose.BindEffect
56-
import dev.icerock.moko.permissions.compose.PermissionsControllerFactory
57-
import dev.icerock.moko.permissions.compose.rememberPermissionsControllerFactory
58-
import dev.icerock.moko.permissions.notifications.REMOTE_NOTIFICATION
5951
import kotlinx.coroutines.CoroutineScope
6052
import kotlinx.coroutines.launch
6153
import ooniprobe.composeapp.generated.resources.Modal_Autorun_BatteryOptimization_Onboarding
@@ -93,6 +85,11 @@ import org.jetbrains.compose.resources.painterResource
9385
import org.jetbrains.compose.resources.stringResource
9486
import org.ooni.probe.config.OrganizationConfig
9587
import org.ooni.probe.ui.shared.MarkdownViewer
88+
import org.ooni.probe.ui.shared.Permission
89+
import org.ooni.probe.ui.shared.PermissionDeniedAlwaysException
90+
import org.ooni.probe.ui.shared.PermissionDeniedException
91+
import org.ooni.probe.ui.shared.PermissionRequestCanceledException
92+
import org.ooni.probe.ui.shared.buildPermissionsController
9693
import org.ooni.probe.ui.shared.isHeightCompact
9794
import org.ooni.probe.ui.theme.LocalCustomColors
9895

@@ -292,7 +289,10 @@ fun ColumnScope.AutomatedTestingStep(
292289
Text(stringResource(Res.string.Modal_Cancel))
293290
}
294291
},
295-
properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false),
292+
properties = DialogProperties(
293+
dismissOnClickOutside = false,
294+
dismissOnBackPress = false,
295+
),
296296
)
297297
}
298298
}
@@ -332,9 +332,7 @@ fun ColumnScope.CrashReportingStep(onEvent: (OnboardingViewModel.Event) -> Unit)
332332

333333
@Composable
334334
fun ColumnScope.RequestPermissionStep(onEvent: (OnboardingViewModel.Event) -> Unit) {
335-
val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory()
336-
val controller = remember(factory) { factory.createPermissionsController() }
337-
BindEffect(controller)
335+
val permissionsController = buildPermissionsController()
338336
val coroutineScope: CoroutineScope = rememberCoroutineScope()
339337

340338
OnboardingImage(OrganizationConfig.onboardingImages.image3)
@@ -363,15 +361,15 @@ fun ColumnScope.RequestPermissionStep(onEvent: (OnboardingViewModel.Event) -> Un
363361
onClick = {
364362
coroutineScope.launch {
365363
try {
366-
controller.providePermission(Permission.REMOTE_NOTIFICATION)
364+
permissionsController.providePermission(Permission.RemoteNotification)
367365
onEvent(OnboardingViewModel.Event.RequestNotificationsPermissionClicked)
368-
} catch (e: DeniedException) {
366+
} catch (e: PermissionDeniedException) {
369367
Logger.i("Permission denied")
370368
onEvent(OnboardingViewModel.Event.NextClicked)
371-
} catch (e: DeniedAlwaysException) {
369+
} catch (e: PermissionDeniedAlwaysException) {
372370
Logger.i("Permission already denied")
373371
onEvent(OnboardingViewModel.Event.NextClicked)
374-
} catch (e: RequestCanceledException) {
372+
} catch (e: PermissionRequestCanceledException) {
375373
Logger.i("Permission request cancelled")
376374
// Nothing to do here
377375
} catch (e: Exception) {

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/settings/about/AboutViewModel.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import kotlinx.coroutines.flow.launchIn
88
import kotlinx.coroutines.flow.onEach
99
import org.ooni.probe.config.OrganizationConfig
1010
import org.ooni.probe.shared.PlatformInfo
11-
import org.ooni.probe.shared.value
1211

1312
class AboutViewModel(
1413
onBack: () -> Unit,
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.ooni.probe.ui.shared
2+
3+
import androidx.compose.runtime.Composable
4+
5+
interface PermissionsController {
6+
@Throws(Exception::class)
7+
suspend fun providePermission(permission: Permission)
8+
}
9+
10+
@Composable
11+
expect fun buildPermissionsController(): PermissionsController
12+
13+
enum class Permission {
14+
RemoteNotification,
15+
}
16+
17+
abstract class PermissionException : Exception()
18+
19+
class PermissionDeniedException : PermissionException()
20+
21+
class PermissionDeniedAlwaysException : PermissionException()
22+
23+
class PermissionRequestCanceledException : PermissionException()

composeApp/src/commonTest/kotlin/org/ooni/engine/EngineTest.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ class EngineTest {
7272
taskEventMapper = TaskEventMapper(networkTypeFinder, json),
7373
networkTypeFinder = networkTypeFinder,
7474
isBatteryCharging = { true },
75-
platformInfo = object : PlatformInfo {
76-
override val buildName: String = "1"
77-
override val buildNumber: String = "1"
78-
override val platform = Platform.Ios
79-
override val osVersion = "1"
80-
override val model = "test"
81-
override val needsToRequestNotificationsPermission = false
82-
override val sentryDsn = ""
83-
},
75+
platformInfo = PlatformInfo(
76+
buildName = "1",
77+
buildNumber = "1",
78+
platform = Platform.Ios,
79+
osVersion = "1",
80+
model = "test",
81+
needsToRequestNotificationsPermission = false,
82+
sentryDsn = "",
83+
),
8484
getEnginePreferences = {
8585
EnginePreferences(
8686
enabledWebCategories = emptyList(),

0 commit comments

Comments
 (0)