Move Glance Widget to seperate module (#8989)

Move Widget to seperate module

- Create a core module for presentation. Widget and App will share some resources and hopefully composables
This commit is contained in:
Andreas 2023-01-26 23:53:24 +01:00 committed by GitHub
parent c892c793a8
commit 12e41b6e6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 154 additions and 35 deletions

View File

@ -143,6 +143,8 @@ dependencies {
implementation(project(":source-api")) implementation(project(":source-api"))
implementation(project(":data")) implementation(project(":data"))
implementation(project(":domain")) implementation(project(":domain"))
implementation(project(":presentation-core"))
implementation(project(":presentation-widget"))
// Compose // Compose
implementation(platform(compose.bom)) implementation(platform(compose.bom))
@ -181,7 +183,6 @@ dependencies {
implementation(androidx.splashscreen) implementation(androidx.splashscreen)
implementation(androidx.recyclerview) implementation(androidx.recyclerview)
implementation(androidx.viewpager) implementation(androidx.viewpager)
implementation(androidx.glance)
implementation(androidx.profileinstaller) implementation(androidx.profileinstaller)
implementation(androidx.bundles.lifecycle) implementation(androidx.bundles.lifecycle)

View File

@ -188,7 +188,7 @@
android:exported="false" /> android:exported="false" />
<receiver <receiver
android:name=".glance.UpdatesGridGlanceReceiver" android:name="tachiyomi.presentation.widget.UpdatesGridGlanceReceiver"
android:enabled="@bool/glance_appwidget_available" android:enabled="@bool/glance_appwidget_available"
android:exported="false" android:exported="false"
android:label="@string/label_recent_updates"> android:label="@string/label_recent_updates">

View File

@ -13,7 +13,6 @@ import android.os.Looper
import android.webkit.WebView import android.webkit.WebView
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.glance.appwidget.GlanceAppWidgetManager
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
@ -36,7 +35,6 @@ import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
import eu.kanade.tachiyomi.data.coil.MangaKeyer import eu.kanade.tachiyomi.data.coil.MangaKeyer
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.glance.UpdatesGridGlanceWidget
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
@ -47,8 +45,6 @@ import eu.kanade.tachiyomi.util.system.isReleaseBuildType
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.notification import eu.kanade.tachiyomi.util.system.notification
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import logcat.AndroidLogcatLogger import logcat.AndroidLogcatLogger
@ -58,7 +54,7 @@ import org.acra.config.httpSender
import org.acra.ktx.initAcra import org.acra.ktx.initAcra
import org.acra.sender.HttpSender import org.acra.sender.HttpSender
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
import tachiyomi.data.DatabaseHandler import tachiyomi.presentation.widget.TachiyomiWidgetManager
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -128,17 +124,9 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get()) setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get())
// Updates widget update // Updates widget update
Injekt.get<DatabaseHandler>() with(TachiyomiWidgetManager) {
.subscribeToList { updatesViewQueries.updates(after = UpdatesGridGlanceWidget.DateLimit.timeInMillis) } init(ProcessLifecycleOwner.get().lifecycleScope, Injekt.get())
.drop(1) }
.distinctUntilChanged()
.onEach {
val manager = GlanceAppWidgetManager(this)
if (manager.getGlanceIds(UpdatesGridGlanceWidget::class.java).isNotEmpty()) {
UpdatesGridGlanceWidget().loadData(it)
}
}
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) { if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) {
LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE)) LogcatLogger.install(AndroidLogcatLogger(LogPriority.VERBOSE))

View File

@ -115,12 +115,6 @@ fun Context.hasPermission(permission: String) = ContextCompat.checkSelfPermissio
val getDisplayMaxHeightInPx: Int val getDisplayMaxHeightInPx: Int
get() = Resources.getSystem().displayMetrics.let { max(it.heightPixels, it.widthPixels) } get() = Resources.getSystem().displayMetrics.let { max(it.heightPixels, it.widthPixels) }
/**
* Converts to px.
*/
val Int.dpToPx: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
/** /**
* Converts to px and takes into account LTR/RTL layout. * Converts to px and takes into account LTR/RTL layout.
*/ */

