diff --git a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt index 8af4f2ef01..b463318d63 100644 --- a/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt @@ -32,7 +32,7 @@ import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.more.DownloadQueueState -import eu.kanade.tachiyomi.util.Constants +import tachiyomi.core.Constants @Composable fun MoreScreen( diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 7919e82440..dbb3e6ec72 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -124,8 +124,8 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { setAppCompatDelegateThemeMode(Injekt.get().themeMode().get()) // Updates widget update - with(TachiyomiWidgetManager) { - init(ProcessLifecycleOwner.get().lifecycleScope, Injekt.get()) + with(TachiyomiWidgetManager(Injekt.get())) { + init(ProcessLifecycleOwner.get().lifecycleScope) } if (!LogcatLogger.isInstalled && networkPreferences.verboseLogging().get()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt index 1c4c95149e..78269db552 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt @@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.system.notification import eu.kanade.tachiyomi.util.system.notificationBuilder import eu.kanade.tachiyomi.util.system.notificationManager +import tachiyomi.core.Constants import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga import uy.kohesive.injekt.injectLazy @@ -333,7 +334,7 @@ class LibraryUpdateNotifier(private val context: Context) { private fun getNotificationIntent(): PendingIntent { val intent = Intent(context, MainActivity::class.java).apply { 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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt index b3be0f5478..e271294c9b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationHandler.kt @@ -7,6 +7,7 @@ import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.extension.util.ExtensionInstaller import eu.kanade.tachiyomi.ui.main.MainActivity +import tachiyomi.core.Constants /** * Class that manages [PendingIntent] of activity's @@ -20,7 +21,7 @@ object NotificationHandler { internal fun openDownloadManagerPendingActivity(context: Context): PendingIntent { val intent = Intent(context, MainActivity::class.java).apply { 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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index eefabb2d45..e9c0e6a8e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -21,7 +21,6 @@ import eu.kanade.tachiyomi.data.updater.AppUpdateService import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.ui.main.MainActivity 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.storage.DiskUtil 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.toast import kotlinx.coroutines.runBlocking +import tachiyomi.core.Constants import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.toChapterUpdate import tachiyomi.domain.manga.model.Manga @@ -455,7 +455,7 @@ class NotificationReceiver : BroadcastReceiver() { */ internal fun openChapterPendingActivity(context: Context, manga: Manga, groupId: Int): PendingIntent { 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) .putExtra(Constants.MANGA_EXTRA, manga.id) .putExtra("notificationId", manga.id.hashCode()) @@ -538,7 +538,7 @@ class NotificationReceiver : BroadcastReceiver() { */ internal fun openExtensionsPendingActivity(context: Context): PendingIntent { val intent = Intent(context, MainActivity::class.java).apply { - action = MainActivity.SHORTCUT_EXTENSIONS + action = Constants.SHORTCUT_EXTENSIONS addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) } return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt index a899e0bcba..ab36d83129 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt @@ -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.manga.MangaScreen import eu.kanade.tachiyomi.ui.webview.WebViewScreen -import eu.kanade.tachiyomi.util.Constants import kotlinx.coroutines.launch +import tachiyomi.core.Constants import tachiyomi.domain.manga.model.Manga data class SourceSearchScreen( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt index 4be17c8179..c3d5e73a62 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt @@ -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.manga.MangaScreen import eu.kanade.tachiyomi.ui.webview.WebViewScreen -import eu.kanade.tachiyomi.util.Constants import eu.kanade.tachiyomi.util.lang.launchIO import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.receiveAsFlow +import tachiyomi.core.Constants data class BrowseSourceScreen( private val sourceId: Long, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index fd51a9d4de..30c1bfc3d7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -79,7 +79,6 @@ import eu.kanade.tachiyomi.ui.library.LibrarySettingsSheet import eu.kanade.tachiyomi.ui.library.LibraryTab import eu.kanade.tachiyomi.ui.manga.MangaScreen 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.isNavigationBarNeedsScrim import eu.kanade.tachiyomi.util.system.logcat @@ -94,6 +93,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import logcat.LogPriority +import tachiyomi.core.Constants import tachiyomi.domain.category.model.Category import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -405,17 +405,17 @@ class MainActivity : BaseActivity() { isHandlingShortcut = true when (intent.action) { - SHORTCUT_LIBRARY -> HomeScreen.openTab(HomeScreen.Tab.Library()) - SHORTCUT_MANGA -> { + Constants.SHORTCUT_LIBRARY -> HomeScreen.openTab(HomeScreen.Tab.Library()) + Constants.SHORTCUT_MANGA -> { val idToOpen = intent.extras?.getLong(Constants.MANGA_EXTRA) ?: return false navigator.popUntilRoot() HomeScreen.openTab(HomeScreen.Tab.Library(idToOpen)) } - SHORTCUT_UPDATES -> HomeScreen.openTab(HomeScreen.Tab.Updates) - SHORTCUT_HISTORY -> HomeScreen.openTab(HomeScreen.Tab.History) - SHORTCUT_SOURCES -> HomeScreen.openTab(HomeScreen.Tab.Browse(false)) - SHORTCUT_EXTENSIONS -> HomeScreen.openTab(HomeScreen.Tab.Browse(true)) - SHORTCUT_DOWNLOADS -> { + Constants.SHORTCUT_UPDATES -> HomeScreen.openTab(HomeScreen.Tab.Updates) + Constants.SHORTCUT_HISTORY -> HomeScreen.openTab(HomeScreen.Tab.History) + Constants.SHORTCUT_SOURCES -> HomeScreen.openTab(HomeScreen.Tab.Browse(false)) + Constants.SHORTCUT_EXTENSIONS -> HomeScreen.openTab(HomeScreen.Tab.Browse(true)) + Constants.SHORTCUT_DOWNLOADS -> { navigator.popUntilRoot() 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_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_QUERY = "query" const val INTENT_SEARCH_FILTER = "filter" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 4667d54984..127f90af26 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -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.pager.R2LPagerViewer 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.launchNonCancellable import eu.kanade.tachiyomi.util.lang.withUIContext @@ -94,6 +93,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import logcat.LogPriority +import tachiyomi.core.Constants import tachiyomi.domain.manga.model.Manga import uy.kohesive.injekt.injectLazy import kotlin.math.abs @@ -403,7 +403,7 @@ class ReaderActivity : BaseActivity() { viewModel.manga?.id?.let { id -> startActivity( Intent(this, MainActivity::class.java).apply { - action = MainActivity.SHORTCUT_MANGA + action = Constants.SHORTCUT_MANGA putExtra(Constants.MANGA_EXTRA, id) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/Constants.kt b/app/src/main/java/eu/kanade/tachiyomi/util/Constants.kt deleted file mode 100644 index dadc48afb9..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/util/Constants.kt +++ /dev/null @@ -1,7 +0,0 @@ -package eu.kanade.tachiyomi.util - -object Constants { - const val URL_HELP = "https://tachiyomi.org/help/" - - const val MANGA_EXTRA = "manga" -} diff --git a/core/src/main/java/tachiyomi/core/Constants.kt b/core/src/main/java/tachiyomi/core/Constants.kt new file mode 100644 index 0000000000..156ed61012 --- /dev/null +++ b/core/src/main/java/tachiyomi/core/Constants.kt @@ -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" +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/GlanceUtils.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/GlanceUtils.kt deleted file mode 100644 index 1d49e6c81a..0000000000 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/GlanceUtils.kt +++ /dev/null @@ -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) -} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt index 27d197e6d5..1ede10ba00 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/TachiyomiWidgetManager.kt @@ -8,10 +8,14 @@ import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach 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) } .drop(1) .distinctUntilChanged() diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt index e6de78f2c2..4465e1303d 100644 --- a/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/UpdatesGridGlanceWidget.kt @@ -1,41 +1,19 @@ package tachiyomi.presentation.widget import android.app.Application -import android.content.Intent import android.graphics.Bitmap import android.os.Build 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.glance.GlanceModifier -import androidx.glance.Image 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.GlanceAppWidgetManager import androidx.glance.appwidget.SizeMode -import androidx.glance.appwidget.action.actionStartActivity import androidx.glance.appwidget.appWidgetBackground import androidx.glance.appwidget.updateAll 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.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.imageLoader import coil.request.CachePolicy @@ -49,6 +27,10 @@ import eu.kanade.tachiyomi.util.system.dpToPx import kotlinx.coroutines.MainScope import tachiyomi.data.DatabaseHandler 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 uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -62,127 +44,18 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() { private val coroutineScope = MainScope() - var data: List>? = null + private var data: List>? = null override val sizeMode = SizeMode.Exact @Composable override fun Content() { - // App lock enabled, don't do anything + // If app lock enabled, don't do anything if (preferences.useAuthenticator().get()) { - WidgetNotAvailable() - } else { - 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, - ) - } + LockedWidget() + return } + UpdatesWidget(data) } fun loadData(list: List? = null) { @@ -254,32 +127,8 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() { } } -private val CoverWidth = 58.dp -private val CoverHeight = 87.dp - -private val ContainerModifier = GlanceModifier +val ContainerModifier = GlanceModifier .fillMaxSize() .background(ImageProvider(R.drawable.appwidget_background)) .appWidgetBackground() .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 { - // 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) -} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt new file mode 100644 index 0000000000..8768f8c139 --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/LockedWidget.kt @@ -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, + ), + ) + } +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt new file mode 100644 index 0000000000..58bcd3635f --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesMangaCover.kt @@ -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, + ) + } + } +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt new file mode 100644 index 0000000000..ac9508abd3 --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/components/UpdatesWidget.kt @@ -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>?) { + 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, + ) + } + } + } + } + } + } + } +} diff --git a/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt b/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt new file mode 100644 index 0000000000..dc131941d2 --- /dev/null +++ b/presentation-widget/src/main/java/tachiyomi/presentation/widget/util/GlanceUtils.kt @@ -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 { + // 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) +}