Skip to content

Commit

Permalink
Switch to Coil for image loading
Browse files Browse the repository at this point in the history
  • Loading branch information
DRSchlaubi committed Dec 9, 2023
1 parent d8de2e9 commit 28ed6b8
Show file tree
Hide file tree
Showing 26 changed files with 234 additions and 147 deletions.
20 changes: 8 additions & 12 deletions .idea/deploymentTargetDropDown.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 33 additions & 26 deletions app/android/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,53 @@
-keepclassmembers class io.ktor.** { volatile <fields>; }
-keep class io.ktor.client.engine.okhttp.OkHttpEngineContainer
-keep class io.ktor.serialization.kotlinx.json.KotlinxSerializationJsonExtensionProvider
-keep class kotlinx.coroutines.** { *; }
# even though we don't use log4j, proguard fails preverification if this class gets optimized
-keep class io.netty.util.internal.logging.Log4J2LoggerFactory { *; }
-dontwarn kotlinx.coroutines.swing.**

# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keep class kotlinx.coroutines.android.AndroidDispatcherFactory {}

# Most of volatile fields are updated with AFU and should not be mangled
-keepclassmembers class kotlinx.coroutines.** {
volatile <fields>;
}
-keepclasseswithmembers class io.netty.** {
*;
}
-keepnames class io.netty.** {
*;
}
# Same story for the standard library's SafeContinuation that also uses AtomicReferenceFieldUpdater
-keepclassmembers class kotlin.coroutines.SafeContinuation {
volatile <fields>;
}

-dontwarn kotlinx.atomicfu.**
-dontwarn io.netty.**
-dontwarn com.typesafe.**
-dontwarn org.slf4j.**
-dontwarn ch.qos.logback.**
-dontwarn okhttp3.**
-dontwarn io.ktor.**

# okhttp
# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**

# A resource is loaded with a relative path so the package of this class must be preserved.
-adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz

# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*

# OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
-dontwarn dev.schlaubi.tonbrett.app.desktop.uwp_helper.**

# kmongo
-keep class org.litote.kmongo.id.UUIDStringIdGeneratorProvider
-keepclassmembers class org.litote.kmongo.id.StringId {
public <init>(java.lang.String);
}

# logback
-keep class ch.qos.logback.classic.spi.LogbackServiceProvider
-keep class ch.qos.logback.core.rolling.RollingFileAppender
-keep class ch.qos.logback.core.rolling.TimeBasedRollingPolicy
-keep class ch.qos.logback.core.ConsoleAppender

# serialization
# For some reason if we don't do this, we get a VerifyError at runtime
-keep class kotlinx.serialization.* { *; }

# Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`.
# If you have any, replace classes with those containing named companion objects.
-keepattributes InnerClasses # Needed for `getDeclaredClasses`.
Expand All @@ -52,10 +66,3 @@
-keepclassmembers class <1>.<2> {
<1>.<2>$Companion Companion;
}

# compose
-keep class androidx.compose.ui.text.platform.Platform { *; }
-keep class androidx.compose.runtime.** { *; }

# protobuf
-keep class dev.schlaubi.tonbrett.app.android.shared.* { *; }
11 changes: 4 additions & 7 deletions app/android/src/main/java/AppActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.browser.customtabs.CustomTabsIntent
import dev.schlaubi.tonbrett.app.MobileTonbrettApp
import dev.schlaubi.tonbrett.app.ProvideImageLoader
import dev.schlaubi.tonbrett.app.api.AppContext
import dev.schlaubi.tonbrett.app.api.ProvideContext

