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

(cherry picked from commit 12e41b6e6f3b5d95d19e1caa6c9fbe5eb6c9749c)
This commit is contained in:
Andreas 2023-01-26 23:53:24 +01:00 committed by Jobobby04
parent f2944c1fa3
commit d8a938374a
38 changed files with 154 additions and 35 deletions

View File

@ -141,6 +141,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))
@ -179,7 +181,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

@ -194,7 +194,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

@ -14,7 +14,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
@ -50,7 +49,6 @@ import eu.kanade.tachiyomi.data.coil.PagePreviewFetcher
import eu.kanade.tachiyomi.data.coil.PagePreviewKeyer import eu.kanade.tachiyomi.data.coil.PagePreviewKeyer
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
@ -66,14 +64,12 @@ import exh.log.XLogLogcatLogger
import exh.log.xLogD import exh.log.xLogD
import exh.syDebugVersion import exh.syDebugVersion
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.LogPriority import logcat.LogPriority
import logcat.LogcatLogger import logcat.LogcatLogger
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
@ -154,17 +150,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

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