View File

@ -0,0 +1,9 @@
package eu.kanade.tachiyomi.util.system
import android.content.res.Resources
/**
* Converts to px.
*/
val Int.dpToPx: Int
get() = (this * Resources.getSystem().displayMetrics.density).toInt()

1
presentation-core/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,17 @@
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "tachiyomi.presentation.core"
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
}
dependencies {
}

View File

21
presentation-core/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

1
presentation-widget/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,33 @@
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "tachiyomi.presentation.widget"
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = compose.versions.compiler.get()
}
}
dependencies {
implementation(project(":core"))
implementation(project(":data"))
implementation(project(":domain"))
implementation(project(":presentation-core"))
implementation(androidx.glance)
implementation(libs.coil.core)
}

View File

21
presentation-widget/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

View File

@ -1,11 +1,10 @@
package eu.kanade.tachiyomi.glance package tachiyomi.presentation.widget
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.glance.GlanceModifier import androidx.glance.GlanceModifier
import androidx.glance.LocalContext import androidx.glance.LocalContext
import androidx.glance.appwidget.cornerRadius import androidx.glance.appwidget.cornerRadius
import eu.kanade.tachiyomi.R
fun GlanceModifier.appWidgetBackgroundRadius(): GlanceModifier { fun GlanceModifier.appWidgetBackgroundRadius(): GlanceModifier {
return this.cornerRadius(R.dimen.appwidget_background_radius) return this.cornerRadius(R.dimen.appwidget_background_radius)

View File

@ -0,0 +1,26 @@
package tachiyomi.presentation.widget
import android.content.Context
import androidx.glance.appwidget.GlanceAppWidgetManager
import androidx.lifecycle.LifecycleCoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import tachiyomi.data.DatabaseHandler
object TachiyomiWidgetManager {
fun Context.init(scope: LifecycleCoroutineScope, database: DatabaseHandler) {
database.subscribeToList { updatesViewQueries.updates(after = UpdatesGridGlanceWidget.DateLimit.timeInMillis) }
.drop(1)
.distinctUntilChanged()
.onEach {
val manager = GlanceAppWidgetManager(this)
if (manager.getGlanceIds(UpdatesGridGlanceWidget::class.java).isNotEmpty()) {
UpdatesGridGlanceWidget().loadData(it)
}
}
.launchIn(scope)
}
}

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.glance package tachiyomi.presentation.widget
import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver import androidx.glance.appwidget.GlanceAppWidgetReceiver

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.glance package tachiyomi.presentation.widget
import android.app.Application import android.app.Application
import android.content.Intent import android.content.Intent
@ -43,10 +43,7 @@ import coil.request.ImageRequest
import coil.size.Precision import coil.size.Precision
import coil.size.Scale import coil.size.Scale
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.Constants
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
@ -81,7 +78,8 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
@Composable @Composable
private fun WidgetNotAvailable() { private fun WidgetNotAvailable() {
val intent = Intent(LocalContext.current, MainActivity::class.java).apply { val clazz = Class.forName("eu.kanade.tachiyomi.ui.main.MainActivity")
val intent = Intent(LocalContext.current, clazz).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} }
Box( Box(
@ -134,9 +132,9 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
.padding(horizontal = 3.dp), .padding(horizontal = 3.dp),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
val intent = Intent(LocalContext.current, MainActivity::class.java).apply { val intent = Intent(LocalContext.current, Class.forName("eu.kanade.tachiyomi.ui.main.MainActivity")).apply {
action = MainActivity.SHORTCUT_MANGA action = "eu.kanade.tachiyomi.SHOW_MANGA"
putExtra(Constants.MANGA_EXTRA, mangaId) putExtra("manga", mangaId)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

View File

@ -0,0 +1,4 @@
<resources>
<dimen name="appwidget_background_radius">16dp</dimen>
<dimen name="appwidget_inner_radius">12dp</dimen>
</resources>

View File

@ -43,3 +43,5 @@ include(":core")
include(":macrobenchmark") include(":macrobenchmark")
include(":data") include(":data")
include(":domain") include(":domain")
include(":presentation-widget")
include(":presentation-core")