Expand All @@ -25,12 +24,10 @@ class AppActivity : ComponentActivity() {
WearOSTokenSharing(token = token ?: context.getTokenOrNull())

ProvideContext(context) {
ProvideImageLoader {
UpdateAwareAppScope(activity = this) {
MobileTonbrettApp(token) { url ->
val intent = CustomTabsIntent.Builder().build()
intent.launchUrl(this@AppActivity, Uri.parse(url))
}
UpdateAwareAppScope(activity = this) {
MobileTonbrettApp(token) { url ->
val intent = CustomTabsIntent.Builder().build()
intent.launchUrl(this@AppActivity, Uri.parse(url))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/desktop/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ compose.desktop {
buildTypes {
release {
proguard {
version = "7.4.0"
version = "7.4.1"
configurationFiles.from(files("rules.pro"))
}
}
Expand Down
12 changes: 2 additions & 10 deletions app/desktop/rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keep class kotlinx.coroutines.swing.SwingDispatcherFactory {}

# Most of volatile fields are updated with AFU and should not be mangled
-keepclassmembers class kotlinx.coroutines.** {
Expand Down Expand Up @@ -65,14 +66,5 @@
<1>.<2>$Companion Companion;
}


-keep class dev.schlaubi.tonbrett.common.** {*;}
-keep class dev.schlaubi.tonbrett.app.desktop.** {*;}
-keep class kotlinx.serialization.* { *; }

# compose
-keep class androidx.compose.ui.text.platform.Platform { *; }
-keep class androidx.compose.runtime.** { *; }

# https://github.com/Guardsquare/proguard/issues/349
-optimizations !class/unboxing/enum
-dontoptimize
4 changes: 1 addition & 3 deletions app/desktop/src/commonMain/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ private fun ApplicationScope.startActualApplication(
} else {
context.resetApi()
ProvideContext(context) {
ProvideImageLoader {
TonbrettApp(sessionExpired)
}
TonbrettApp(sessionExpired)
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions app/desktop/src/windowsMain/kotlin/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dev.schlaubi.tonbrett.app.desktop

import dev.schlaubi.tonbrett.app.desktop.uwp_helper.StringResult
import dev.schlaubi.tonbrett.app.desktop.uwp_helper.UwpHelper.*
import dev.schlaubi.tonbrett.app.uwpTempFolder
import dev.schlaubi.tonbrett.common.Route
import io.ktor.http.*
import kotlinx.coroutines.DelicateCoroutinesApi
Expand All @@ -23,6 +24,9 @@ actual fun prepareAuthentication(onAuth: () -> Unit): Unit = exitProcess(0)

@OptIn(DelicateCoroutinesApi::class)
actual fun start(args: Array<String>) {
val tempFolder = getTempFolder()
System.setProperty(uwpTempFolder, tempFolder)

val argsString = args.joinToString(" ")
if (argsString.startsWith("tonbrett://login")) {
try {
Expand Down Expand Up @@ -53,6 +57,8 @@ actual fun setToken(token: String) = Arena.ofConfined().use { arena ->

actual fun getToken(): String = invokeStringResultFunction(::get_token)

private fun getTempFolder(): String = invokeStringResultFunction(::get_temp_folder)

private fun invokeStringResultFunction(
function: (SegmentAllocator) -> MemorySegment
) =
Expand Down
5 changes: 3 additions & 2 deletions app/desktop/uwp_helper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ crate-type = ["cdylib"]

[dependencies.windows]
version = "0.51.1"
features = ["System", "Foundation", "Win32_Foundation", "Security_Credentials", "Services_Store", "Foundation_Collections"]
features = ["System", "Foundation", "Win32_Foundation", "Security_Credentials", "Services_Store", "Foundation_Collections", "Storage"]

[dependencies.tokio]
version = "1.32.0"
Expand All @@ -18,5 +18,6 @@ features = ["macros", "rt-multi-thread"]
[build-dependencies.cbindgen]
version = "0.26.0"
default-features = false

[dependencies]
log = "0.4.20"
log = "0.4.20"
1 change: 1 addition & 0 deletions app/desktop/uwp_helper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ tasks {
"--include-function", "launch_uri",
"--include-function", "get_token",
"--include-function", "store_token",
"--include-function", "get_temp_folder",
"--include-function", "copy_string_from_get_string_result_into_buffer",
"--include-function", "request_msstore_auto_update",
"--include-struct", "StringResult",
Expand Down
65 changes: 40 additions & 25 deletions app/desktop/uwp_helper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::ffi::{c_char, CStr};

use windows::Services::Store::StoreContext;
use windows::Storage::ApplicationData;
use windows::{
core::h,
core::Result,
Expand All @@ -27,20 +28,6 @@ pub async extern "C" fn request_msstore_auto_update() -> bool {
};
}

async fn _request_msstore_auto_update() -> Result<()> {
let context = StoreContext::GetDefault()?;
let updates = context.GetAppAndOptionalStorePackageUpdatesAsync()?.await?;

if updates.Size()? > 0 {
context
.RequestDownloadAndInstallStorePackageUpdatesAsync(&updates)?
.await
.map(|_| ())
} else {
Ok(())
}
}

#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn launch_uri(uri: *const c_char) {
Expand All @@ -63,17 +50,7 @@ pub unsafe extern "C" fn store_token(token: *const c_char) {

#[no_mangle]
pub extern "C" fn get_token() -> StringResult {
let result = _get_token();
let (string, is_error) = match result {
Ok(password) => (password, false),
Err(error) => (error.message(), true),
};

StringResult {
is_error,
length: string.len(),
string,
}
StringResult::from(_get_token())
}

#[no_mangle]
Expand All @@ -84,6 +61,11 @@ pub unsafe extern "C" fn copy_string_from_get_string_result_into_buffer(
buffer.copy_from(result.string.as_ptr(), result.length)
}

#[no_mangle]
pub unsafe extern "C" fn get_temp_folder() -> StringResult {
StringResult::from(_get_temp_folder())
}

async fn _launch_uri(uri: &str) -> Result<()> {
let actual_uri = Uri::CreateUri(&HSTRING::from(uri))?;

Expand All @@ -107,3 +89,36 @@ fn _get_token() -> Result<HSTRING> {

Ok(password)
}

fn _get_temp_folder() -> Result<HSTRING> {
ApplicationData::Current()?.TemporaryFolder()?.Path()
}

async fn _request_msstore_auto_update() -> Result<()> {
let context = StoreContext::GetDefault()?;
let updates = context.GetAppAndOptionalStorePackageUpdatesAsync()?.await?;

if updates.Size()? > 0 {
context
.RequestDownloadAndInstallStorePackageUpdatesAsync(&updates)?
.await
.map(|_| ())
} else {
Ok(())
}
}

impl From<Result<HSTRING>> for StringResult {
fn from(value: Result<HSTRING>) -> Self {
let (string, is_error) = match value {
Ok(password) => (password, false),
Err(error) => (error.message(), true),
};

StringResult {
is_error,
length: string.len(),
string,
}
}
}
10 changes: 8 additions & 2 deletions app/shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,24 @@ kotlin {
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
implementation(libs.imageloader)

implementation(libs.coil.compose)
implementation(libs.coil.gif)
implementation(libs.coil.svg)
implementation(libs.coil.network)
}
}

jsMain {
dependencies {
api("org.jetbrains.kotlin:kotlinx-atomicfu-runtime:1.9.10")
api("org.jetbrains.kotlin:kotlinx-atomicfu-runtime:1.9.21")
}
}

jvmMain {
dependencies {
implementation(libs.kmongo.id.serialization)
implementation(libs.kotlinx.coroutines.swing)
}
}

Expand All @@ -84,6 +89,7 @@ kotlin {
androidMain {
dependencies {
implementation(libs.androidx.browser)
implementation(libs.kotlinx.coroutines.android)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

package dev.schlaubi.tonbrett.app

import com.seiko.imageloader.component.ComponentRegistryBuilder
import com.seiko.imageloader.component.decoder.BitmapFactoryDecoder
import com.seiko.imageloader.component.decoder.GifDecoder
import dev.schlaubi.tonbrett.app.api.AppContext
import kotlinx.coroutines.CoroutineScope
import android.os.Build
import coil3.ComponentRegistry
import coil3.decode.GifDecoder
import coil3.decode.ImageDecoderDecoder
import coil3.decode.SvgDecoder

internal actual fun ComponentRegistryBuilder.registerComponents(
appContext: AppContext,
coroutineScope: CoroutineScope
) {
add(GifDecoder.Factory())
add(BitmapFactoryDecoder.Factory(appContext.currentActivity, Int.MAX_VALUE))
internal actual fun ComponentRegistry.Builder.addPlatformComponents() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
add(ImageDecoderDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
add(SvgDecoder.Factory())
}
Loading

0 comments on commit 28ed6b8

Please sign in to comment.