Skip to content

Commit

Permalink
feat(coil): enable very early support for animated emotes on iOS (#453)
Browse files Browse the repository at this point in the history
  • Loading branch information
outadoc authored Oct 4, 2024
1 parent c9fdf54 commit c48c57b
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
package fr.outadoc.justchatting

import android.app.Application
import android.os.Build
import coil3.ImageLoader
import coil3.PlatformContext
import coil3.SingletonImageLoader
import coil3.disk.DiskCache
import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import coil3.memory.MemoryCache
import coil3.request.crossfade
import coil3.request.transitionFactory
import coil3.transition.Transition
import coil3.util.DebugLogger
import com.google.android.material.color.DynamicColors
import fr.outadoc.justchatting.utils.logging.AndroidLogStrategy
import fr.outadoc.justchatting.utils.logging.Logger
import okio.Path.Companion.toOkioPath

class MainApplication :
Application(),
SingletonImageLoader.Factory {
class MainApplication : Application() {

override fun onCreate() {
super.onCreate()
Expand All @@ -31,33 +16,4 @@ class MainApplication :

DynamicColors.applyToActivitiesIfAvailable(this)
}

override fun newImageLoader(context: PlatformContext): ImageLoader =
ImageLoader.Builder(context)
.crossfade(true)
.memoryCache {
MemoryCache.Builder()
.maxSizePercent(applicationContext, percent = 0.25)
.build()
}
.diskCache {
DiskCache.Builder()
.directory(applicationContext.cacheDir.toOkioPath().resolve("image_cache"))
.maxSizePercent(0.02)
.build()
}
.transitionFactory(Transition.Factory.NONE)
.components {
if (Build.VERSION.SDK_INT >= 28) {
add(AnimatedImageDecoder.Factory(enforceMinimumFrameDelay = true))
} else {
add(GifDecoder.Factory())
}
}
.apply {
if (BuildConfig.ENABLE_LOGGING) {
logger(DebugLogger())
}
}
.build()
}
1 change: 1 addition & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ kotlin {
implementation(libs.androidx.palette)
implementation(libs.androidx.paging.runtime.android)
implementation(libs.androidx.splashscreen)
implementation(libs.coil.gif)
implementation(libs.koin.android)
implementation(libs.ktor.client.okhttp)
implementation(libs.material.core)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package fr.outadoc.justchatting.utils.coil

import android.os.Build
import coil3.ImageLoader
import coil3.PlatformContext
import coil3.SingletonImageLoader
import coil3.disk.DiskCache
import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import coil3.memory.MemoryCache
import coil3.request.crossfade
import okio.Path.Companion.toOkioPath

internal actual object ImageLoaderFactory : SingletonImageLoader.Factory {

override fun newImageLoader(context: PlatformContext): ImageLoader {
return ImageLoader.Builder(context)
.crossfade(true)
.memoryCache {
MemoryCache.Builder()
.maxSizePercent(context, percent = 0.25)
.build()
}
.diskCache {
DiskCache.Builder()
.directory(context.cacheDir.toOkioPath().resolve("image_cache"))
.maxSizePercent(0.02)
.build()
}
.components {
if (Build.VERSION.SDK_INT >= 28) {
add(AnimatedImageDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
}
.logger(CoilCustomLogger())
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.navigation.compose.rememberNavController
import coil3.SingletonImageLoader
import com.eygraber.uri.Uri
import fr.outadoc.justchatting.feature.onboarding.presentation.mobile.OnboardingScreen
import fr.outadoc.justchatting.feature.shared.presentation.MainRouterViewModel
import fr.outadoc.justchatting.utils.coil.ImageLoaderFactory
import fr.outadoc.justchatting.utils.presentation.AppTheme
import fr.outadoc.justchatting.utils.presentation.OnLifecycleEvent
import org.koin.compose.koinInject
Expand All @@ -37,6 +39,11 @@ internal fun App(
val navController = rememberNavController()
val navigator = rememberListDetailPaneScaffoldNavigator<DetailScreen>()

LaunchedEffect(Unit) {
// Initialize Coil
SingletonImageLoader.setSafe(ImageLoaderFactory)
}

val onChannelClick = { userId: String ->
navigator.navigateTo(
pane = ListDetailPaneScaffoldRole.Detail,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package fr.outadoc.justchatting.utils.coil

import fr.outadoc.justchatting.utils.logging.Logger

internal class CoilCustomLogger(
override var minLevel: coil3.util.Logger.Level = coil3.util.Logger.Level.Debug,
) : coil3.util.Logger {

override fun log(
tag: String,
level: coil3.util.Logger.Level,
message: String?,
throwable: Throwable?,
) {
Logger.println(
level = when (level) {
coil3.util.Logger.Level.Error -> Logger.Level.Error
coil3.util.Logger.Level.Warn -> Logger.Level.Warning
coil3.util.Logger.Level.Info -> Logger.Level.Info
coil3.util.Logger.Level.Debug -> Logger.Level.Debug
coil3.util.Logger.Level.Verbose -> Logger.Level.Verbose
},
tag = tag,
content = {
buildString {
if (message != null) {
appendLine(message)
}

if (throwable != null) {
appendLine(throwable.stackTraceToString())
}
}
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package fr.outadoc.justchatting.utils.coil

import coil3.SingletonImageLoader

internal expect object ImageLoaderFactory : SingletonImageLoader.Factory
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import platform.Foundation.NSDocumentDirectory
import platform.Foundation.NSFileManager
import platform.Foundation.NSUserDomainMask

@OptIn(ExperimentalForeignApi::class)
internal actual val platformModule: Module
get() = module {
single {
Expand All @@ -49,25 +50,10 @@ internal actual val platformModule: Module
)
}

@OptIn(ExperimentalForeignApi::class)
single<DataStore<Preferences>> {
PreferenceDataStoreFactory.createWithPath(
produceFile = {
val documentDirectory: Path =
NSFileManager.defaultManager
.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = null,
)
?.path
?.toPath()
?: error("Could not get document directory")

documentDirectory
.resolve("fr.outadoc.justchatting.preferences_pb")
getDocumentsDirectory().resolve("fr.outadoc.justchatting.preferences_pb")
},
)
}
Expand All @@ -79,3 +65,18 @@ internal actual val platformModule: Module
single<AppVersionNameProvider> { AppleAppVersionNameProvider() }
single<ReadExternalDependenciesList> { AppleReadExternalDependenciesList() }
}

@OptIn(ExperimentalForeignApi::class)
private fun getDocumentsDirectory(): Path {
return NSFileManager.defaultManager
.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = null,
)
?.path
?.toPath()
?: error("Could not get document directory")
}
Loading

0 comments on commit c48c57b

Please sign in to comment.