Split UpdatesGridGlanceWidget into smaller bits (#8991)

- Renamed Composables
- Moved Constants to core module
This commit is contained in:
Andreas 2023-01-27 20:49:57 +01:00 committed by GitHub
parent 12e41b6e6f
commit 2501fef9e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 267 additions and 219 deletions

View File

@ -32,7 +32,7 @@ import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.more.DownloadQueueState import eu.kanade.tachiyomi.ui.more.DownloadQueueState
import eu.kanade.tachiyomi.util.Constants import tachiyomi.core.Constants
@Composable @Composable
fun MoreScreen( fun MoreScreen(

View File

@ -124,8 +124,8 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get()) setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get())
// Updates widget update // Updates widget update
with(TachiyomiWidgetManager) { with(TachiyomiWidgetManager(Injekt.get())) {
init(ProcessLifecycleOwner.get().lifecycleScope, Injekt.get()) init(ProcessLifecycleOwner.get().lifecycleScope)
} }
if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) { if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) {

View File

@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.system.notification import eu.kanade.tachiyomi.util.system.notification
import eu.kanade.tachiyomi.util.system.notificationBuilder import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import tachiyomi.core.Constants
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -333,7 +334,7 @@ class LibraryUpdateNotifier(private val context: Context) {
private fun getNotificationIntent(): PendingIntent { private fun getNotificationIntent(): PendingIntent {
val intent = Intent(context, MainActivity::class.java).apply { val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = MainActivity.SHORTCUT_UPDATES action = Constants.SHORTCUT_UPDATES
} }
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
} }

View File

@ -7,6 +7,7 @@ import android.net.Uri
import androidx.core.net.toUri import androidx.core.net.toUri
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import tachiyomi.core.Constants
/** /**
* Class that manages [PendingIntent] of activity's * Class that manages [PendingIntent] of activity's
@ -20,7 +21,7 @@ object NotificationHandler {
internal fun openDownloadManagerPendingActivity(context: Context): PendingIntent { internal fun openDownloadManagerPendingActivity(context: Context): PendingIntent {
val intent = Intent(context, MainActivity::class.java).apply { val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = MainActivity.SHORTCUT_DOWNLOADS action = Constants.SHORTCUT_DOWNLOADS
} }
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
} }

View File

@ -21,7 +21,6 @@ import eu.kanade.tachiyomi.data.updater.AppUpdateService
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
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.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
@ -30,6 +29,7 @@ import eu.kanade.tachiyomi.util.system.notificationManager
import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toShareIntent
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import tachiyomi.core.Constants
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.chapter.model.toChapterUpdate import tachiyomi.domain.chapter.model.toChapterUpdate
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
@ -455,7 +455,7 @@ class NotificationReceiver : BroadcastReceiver() {
*/ */
internal fun openChapterPendingActivity(context: Context, manga: Manga, groupId: Int): PendingIntent { internal fun openChapterPendingActivity(context: Context, manga: Manga, groupId: Int): PendingIntent {
val newIntent = val newIntent =
Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_MANGA) Intent(context, MainActivity::class.java).setAction(Constants.SHORTCUT_MANGA)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(Constants.MANGA_EXTRA, manga.id) .putExtra(Constants.MANGA_EXTRA, manga.id)
.putExtra("notificationId", manga.id.hashCode()) .putExtra("notificationId", manga.id.hashCode())
@ -538,7 +538,7 @@ class NotificationReceiver : BroadcastReceiver() {
*/ */
internal fun openExtensionsPendingActivity(context: Context): PendingIntent { internal fun openExtensionsPendingActivity(context: Context): PendingIntent {
val intent = Intent(context, MainActivity::class.java).apply { val intent = Intent(context, MainActivity::class.java).apply {
action = MainActivity.SHORTCUT_EXTENSIONS action = Constants.SHORTCUT_EXTENSIONS
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
} }
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)

View File

@ -33,8 +33,8 @@ import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
import eu.kanade.tachiyomi.ui.home.HomeScreen import eu.kanade.tachiyomi.ui.home.HomeScreen
import eu.kanade.tachiyomi.ui.manga.MangaScreen import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.ui.webview.WebViewScreen import eu.kanade.tachiyomi.ui.webview.WebViewScreen
import eu.kanade.tachiyomi.util.Constants
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import tachiyomi.core.Constants
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
data class SourceSearchScreen( data class SourceSearchScreen(

View File

@ -54,11 +54,11 @@ import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listi
import eu.kanade.tachiyomi.ui.category.CategoryScreen import eu.kanade.tachiyomi.ui.category.CategoryScreen
import eu.kanade.tachiyomi.ui.manga.MangaScreen import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.ui.webview.WebViewScreen import eu.kanade.tachiyomi.ui.webview.WebViewScreen
import eu.kanade.tachiyomi.util.Constants
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.receiveAsFlow
import tachiyomi.core.Constants
data class BrowseSourceScreen( data class BrowseSourceScreen(
private val sourceId: Long, private val sourceId: Long,

View File

@ -79,7 +79,6 @@ import eu.kanade.tachiyomi.ui.library.LibrarySettingsSheet
import eu.kanade.tachiyomi.ui.library.LibraryTab import eu.kanade.tachiyomi.ui.library.LibraryTab
import eu.kanade.tachiyomi.ui.manga.MangaScreen import eu.kanade.tachiyomi.ui.manga.MangaScreen
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
import eu.kanade.tachiyomi.util.Constants
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.isNavigationBarNeedsScrim import eu.kanade.tachiyomi.util.system.isNavigationBarNeedsScrim
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
@ -94,6 +93,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.Constants
import tachiyomi.domain.category.model.Category import tachiyomi.domain.category.model.Category
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -405,17 +405,17 @@ class MainActivity : BaseActivity() {
isHandlingShortcut = true isHandlingShortcut = true
when (intent.action) { when (intent.action) {
SHORTCUT_LIBRARY -> HomeScreen.openTab(HomeScreen.Tab.Library()) Constants.SHORTCUT_LIBRARY -> HomeScreen.openTab(HomeScreen.Tab.Library())
SHORTCUT_MANGA -> { Constants.SHORTCUT_MANGA -> {
val idToOpen = intent.extras?.getLong(Constants.MANGA_EXTRA) ?: return false val idToOpen = intent.extras?.getLong(Constants.MANGA_EXTRA) ?: return false
navigator.popUntilRoot() navigator.popUntilRoot()
HomeScreen.openTab(HomeScreen.Tab.Library(idToOpen)) HomeScreen.openTab(HomeScreen.Tab.Library(idToOpen))
} }
SHORTCUT_UPDATES -> HomeScreen.openTab(HomeScreen.Tab.Updates) Constants.SHORTCUT_UPDATES -> HomeScreen.openTab(HomeScreen.Tab.Updates)
SHORTCUT_HISTORY -> HomeScreen.openTab(HomeScreen.Tab.History) Constants.SHORTCUT_HISTORY -> HomeScreen.openTab(HomeScreen.Tab.History)
SHORTCUT_SOURCES -> HomeScreen.openTab(HomeScreen.Tab.Browse(false)) Constants.SHORTCUT_SOURCES -> HomeScreen.openTab(HomeScreen.Tab.Browse(false))
SHORTCUT_EXTENSIONS -> HomeScreen.openTab(HomeScreen.Tab.Browse(true)) Constants.SHORTCUT_EXTENSIONS -> HomeScreen.openTab(HomeScreen.Tab.Browse(true))
SHORTCUT_DOWNLOADS -> { Constants.SHORTCUT_DOWNLOADS -> {
navigator.popUntilRoot() navigator.popUntilRoot()
HomeScreen.openTab(HomeScreen.Tab.More(toDownloads = true)) HomeScreen.openTab(HomeScreen.Tab.More(toDownloads = true))
} }
@ -475,15 +475,6 @@ class MainActivity : BaseActivity() {
private const val SPLASH_MAX_DURATION = 5000 // ms private const val SPLASH_MAX_DURATION = 5000 // ms
private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms private const val SPLASH_EXIT_ANIM_DURATION = 400L // ms
// Shortcut actions
const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
const val SHORTCUT_MANGA = "eu.kanade.tachiyomi.SHOW_MANGA"
const val SHORTCUT_UPDATES = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED"
const val SHORTCUT_HISTORY = "eu.kanade.tachiyomi.SHOW_RECENTLY_READ"
const val SHORTCUT_SOURCES = "eu.kanade.tachiyomi.SHOW_CATALOGUES"
const val SHORTCUT_EXTENSIONS = "eu.kanade.tachiyomi.EXTENSIONS"
const val SHORTCUT_DOWNLOADS = "eu.kanade.tachiyomi.SHOW_DOWNLOADS"
const val INTENT_SEARCH = "eu.kanade.tachiyomi.SEARCH" const val INTENT_SEARCH = "eu.kanade.tachiyomi.SEARCH"
const val INTENT_SEARCH_QUERY = "query" const val INTENT_SEARCH_QUERY = "query"
const val INTENT_SEARCH_FILTER = "filter" const val INTENT_SEARCH_FILTER = "filter"

View File

@ -67,7 +67,6 @@ import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.ui.webview.WebViewActivity
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.lang.launchNonCancellable import eu.kanade.tachiyomi.util.lang.launchNonCancellable
import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.lang.withUIContext
@ -94,6 +93,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.Constants
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import kotlin.math.abs import kotlin.math.abs
@ -403,7 +403,7 @@ class ReaderActivity : BaseActivity() {
viewModel.manga?.id?.let { id -> viewModel.manga?.id?.let { id ->
startActivity( startActivity(
Intent(this, MainActivity::class.java).apply { Intent(this, MainActivity::class.java).apply {
action = MainActivity.SHORTCUT_MANGA action = Constants.SHORTCUT_MANGA
putExtra(Constants.MANGA_EXTRA, id) putExtra(Constants.MANGA_EXTRA, id)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}, },

View File

@ -1,7 +0,0 @@
package eu.kanade.tachiyomi.util
object Constants {
const val URL_HELP = "https://tachiyomi.org/help/"
const val MANGA_EXTRA = "manga"
}

View File

@ -0,0 +1,18 @@
package tachiyomi.core
object Constants {
const val URL_HELP = "https://tachiyomi.org/help/"
const val MANGA_EXTRA = "manga"
const val MAIN_ACTIVITY = "eu.kanade.tachiyomi.ui.main.MainActivity"
// Shortcut actions
const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
const val SHORTCUT_MANGA = "eu.kanade.tachiyomi.SHOW_MANGA"
const val SHORTCUT_UPDATES = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED"
const val SHORTCUT_HISTORY = "eu.kanade.tachiyomi.SHOW_RECENTLY_READ"
const val SHORTCUT_SOURCES = "eu.kanade.tachiyomi.SHOW_CATALOGUES"
const val SHORTCUT_EXTENSIONS = "eu.kanade.tachiyomi.EXTENSIONS"
const val SHORTCUT_DOWNLOADS = "eu.kanade.tachiyomi.SHOW_DOWNLOADS"
}

View File

@ -1,20 +0,0 @@
package tachiyomi.presentation.widget
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.glance.GlanceModifier
import androidx.glance.LocalContext
import androidx.glance.appwidget.cornerRadius
fun GlanceModifier.appWidgetBackgroundRadius(): GlanceModifier {
return this.cornerRadius(R.dimen.appwidget_background_radius)
}
fun GlanceModifier.appWidgetInnerRadius(): GlanceModifier {
return this.cornerRadius(R.dimen.appwidget_inner_radius)
}
@Composable
fun stringResource(@StringRes id: Int): String {
return LocalContext.current.getString(id)
}

View File

@ -8,10 +8,14 @@ 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 tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
object TachiyomiWidgetManager { class TachiyomiWidgetManager(
private val database: DatabaseHandler = Injekt.get(),
) {
fun Context.init(scope: LifecycleCoroutineScope, database: DatabaseHandler) { fun Context.init(scope: LifecycleCoroutineScope) {
database.subscribeToList { updatesViewQueries.updates(after = UpdatesGridGlanceWidget.DateLimit.timeInMillis) } database.subscribeToList { updatesViewQueries.updates(after = UpdatesGridGlanceWidget.DateLimit.timeInMillis) }
.drop(1) .drop(1)
.distinctUntilChanged() .distinctUntilChanged()

View File

@ -1,41 +1,19 @@
package tachiyomi.presentation.widget package tachiyomi.presentation.widget
import android.app.Application import android.app.Application
import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build import android.os.Build
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.glance.GlanceModifier import androidx.glance.GlanceModifier
import androidx.glance.Image
import androidx.glance.ImageProvider import androidx.glance.ImageProvider
import androidx.glance.LocalContext
import androidx.glance.LocalSize
import androidx.glance.action.clickable
import androidx.glance.appwidget.CircularProgressIndicator
import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetManager import androidx.glance.appwidget.GlanceAppWidgetManager
import androidx.glance.appwidget.SizeMode import androidx.glance.appwidget.SizeMode
import androidx.glance.appwidget.action.actionStartActivity
import androidx.glance.appwidget.appWidgetBackground import androidx.glance.appwidget.appWidgetBackground
import androidx.glance.appwidget.updateAll import androidx.glance.appwidget.updateAll
import androidx.glance.background import androidx.glance.background
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.Column
import androidx.glance.layout.ContentScale
import androidx.glance.layout.Row
import androidx.glance.layout.fillMaxSize import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.layout.size
import androidx.glance.text.Text
import androidx.glance.text.TextAlign
import androidx.glance.text.TextStyle
import androidx.glance.unit.ColorProvider
import coil.executeBlocking import coil.executeBlocking
import coil.imageLoader import coil.imageLoader
import coil.request.CachePolicy import coil.request.CachePolicy
@ -49,6 +27,10 @@ import eu.kanade.tachiyomi.util.system.dpToPx
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.domain.manga.model.MangaCover import tachiyomi.domain.manga.model.MangaCover
import tachiyomi.presentation.widget.components.CoverHeight
import tachiyomi.presentation.widget.components.CoverWidth
import tachiyomi.presentation.widget.components.LockedWidget
import tachiyomi.presentation.widget.components.UpdatesWidget
import tachiyomi.view.UpdatesView import tachiyomi.view.UpdatesView
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -62,127 +44,18 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
private val coroutineScope = MainScope() private val coroutineScope = MainScope()
var data: List<Pair<Long, Bitmap?>>? = null private var data: List<Pair<Long, Bitmap?>>? = null
override val sizeMode = SizeMode.Exact override val sizeMode = SizeMode.Exact
@Composable @Composable
override fun Content() { override fun Content() {
// App lock enabled, don't do anything // If app lock enabled, don't do anything
if (preferences.useAuthenticator().get()) { if (preferences.useAuthenticator().get()) {
WidgetNotAvailable() LockedWidget()
} else { return
UpdatesWidget()
}
}
@Composable
private fun WidgetNotAvailable() {
val clazz = Class.forName("eu.kanade.tachiyomi.ui.main.MainActivity")
val intent = Intent(LocalContext.current, clazz).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
Box(
modifier = GlanceModifier
.clickable(actionStartActivity(intent))
.then(ContainerModifier)
.padding(8.dp),
contentAlignment = Alignment.Center,
) {
Text(
text = stringResource(R.string.appwidget_unavailable_locked),
style = TextStyle(
color = ColorProvider(R.color.appwidget_on_secondary_container),
fontSize = 12.sp,
textAlign = TextAlign.Center,
),
)
}
}
@Composable
private fun UpdatesWidget() {
val (rowCount, columnCount) = LocalSize.current.calculateRowAndColumnCount()
Column(
modifier = ContainerModifier,
verticalAlignment = Alignment.CenterVertically,
horizontalAlignment = Alignment.CenterHorizontally,
) {
val inData = data
if (inData == null) {
CircularProgressIndicator()
} else if (inData.isEmpty()) {
Text(text = stringResource(R.string.information_no_recent))
} else {
(0 until rowCount).forEach { i ->
val coverRow = (0 until columnCount).mapNotNull { j ->
inData.getOrNull(j + (i * columnCount))
}
if (coverRow.isNotEmpty()) {
Row(
modifier = GlanceModifier
.padding(vertical = 4.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalAlignment = Alignment.CenterVertically,
) {
coverRow.forEach { (mangaId, cover) ->
Box(
modifier = GlanceModifier
.padding(horizontal = 3.dp),
contentAlignment = Alignment.Center,
) {
val intent = Intent(LocalContext.current, Class.forName("eu.kanade.tachiyomi.ui.main.MainActivity")).apply {
action = "eu.kanade.tachiyomi.SHOW_MANGA"
putExtra("manga", mangaId)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
// https://issuetracker.google.com/issues/238793260
addCategory(mangaId.toString())
}
Cover(
modifier = GlanceModifier.clickable(actionStartActivity(intent)),
cover = cover,
)
}
}
}
}
}
}
}
}
@Composable
private fun Cover(
modifier: GlanceModifier = GlanceModifier,
cover: Bitmap?,
) {
Box(
modifier = modifier
.size(width = CoverWidth, height = CoverHeight)
.appWidgetInnerRadius(),
) {
if (cover != null) {
Image(
provider = ImageProvider(cover),
contentDescription = null,
modifier = GlanceModifier
.fillMaxSize()
.appWidgetInnerRadius(),
contentScale = ContentScale.Crop,
)
} else {
// Enjoy placeholder
Image(
provider = ImageProvider(R.drawable.appwidget_cover_error),
contentDescription = null,
modifier = GlanceModifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
}
} }
UpdatesWidget(data)
} }
fun loadData(list: List<UpdatesView>? = null) { fun loadData(list: List<UpdatesView>? = null) {
@ -254,32 +127,8 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
} }
} }
private val CoverWidth = 58.dp val ContainerModifier = GlanceModifier
private val CoverHeight = 87.dp
private val ContainerModifier = GlanceModifier
.fillMaxSize() .fillMaxSize()
.background(ImageProvider(R.drawable.appwidget_background)) .background(ImageProvider(R.drawable.appwidget_background))
.appWidgetBackground() .appWidgetBackground()
.appWidgetBackgroundRadius() .appWidgetBackgroundRadius()
/**
* Calculates row-column count.
*
* Row
* Numerator: Container height - container vertical padding
* Denominator: Cover height + cover vertical padding
*
* Column
* Numerator: Container width - container horizontal padding
* Denominator: Cover width + cover horizontal padding
*
* @return pair of row and column count
*/
private fun DpSize.calculateRowAndColumnCount(): Pair<Int, Int> {
// Hack: Size provided by Glance manager is not reliable so take at least 1 row and 1 column
// Set max to 10 children each direction because of Glance limitation
val rowCount = (height.value / 95).toInt().coerceIn(1, 10)
val columnCount = (width.value / 64).toInt().coerceIn(1, 10)
return Pair(rowCount, columnCount)
}

View File

@ -0,0 +1,44 @@
package tachiyomi.presentation.widget.components
import android.content.Intent
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.glance.GlanceModifier
import androidx.glance.LocalContext
import androidx.glance.action.clickable
import androidx.glance.appwidget.action.actionStartActivity
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.padding
import androidx.glance.text.Text
import androidx.glance.text.TextAlign
import androidx.glance.text.TextStyle
import androidx.glance.unit.ColorProvider
import tachiyomi.core.Constants
import tachiyomi.presentation.widget.ContainerModifier
import tachiyomi.presentation.widget.R
import tachiyomi.presentation.widget.stringResource
@Composable
fun LockedWidget() {
val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
Box(
modifier = GlanceModifier
.clickable(actionStartActivity(intent))
.then(ContainerModifier)
.padding(8.dp),
contentAlignment = Alignment.Center,
) {
Text(
text = stringResource(R.string.appwidget_unavailable_locked),
style = TextStyle(
color = ColorProvider(R.color.appwidget_on_secondary_container),
fontSize = 12.sp,
textAlign = TextAlign.Center,
),
)
}
}

View File

@ -0,0 +1,48 @@
package tachiyomi.presentation.widget.components
import android.graphics.Bitmap
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.glance.GlanceModifier
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.layout.Box
import androidx.glance.layout.ContentScale
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.size
import tachiyomi.presentation.widget.R
import tachiyomi.presentation.widget.appWidgetInnerRadius
val CoverWidth = 58.dp
val CoverHeight = 87.dp
@Composable
fun UpdatesMangaCover(
modifier: GlanceModifier = GlanceModifier,
cover: Bitmap?,
) {
Box(
modifier = modifier
.size(width = CoverWidth, height = CoverHeight)
.appWidgetInnerRadius(),
) {
if (cover != null) {
Image(
provider = ImageProvider(cover),
contentDescription = null,
modifier = GlanceModifier
.fillMaxSize()
.appWidgetInnerRadius(),
contentScale = ContentScale.Crop,
)
} else {
// Enjoy placeholder
Image(
provider = ImageProvider(R.drawable.appwidget_cover_error),
contentDescription = null,
modifier = GlanceModifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
}
}
}

View File

@ -0,0 +1,77 @@
package tachiyomi.presentation.widget.components
import android.content.Intent
import android.graphics.Bitmap
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.glance.GlanceModifier
import androidx.glance.LocalContext
import androidx.glance.LocalSize
import androidx.glance.action.clickable
import androidx.glance.appwidget.CircularProgressIndicator
import androidx.glance.appwidget.action.actionStartActivity
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.text.Text
import tachiyomi.core.Constants
import tachiyomi.presentation.widget.ContainerModifier
import tachiyomi.presentation.widget.R
import tachiyomi.presentation.widget.calculateRowAndColumnCount
import tachiyomi.presentation.widget.stringResource
@Composable
fun UpdatesWidget(data: List<Pair<Long, Bitmap?>>?) {
val (rowCount, columnCount) = LocalSize.current.calculateRowAndColumnCount()
Column(
modifier = ContainerModifier,
verticalAlignment = Alignment.CenterVertically,
horizontalAlignment = Alignment.CenterHorizontally,
) {
if (data == null) {
CircularProgressIndicator()
} else if (data.isEmpty()) {
Text(text = stringResource(R.string.information_no_recent))
} else {
(0 until rowCount).forEach { i ->
val coverRow = (0 until columnCount).mapNotNull { j ->
data.getOrNull(j + (i * columnCount))
}
if (coverRow.isNotEmpty()) {
Row(
modifier = GlanceModifier
.padding(vertical = 4.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalAlignment = Alignment.CenterVertically,
) {
coverRow.forEach { (mangaId, cover) ->
Box(
modifier = GlanceModifier
.padding(horizontal = 3.dp),
contentAlignment = Alignment.Center,
) {
val intent = Intent(LocalContext.current, Class.forName(Constants.MAIN_ACTIVITY)).apply {
action = Constants.SHORTCUT_MANGA
putExtra(Constants.MANGA_EXTRA, mangaId)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
// https://issuetracker.google.com/issues/238793260
addCategory(mangaId.toString())
}
UpdatesMangaCover(
modifier = GlanceModifier.clickable(actionStartActivity(intent)),
cover = cover,
)
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,42 @@
package tachiyomi.presentation.widget
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.DpSize
import androidx.glance.GlanceModifier
import androidx.glance.LocalContext
import androidx.glance.appwidget.cornerRadius
fun GlanceModifier.appWidgetBackgroundRadius(): GlanceModifier {
return this.cornerRadius(R.dimen.appwidget_background_radius)
}
fun GlanceModifier.appWidgetInnerRadius(): GlanceModifier {
return this.cornerRadius(R.dimen.appwidget_inner_radius)
}
@Composable
fun stringResource(@StringRes id: Int): String {
return LocalContext.current.getString(id)
}
/**
* Calculates row-column count.
*
* Row
* Numerator: Container height - container vertical padding
* Denominator: Cover height + cover vertical padding
*
* Column
* Numerator: Container width - container horizontal padding
* Denominator: Cover width + cover horizontal padding
*
* @return pair of row and column count
*/
fun DpSize.calculateRowAndColumnCount(): Pair<Int, Int> {
// Hack: Size provided by Glance manager is not reliable so take at least 1 row and 1 column
// Set max to 10 children each direction because of Glance limitation
val rowCount = (height.value / 95).toInt().coerceIn(1, 10)
val columnCount = (width.value / 64).toInt().coerceIn(1, 10)
return Pair(rowCount, columnCount)
}