Skip to content

Commit

Permalink
Merge pull request #229 from terrakok/dev
Browse files Browse the repository at this point in the history
Introduce more services instead of usecases
  • Loading branch information
Hiebeler authored Feb 27, 2025
2 parents 0dc9f62 + c1a178a commit 7228c80
Show file tree
Hide file tree
Showing 109 changed files with 671 additions and 1,800 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ kotlin {

//shared preferences
implementation(libs.multiplatform.settings)
implementation(libs.multiplatform.settings.coroutines)
implementation(libs.multiplatform.settings.datastore)

//file picker
implementation(libs.filekit.compose)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package com.daniebeler.pfpixelix.domain.service.platform

import android.content.ComponentName
import android.content.ContentResolver
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.provider.OpenableColumns
import android.util.DisplayMetrics
import android.webkit.MimeTypeMap
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap
import co.touchlab.kermit.Logger
import coil3.SingletonImageLoader
import coil3.request.ImageRequest
import coil3.toBitmap
import coil3.video.videoFrameMillis
import com.daniebeler.pfpixelix.R
import com.daniebeler.pfpixelix.ui.composables.settings.icon_selection.IconWithName
import com.daniebeler.pfpixelix.utils.KmpContext
import com.daniebeler.pfpixelix.utils.KmpUri
import kotlinx.coroutines.Dispatchers
Expand All @@ -26,6 +35,10 @@ actual class Platform actual constructor(
val f = AndroidFile(uri, context)
return if (f.getName() != "AndroidFile:unknown") f else null
}

actual fun getAppIconManager(): AppIconManager {
return AndroidAppIconManager(context)
}
}

private class AndroidFile(
Expand Down Expand Up @@ -91,4 +104,62 @@ private class AndroidFile(
bm.compress(Bitmap.CompressFormat.PNG, 100, stream)
stream.toByteArray()
}
}

private class AndroidAppIconManager(
private val context: Context
) : AppIconManager {
private val appIcons = listOf(
"com.daniebeler.pfpixelix.MainActivity" to R.mipmap.ic_launcher_02,
"com.daniebeler.pfpixelix.Icon03" to R.mipmap.ic_launcher_03,
"com.daniebeler.pfpixelix.Icon01" to R.mipmap.ic_launcher_01,
"com.daniebeler.pfpixelix.Icon05" to R.mipmap.ic_launcher_05,
"com.daniebeler.pfpixelix.Icon06" to R.mipmap.ic_launcher_06,
"com.daniebeler.pfpixelix.Icon07" to R.mipmap.ic_launcher_07,
"com.daniebeler.pfpixelix.Icon08" to R.mipmap.ic_launcher_08,
"com.daniebeler.pfpixelix.Icon09" to R.mipmap.ic_launcher_09,
"com.daniebeler.pfpixelix.Icon04" to R.mipmap.ic_launcher,
)

override fun getIcons(): List<IconWithName> {
fun icon(name: String, id: Int): IconWithName {
val bm = ResourcesCompat.getDrawableForDensity(
context.resources, id, DisplayMetrics.DENSITY_XXXHIGH, context.theme
)!!.let { drawable ->
drawable.toBitmap(drawable.minimumWidth, drawable.minimumHeight).asImageBitmap()
}
val isEnabled = context.packageManager.getComponentEnabledSetting(
ComponentName(context, name)
) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
return IconWithName(name, bm, isEnabled)
}

return appIcons.map { (name, id) -> icon(name, id) }
}

override fun getCurrentIcon(): ImageBitmap? {
return getIcons().firstOrNull { it.enabled }?.icon
}

override fun enableCustomIcon(iconWithName: IconWithName) {
try {
context.packageManager.setComponentEnabledSetting(
ComponentName(context, iconWithName.name),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
} catch (e: Error) {
Logger.e("enableCustomIcon", e)
}
}

override fun disableCustomIcon() {
appIcons.forEach { (name, id) ->
context.packageManager.setComponentEnabledSetting(
ComponentName(context, name),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package com.daniebeler.pfpixelix.domain.service.platform
actual object PlatformFeatures {
actual val notificationWidgets = true
actual val customAppIcon = true
actual val inAppBrowser = true
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
package com.daniebeler.pfpixelix.domain.usecase

import com.daniebeler.pfpixelix.domain.repository.StorageRepository
import com.daniebeler.pfpixelix.domain.service.preferences.UserPreferences
import com.daniebeler.pfpixelix.utils.KmpContext
import com.daniebeler.pfpixelix.utils.Navigate
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import me.tatarka.inject.annotations.Inject

@Inject
actual class OpenExternalUrlUseCase actual constructor(
private val repository: StorageRepository
private val prefs: UserPreferences
) {
actual operator fun invoke(url: String, context: KmpContext) {
CoroutineScope(Dispatchers.Default).launch {
val useInAppBrowser = repository.getUseInAppBrowser().first()
if (useInAppBrowser) {
if (prefs.useInAppBrowser) {
Navigate.openUrlInApp(context, url)
} else {
Navigate.openUrlInBrowser(context, url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,16 @@ import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.util.DisplayMetrics
import androidx.appcompat.app.AppCompatDelegate
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.ui.graphics.asImageBitmap
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.net.toUri
import co.touchlab.kermit.Logger
import coil3.PlatformContext
import com.daniebeler.pfpixelix.R
import com.daniebeler.pfpixelix.domain.model.AppThemeMode.AMOLED
import com.daniebeler.pfpixelix.domain.model.AppThemeMode.DARK
import com.daniebeler.pfpixelix.domain.model.AppThemeMode.LIGHT
import com.daniebeler.pfpixelix.ui.composables.settings.icon_selection.IconWithName
import com.daniebeler.pfpixelix.widget.notifications.NotificationWidgetReceiver
import com.russhwolf.settings.Settings
import com.russhwolf.settings.SharedPreferencesSettings
Expand All @@ -40,14 +33,6 @@ actual val KmpContext.dataStoreDir: Path
get() = File(applicationContext.filesDir, "datastore").path.toPath()
actual val KmpContext.imageCacheDir: Path get() = cacheDir.path.toPath().resolve("image_cache")

actual val KmpContext.pref: Settings
get() = SharedPreferencesSettings(
applicationContext.getSharedPreferences(
applicationContext.packageName + "_preferences",
Context.MODE_PRIVATE
)
)

actual val KmpContext.coilContext: PlatformContext get() = this

actual fun KmpContext.openUrlInApp(url: String) {
Expand Down Expand Up @@ -86,56 +71,6 @@ actual fun KmpContext.cleanCache() {
cacheDir.deleteRecursively()
}

private val appIcons = listOf(
"com.daniebeler.pfpixelix.MainActivity" to R.mipmap.ic_launcher_02,
"com.daniebeler.pfpixelix.Icon03" to R.mipmap.ic_launcher_03,
"com.daniebeler.pfpixelix.Icon01" to R.mipmap.ic_launcher_01,
"com.daniebeler.pfpixelix.Icon05" to R.mipmap.ic_launcher_05,
"com.daniebeler.pfpixelix.Icon06" to R.mipmap.ic_launcher_06,
"com.daniebeler.pfpixelix.Icon07" to R.mipmap.ic_launcher_07,
"com.daniebeler.pfpixelix.Icon08" to R.mipmap.ic_launcher_08,
"com.daniebeler.pfpixelix.Icon09" to R.mipmap.ic_launcher_09,
"com.daniebeler.pfpixelix.Icon04" to R.mipmap.ic_launcher,
)

actual fun KmpContext.getAppIcons(): List<IconWithName> {
fun icon(name: String, id: Int): IconWithName {
val bm = ResourcesCompat.getDrawableForDensity(
resources, id, DisplayMetrics.DENSITY_XXXHIGH, theme
)!!.let { drawable ->
drawable.toBitmap(drawable.minimumWidth, drawable.minimumHeight).asImageBitmap()
}
val isEnabled = packageManager.getComponentEnabledSetting(
ComponentName(this, name)
) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
return IconWithName(name, bm, isEnabled)
}

return appIcons.map { (name, id) -> icon(name, id) }
}

actual fun KmpContext.enableCustomIcon(iconWithName: IconWithName) {
try {
packageManager.setComponentEnabledSetting(
ComponentName(this, iconWithName.name),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
} catch (e: Error) {
Logger.e("enableCustomIcon", e)
}
}

actual fun KmpContext.disableCustomIcon() {
appIcons.forEach { (name, id) ->
packageManager.setComponentEnabledSetting(
ComponentName(this, name),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
)
}
}

actual fun KmpContext.pinWidget() {
val appWidgetManager = AppWidgetManager.getInstance(this)
val myProvider = ComponentName(this, NotificationWidgetReceiver::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ import coil3.imageLoader
import coil3.request.ErrorResult
import coil3.request.ImageRequest
import com.daniebeler.pfpixelix.common.Resource
import com.daniebeler.pfpixelix.domain.repository.WidgetRepository
import com.daniebeler.pfpixelix.domain.service.session.AuthService
import com.daniebeler.pfpixelix.domain.service.widget.WidgetService
import com.daniebeler.pfpixelix.utils.KmpContext
import com.daniebeler.pfpixelix.widget.latest_image.updateLatestImageWidget
import com.daniebeler.pfpixelix.widget.latest_image.updateLatestImageWidgetRefreshing
import com.daniebeler.pfpixelix.widget.notifications.updateNotificationsWidget
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.last
import me.tatarka.inject.annotations.Inject

class LatestImageTask @Inject constructor(
private val context: KmpContext,
workerParams: WorkerParameters,
private val authService: AuthService,
private val repository: WidgetRepository,
private val widgetService: WidgetService,
) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
try {
Expand All @@ -34,7 +35,7 @@ class LatestImageTask @Inject constructor(
updateNotificationsWidget(emptyList(), context, "you have to be logged in to an account")
return Result.failure()
}
val res = repository.getLatestImage()
val res = widgetService.getLatestImage().last()
if (res is Resource.Success && res.data != null) {

val imageUri = getImageUri(res.data.mediaAttachments.first().previewUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ import coil3.imageLoader
import coil3.request.ErrorResult
import coil3.request.ImageRequest
import com.daniebeler.pfpixelix.common.Resource
import com.daniebeler.pfpixelix.domain.repository.WidgetRepository
import com.daniebeler.pfpixelix.domain.service.session.AuthService
import com.daniebeler.pfpixelix.domain.service.widget.WidgetService
import com.daniebeler.pfpixelix.utils.KmpContext
import com.daniebeler.pfpixelix.widget.notifications.models.NotificationStoreItem
import com.daniebeler.pfpixelix.widget.notifications.updateNotificationsWidget
import com.daniebeler.pfpixelix.widget.notifications.updateNotificationsWidgetRefreshing
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.last
import me.tatarka.inject.annotations.Inject

class NotificationsTask @Inject constructor(
private val context: KmpContext,
workerParams: WorkerParameters,
private val authService: AuthService,
private val repository: WidgetRepository,
private val widgetService: WidgetService,
) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
try {
Expand All @@ -34,7 +35,7 @@ class NotificationsTask @Inject constructor(
updateNotificationsWidget(emptyList(), context, "you have to be logged in to an account")
return Result.failure()
}
val res = repository.getNotifications()
val res = widgetService.getNotifications().last()
if (res is Resource.Success && res.data != null) {
val notifications = res.data.take(10)
val notificationStoreItems = notifications.map { notification ->
Expand Down
Loading

0 comments on commit 7228c80

Please sign in to comment.