mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 02:34:39 +00:00
Glance widget for Recents
Recents because its using the same logic as app shortcuts already use Also added Compose + Kotlin 1.8.10 but no one cares about that Co-Authored-By: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com>
This commit is contained in:
parent
71e2a54d13
commit
a09fd8ac48
26 changed files with 588 additions and 22 deletions
|
@ -85,6 +85,12 @@ android {
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
|
compose = true
|
||||||
|
|
||||||
|
// Disable some unused things
|
||||||
|
aidl = false
|
||||||
|
renderScript = false
|
||||||
|
shaders = false
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions.add("default")
|
flavorDimensions.add("default")
|
||||||
|
@ -105,6 +111,10 @@ android {
|
||||||
checkReleaseBuilds = false
|
checkReleaseBuilds = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.4.2"
|
||||||
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
@ -116,6 +126,20 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// Compose
|
||||||
|
implementation("androidx.activity:activity-compose:1.6.1")
|
||||||
|
implementation("androidx.compose.foundation:foundation:1.3.1")
|
||||||
|
implementation("androidx.compose.animation:animation:1.3.3")
|
||||||
|
implementation("androidx.compose.ui:ui:1.3.3")
|
||||||
|
implementation("androidx.compose.material:material:1.3.1")
|
||||||
|
implementation("androidx.compose.material3:material3:1.0.1")
|
||||||
|
implementation("com.google.android.material:compose-theme-adapter-3:1.1.1")
|
||||||
|
implementation("androidx.compose.material:material-icons-extended:1.3.1")
|
||||||
|
implementation("androidx.compose.ui:ui-tooling-preview:1.3.3")
|
||||||
|
debugImplementation("androidx.compose.ui:ui-tooling:1.3.3")
|
||||||
|
implementation("com.google.accompanist:accompanist-webview:0.28.0")
|
||||||
|
implementation("androidx.glance:glance-appwidget:1.0.0-alpha03")
|
||||||
|
|
||||||
// Modified dependencies
|
// Modified dependencies
|
||||||
implementation("com.github.jays2kings:subsampling-scale-image-view:756849e") {
|
implementation("com.github.jays2kings:subsampling-scale-image-view:756849e") {
|
||||||
exclude(module = "image-decoder")
|
exclude(module = "image-decoder")
|
||||||
|
|
|
@ -230,6 +230,20 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".appwidget.UpdatesGridGlanceReceiver"
|
||||||
|
android:enabled="@bool/glance_appwidget_available"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/updates">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/updates_grid_glance_widget_info" />
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".data.library.LibraryUpdateService"
|
android:name=".data.library.LibraryUpdateService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package eu.kanade.tachiyomi.appwidget
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.glance.appwidget.GlanceAppWidgetManager
|
||||||
|
|
||||||
|
class TachiyomiWidgetManager {
|
||||||
|
|
||||||
|
suspend fun Context.init() {
|
||||||
|
val manager = GlanceAppWidgetManager(this)
|
||||||
|
if (manager.getGlanceIds(UpdatesGridGlanceWidget::class.java).isNotEmpty()) {
|
||||||
|
UpdatesGridGlanceWidget().loadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package eu.kanade.tachiyomi.appwidget
|
||||||
|
|
||||||
|
import androidx.glance.appwidget.GlanceAppWidget
|
||||||
|
import androidx.glance.appwidget.GlanceAppWidgetReceiver
|
||||||
|
|
||||||
|
class UpdatesGridGlanceReceiver : GlanceAppWidgetReceiver() {
|
||||||
|
override val glanceAppWidget: GlanceAppWidget = UpdatesGridGlanceWidget().apply { loadData() }
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
package eu.kanade.tachiyomi.appwidget
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import androidx.glance.GlanceModifier
|
||||||
|
import androidx.glance.ImageProvider
|
||||||
|
import androidx.glance.appwidget.GlanceAppWidget
|
||||||
|
import androidx.glance.appwidget.GlanceAppWidgetManager
|
||||||
|
import androidx.glance.appwidget.SizeMode
|
||||||
|
import androidx.glance.appwidget.appWidgetBackground
|
||||||
|
import androidx.glance.appwidget.updateAll
|
||||||
|
import androidx.glance.background
|
||||||
|
import androidx.glance.layout.fillMaxSize
|
||||||
|
import coil.executeBlocking
|
||||||
|
import coil.imageLoader
|
||||||
|
import coil.request.CachePolicy
|
||||||
|
import coil.request.ImageRequest
|
||||||
|
import coil.size.Precision
|
||||||
|
import coil.size.Scale
|
||||||
|
import coil.transform.RoundedCornersTransformation
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.appwidget.components.CoverHeight
|
||||||
|
import eu.kanade.tachiyomi.appwidget.components.CoverWidth
|
||||||
|
import eu.kanade.tachiyomi.appwidget.components.LockedWidget
|
||||||
|
import eu.kanade.tachiyomi.appwidget.util.appWidgetBackgroundRadius
|
||||||
|
import eu.kanade.tachiyomi.appwidget.util.calculateRowAndColumnCount
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.ui.recents.RecentsPresenter
|
||||||
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
|
import eu.kanade.tachiyomi.util.system.launchIO
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import tachiyomi.presentation.widget.components.UpdatesWidget
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
class UpdatesGridGlanceWidget : GlanceAppWidget() {
|
||||||
|
private val app: Application by injectLazy()
|
||||||
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
private val coroutineScope = MainScope()
|
||||||
|
|
||||||
|
private var data: List<Pair<Long, Bitmap?>>? = null
|
||||||
|
|
||||||
|
override val sizeMode = SizeMode.Exact
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
// If app lock enabled, don't do anything
|
||||||
|
if (preferences.useBiometrics().get()) {
|
||||||
|
LockedWidget()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
UpdatesWidget(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadData(list: List<Pair<Manga, Long>>? = null) {
|
||||||
|
coroutineScope.launchIO {
|
||||||
|
// Don't show anything when lock is active
|
||||||
|
if (preferences.useBiometrics().get()) {
|
||||||
|
updateAll(app)
|
||||||
|
return@launchIO
|
||||||
|
}
|
||||||
|
|
||||||
|
val manager = GlanceAppWidgetManager(app)
|
||||||
|
val ids = manager.getGlanceIds(this@UpdatesGridGlanceWidget::class.java)
|
||||||
|
if (ids.isEmpty()) return@launchIO
|
||||||
|
|
||||||
|
val (rowCount, columnCount) = ids
|
||||||
|
.flatMap { manager.getAppWidgetSizes(it) }
|
||||||
|
.maxBy { it.height.value * it.width.value }
|
||||||
|
.calculateRowAndColumnCount()
|
||||||
|
val processList = list ?: RecentsPresenter.getRecentManga(customAmount = rowCount * columnCount)
|
||||||
|
|
||||||
|
data = prepareList(processList, rowCount * columnCount)
|
||||||
|
ids.forEach { update(app, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prepareList(processList: List<Pair<Manga, Long>>, take: Int): List<Pair<Long, Bitmap?>> {
|
||||||
|
// Resize to cover size
|
||||||
|
val widthPx = CoverWidth.value.toInt().dpToPx
|
||||||
|
val heightPx = CoverHeight.value.toInt().dpToPx
|
||||||
|
val roundPx = app.resources.getDimension(R.dimen.appwidget_inner_radius)
|
||||||
|
return processList
|
||||||
|
// .distinctBy { it.first.id }
|
||||||
|
.sortedByDescending { it.second }
|
||||||
|
.take(take)
|
||||||
|
.map { it.first }
|
||||||
|
.map { updatesView ->
|
||||||
|
val request = ImageRequest.Builder(app)
|
||||||
|
.data(updatesView)
|
||||||
|
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||||
|
.precision(Precision.EXACT)
|
||||||
|
.size(widthPx, heightPx)
|
||||||
|
.scale(Scale.FILL)
|
||||||
|
.let {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||||
|
it.transformations(RoundedCornersTransformation(roundPx))
|
||||||
|
} else {
|
||||||
|
it // Handled by system
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
Pair(updatesView.id!!, app.imageLoader.executeBlocking(request).drawable?.toBitmap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DateLimit: Calendar
|
||||||
|
get() = Calendar.getInstance().apply {
|
||||||
|
time = Date()
|
||||||
|
add(Calendar.MONTH, -3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ContainerModifier = GlanceModifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(ImageProvider(R.drawable.appwidget_background))
|
||||||
|
.appWidgetBackground()
|
||||||
|
.appWidgetBackgroundRadius()
|
|
@ -0,0 +1,44 @@
|
||||||
|
package eu.kanade.tachiyomi.appwidget.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 eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.appwidget.ContainerModifier
|
||||||
|
import eu.kanade.tachiyomi.appwidget.util.stringResource
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LockedWidget() {
|
||||||
|
val intent = Intent(LocalContext.current, Class.forName(MainActivity.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,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package eu.kanade.tachiyomi.appwidget.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 eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.appwidget.util.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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
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 eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.appwidget.ContainerModifier
|
||||||
|
import eu.kanade.tachiyomi.appwidget.components.UpdatesMangaCover
|
||||||
|
import eu.kanade.tachiyomi.appwidget.util.calculateRowAndColumnCount
|
||||||
|
import eu.kanade.tachiyomi.appwidget.util.stringResource
|
||||||
|
import eu.kanade.tachiyomi.ui.main.SearchActivity
|
||||||
|
|
||||||
|
@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.no_recent_read_updated_manga))
|
||||||
|
} 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 = SearchActivity.openMangaIntent(LocalContext.current, mangaId, true)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
// https://issuetracker.google.com/issues/238793260
|
||||||
|
.addCategory(mangaId.toString())
|
||||||
|
UpdatesMangaCover(
|
||||||
|
modifier = GlanceModifier.clickable(actionStartActivity(intent)),
|
||||||
|
cover = cover,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package eu.kanade.tachiyomi.appwidget.util
|
||||||
|
|
||||||
|
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
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
|
@ -792,7 +792,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
|
||||||
saveExtras()
|
saveExtras()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveExtras() {
|
private fun saveExtras() {
|
||||||
mangaShortcutManager.updateShortcuts(this)
|
mangaShortcutManager.updateShortcuts(this)
|
||||||
MangaCoverMetadata.savePrefs()
|
MangaCoverMetadata.savePrefs()
|
||||||
}
|
}
|
||||||
|
@ -1397,6 +1397,8 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
|
||||||
private const val SWIPE_THRESHOLD = 100
|
private const val SWIPE_THRESHOLD = 100
|
||||||
private const val SWIPE_VELOCITY_THRESHOLD = 100
|
private const val SWIPE_VELOCITY_THRESHOLD = 100
|
||||||
|
|
||||||
|
const val MAIN_ACTIVITY = "eu.kanade.tachiyomi.ui.main.MainActivity"
|
||||||
|
|
||||||
// Shortcut actions
|
// Shortcut actions
|
||||||
const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
|
const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
|
||||||
const val SHORTCUT_RECENTLY_UPDATED = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED"
|
const val SHORTCUT_RECENTLY_UPDATED = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED"
|
||||||
|
|
|
@ -38,6 +38,7 @@ import java.util.Date
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class RecentsPresenter(
|
class RecentsPresenter(
|
||||||
val preferences: PreferencesHelper = Injekt.get(),
|
val preferences: PreferencesHelper = Injekt.get(),
|
||||||
|
@ -115,12 +116,23 @@ class RecentsPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a set of recent entries based on preferred view type, unless changed by [customViewType]
|
||||||
|
*
|
||||||
|
* @param oldQuery used to determine while running this method the query has changed, and to cancel this
|
||||||
|
* @param updatePageCount make true when fetching for more pages in the pagination scroll, otherwise make false to restart the list
|
||||||
|
* @param retryCount used to not burden the db with infinite calls, should not be set as its a recursive param
|
||||||
|
* @param itemCount also used in recursion to know how many items have been collected so far
|
||||||
|
* @param limit used by the companion method to not recursively call this method, since the first batch is good enough
|
||||||
|
* @param customViewType used to decide to use another view type instead of the one saved by preferences
|
||||||
|
* @param includeReadAnyway also used by companion method to include the read manga, by default only unread manga is used
|
||||||
|
*/
|
||||||
private suspend fun runRecents(
|
private suspend fun runRecents(
|
||||||
oldQuery: String = "",
|
oldQuery: String = "",
|
||||||
updatePageCount: Boolean = false,
|
updatePageCount: Boolean = false,
|
||||||
retryCount: Int = 0,
|
retryCount: Int = 0,
|
||||||
itemCount: Int = 0,
|
itemCount: Int = 0,
|
||||||
limit: Boolean = false,
|
limit: Int = -1,
|
||||||
customViewType: Int? = null,
|
customViewType: Int? = null,
|
||||||
includeReadAnyway: Boolean = false,
|
includeReadAnyway: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
@ -137,13 +149,13 @@ class RecentsPresenter(
|
||||||
}
|
}
|
||||||
val viewType = customViewType ?: viewType
|
val viewType = customViewType ?: viewType
|
||||||
|
|
||||||
val showRead = ((preferences.showReadInAllRecents().get() || query.isNotEmpty()) && !limit) || includeReadAnyway
|
val showRead = ((preferences.showReadInAllRecents().get() || query.isNotEmpty()) && limit != 0) || includeReadAnyway
|
||||||
val isUngrouped = viewType > VIEW_TYPE_GROUP_ALL || query.isNotEmpty()
|
val isUngrouped = viewType > VIEW_TYPE_GROUP_ALL || query.isNotEmpty()
|
||||||
val groupChaptersUpdates = preferences.groupChaptersUpdates().get()
|
val groupChaptersUpdates = preferences.groupChaptersUpdates().get()
|
||||||
val groupChaptersHistory = preferences.groupChaptersHistory().get()
|
val groupChaptersHistory = preferences.groupChaptersHistory().get()
|
||||||
|
|
||||||
val isCustom = customViewType != null
|
val isCustom = customViewType != null
|
||||||
val isEndless = isUngrouped && !limit
|
val isEndless = isUngrouped && limit != 0
|
||||||
val cReading = when {
|
val cReading = when {
|
||||||
viewType <= VIEW_TYPE_UNGROUP_ALL -> {
|
viewType <= VIEW_TYPE_UNGROUP_ALL -> {
|
||||||
db.getAllRecentsTypes(
|
db.getAllRecentsTypes(
|
||||||
|
@ -320,11 +332,14 @@ class RecentsPresenter(
|
||||||
}
|
}
|
||||||
val newCount = itemCount + newItems.size
|
val newCount = itemCount + newItems.size
|
||||||
val hasNewItems = newItems.isNotEmpty()
|
val hasNewItems = newItems.isNotEmpty()
|
||||||
if (updatePageCount && newCount < 25 && (viewType != VIEW_TYPE_GROUP_ALL || query.isNotEmpty()) && !limit) {
|
if (updatePageCount && (newCount < if (limit > 0) limit else 25) &&
|
||||||
|
(viewType != VIEW_TYPE_GROUP_ALL || query.isNotEmpty()) &&
|
||||||
|
limit != 0
|
||||||
|
) {
|
||||||
runRecents(oldQuery, true, retryCount + (if (hasNewItems) 0 else 1), newCount)
|
runRecents(oldQuery, true, retryCount + (if (hasNewItems) 0 else 1), newCount)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!limit) {
|
if (limit == -1) {
|
||||||
setDownloadedChapters(recentItems)
|
setDownloadedChapters(recentItems)
|
||||||
if (customViewType == null) {
|
if (customViewType == null) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -549,13 +564,19 @@ class RecentsPresenter(
|
||||||
var SHORT_LIMIT = 25
|
var SHORT_LIMIT = 25
|
||||||
private set
|
private set
|
||||||
|
|
||||||
suspend fun getRecentManga(includeRead: Boolean = false): List<Pair<Manga, Long>> {
|
suspend fun getRecentManga(includeRead: Boolean = false, customAmount: Int = 0): List<Pair<Manga, Long>> {
|
||||||
val presenter = RecentsPresenter()
|
val presenter = RecentsPresenter()
|
||||||
presenter.viewType = 1
|
presenter.viewType = 1
|
||||||
SHORT_LIMIT = if (includeRead) 50 else 25
|
SHORT_LIMIT = when {
|
||||||
presenter.runRecents(limit = true, includeReadAnyway = includeRead)
|
customAmount > 0 -> (customAmount * 1.5).roundToInt()
|
||||||
|
includeRead -> 50
|
||||||
|
else -> 25
|
||||||
|
}
|
||||||
|
presenter.runRecents(limit = customAmount, includeReadAnyway = includeRead)
|
||||||
SHORT_LIMIT = 25
|
SHORT_LIMIT = 25
|
||||||
return presenter.recentItems.filter { it.mch.manga.id != null }.map { it.mch.manga to it.mch.history.last_read }
|
return presenter.recentItems
|
||||||
|
.filter { it.mch.manga.id != null }
|
||||||
|
.map { it.mch.manga to it.mch.history.last_read }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import android.graphics.drawable.Icon
|
||||||
import coil.Coil
|
import coil.Coil
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.appwidget.TachiyomiWidgetManager
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
@ -35,13 +36,14 @@ class MangaShortcutManager(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun updateShortcuts(context: Context) {
|
fun updateShortcuts(context: Context) {
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N_MR1) {
|
launchIO {
|
||||||
if (!preferences.showSeriesInShortcuts() && !preferences.showSourcesInShortcuts()) {
|
with(TachiyomiWidgetManager()) { context.init() }
|
||||||
val shortcutManager = context.getSystemService(ShortcutManager::class.java)
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N_MR1) {
|
||||||
shortcutManager.removeAllDynamicShortcuts()
|
if (!preferences.showSeriesInShortcuts() && !preferences.showSourcesInShortcuts()) {
|
||||||
return
|
val shortcutManager = context.getSystemService(ShortcutManager::class.java)
|
||||||
}
|
shortcutManager.removeAllDynamicShortcuts()
|
||||||
launchIO {
|
return@launchIO
|
||||||
|
}
|
||||||
val shortcutManager = context.getSystemService(ShortcutManager::class.java)
|
val shortcutManager = context.getSystemService(ShortcutManager::class.java)
|
||||||
|
|
||||||
val recentManga = if (preferences.showSeriesInShortcuts()) {
|
val recentManga = if (preferences.showSeriesInShortcuts()) {
|
||||||
|
@ -78,8 +80,14 @@ class MangaShortcutManager(
|
||||||
context,
|
context,
|
||||||
"Manga-${item.id?.toString() ?: item.title}",
|
"Manga-${item.id?.toString() ?: item.title}",
|
||||||
)
|
)
|
||||||
.setShortLabel(item.title.takeUnless { it.isBlank() } ?: context.getString(R.string.manga))
|
.setShortLabel(
|
||||||
.setLongLabel(item.title.takeUnless { it.isBlank() } ?: context.getString(R.string.manga))
|
item.title.takeUnless { it.isBlank() }
|
||||||
|
?: context.getString(R.string.manga),
|
||||||
|
)
|
||||||
|
.setLongLabel(
|
||||||
|
item.title.takeUnless { it.isBlank() }
|
||||||
|
?: context.getString(R.string.manga),
|
||||||
|
)
|
||||||
.setIcon(
|
.setIcon(
|
||||||
if (bitmap != null) if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
if (bitmap != null) if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||||
Icon.createWithAdaptiveBitmap(bitmap.toSquare())
|
Icon.createWithAdaptiveBitmap(bitmap.toSquare())
|
||||||
|
|
6
app/src/main/res/drawable/appwidget_background.xml
Normal file
6
app/src/main/res/drawable/appwidget_background.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/appwidget_secondary_container" />
|
||||||
|
<corners android:radius="@dimen/appwidget_background_radius" />
|
||||||
|
</shape>
|
24
app/src/main/res/drawable/appwidget_cover_error.xml
Normal file
24
app/src/main/res/drawable/appwidget_cover_error.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/cover_placeholder" />
|
||||||
|
<corners android:radius="@dimen/appwidget_inner_radius" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="24dp"
|
||||||
|
android:bottom="24dp"
|
||||||
|
android:left="24dp"
|
||||||
|
android:right="24dp">
|
||||||
|
<vector
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/cover_placeholder"
|
||||||
|
android:pathData="M21,5v6.59l-2.29,-2.3c-0.39,-0.39 -1.03,-0.39 -1.42,0L14,12.59 10.71,9.3c-0.39,-0.39 -1.02,-0.39 -1.41,0L6,12.59 3,9.58L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l2.29,2.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.3 3.29,3.29c0.39,0.39 1.02,0.39 1.41,0l3.3,-3.28z"/>
|
||||||
|
</vector>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
BIN
app/src/main/res/drawable/updates_grid_widget_preview.webp
Normal file
BIN
app/src/main/res/drawable/updates_grid_widget_preview.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 410 KiB |
14
app/src/main/res/layout/appwidget_loading.xml
Normal file
14
app/src/main/res/layout/appwidget_loading.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/appwidget_background">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/loading"
|
||||||
|
android:textColor="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
9
app/src/main/res/values-night-v31/colors_appwidget.xml
Normal file
9
app/src/main/res/values-night-v31/colors_appwidget.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="appwidget_background">@color/m3_sys_color_dynamic_dark_surface</color>
|
||||||
|
<color name="appwidget_on_background">@color/m3_sys_color_dynamic_dark_on_surface</color>
|
||||||
|
<color name="appwidget_surface_variant">@color/m3_sys_color_dynamic_dark_surface_variant</color>
|
||||||
|
<color name="appwidget_on_surface_variant">@color/m3_sys_color_dynamic_dark_on_surface_variant</color>
|
||||||
|
<color name="appwidget_secondary_container">@color/m3_sys_color_dynamic_dark_secondary_container</color>
|
||||||
|
<color name="appwidget_on_secondary_container">@color/m3_sys_color_dynamic_dark_on_secondary_container</color>
|
||||||
|
</resources>
|
|
@ -1,5 +1,28 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<color name="tachiyomi_primary">#AEC6FF</color>
|
||||||
|
<color name="tachiyomi_onPrimary">#002C71</color>
|
||||||
|
<color name="tachiyomi_primaryContainer">#00419E</color>
|
||||||
|
<color name="tachiyomi_onPrimaryContainer">#D8E2FF</color>
|
||||||
|
<color name="tachiyomi_secondary">#AEC6FF</color>
|
||||||
|
<color name="tachiyomi_onSecondary">#002C71</color>
|
||||||
|
<color name="tachiyomi_secondaryContainer">#00419E</color>
|
||||||
|
<color name="tachiyomi_onSecondaryContainer">#D8E2FF</color>
|
||||||
|
<color name="tachiyomi_tertiary">#7ADC77</color>
|
||||||
|
<color name="tachiyomi_onTertiary">#003907</color>
|
||||||
|
<color name="tachiyomi_tertiaryContainer">#00530D</color>
|
||||||
|
<color name="tachiyomi_onTertiaryContainer">#95F990</color>
|
||||||
|
<color name="tachiyomi_background">#1B1B1E</color>
|
||||||
|
<color name="tachiyomi_onBackground">#E4E2E6</color>
|
||||||
|
<color name="tachiyomi_surface">#1B1B1E</color>
|
||||||
|
<color name="tachiyomi_onSurface">#E4E2E6</color>
|
||||||
|
<color name="tachiyomi_surfaceVariant">#44464E</color>
|
||||||
|
<color name="tachiyomi_onSurfaceVariant">#C5C6D0</color>
|
||||||
|
<color name="tachiyomi_outline">#8E9099</color>
|
||||||
|
<color name="tachiyomi_inverseOnSurface">#1B1B1E</color>
|
||||||
|
<color name="tachiyomi_inverseSurface">#E4E2E6</color>
|
||||||
|
<color name="tachiyomi_primaryInverse">#0057CE</color>
|
||||||
|
|
||||||
<!-- Application Colors -->
|
<!-- Application Colors -->
|
||||||
<color name="primaryVariantTachiyomi">#272829</color>
|
<color name="primaryVariantTachiyomi">#272829</color>
|
||||||
<color name="colorPrimaryInactive">@color/md_white_1000_76</color>
|
<color name="colorPrimaryInactive">@color/md_white_1000_76</color>
|
||||||
|
|
9
app/src/main/res/values-v31/colors_appwidget.xml
Normal file
9
app/src/main/res/values-v31/colors_appwidget.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="appwidget_background">@color/m3_sys_color_dynamic_light_surface</color>
|
||||||
|
<color name="appwidget_on_background">@color/m3_sys_color_dynamic_light_on_surface</color>
|
||||||
|
<color name="appwidget_surface_variant">@color/m3_sys_color_dynamic_light_surface_variant</color>
|
||||||
|
<color name="appwidget_on_surface_variant">@color/m3_sys_color_dynamic_light_on_surface_variant</color>
|
||||||
|
<color name="appwidget_secondary_container">@color/m3_sys_color_dynamic_light_secondary_container</color>
|
||||||
|
<color name="appwidget_on_secondary_container">@color/m3_sys_color_dynamic_light_on_secondary_container</color>
|
||||||
|
</resources>
|
|
@ -1,5 +1,30 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<color name="tachiyomi_primary">#0057CE</color>
|
||||||
|
<color name="tachiyomi_onPrimary">#FFFFFF</color>
|
||||||
|
<color name="tachiyomi_primaryContainer">#D8E2FF</color>
|
||||||
|
<color name="tachiyomi_onPrimaryContainer">#001947</color>
|
||||||
|
<color name="tachiyomi_secondary">#0057CE</color>
|
||||||
|
<color name="tachiyomi_onSecondary">#FFFFFF</color>
|
||||||
|
<color name="tachiyomi_secondaryContainer">#D8E2FF</color>
|
||||||
|
<color name="tachiyomi_onSecondaryContainer">#001947</color>
|
||||||
|
<color name="tachiyomi_tertiary">#006E17</color>
|
||||||
|
<color name="tachiyomi_onTertiary">#FFFFFF</color>
|
||||||
|
<color name="tachiyomi_tertiaryContainer">#95F990</color>
|
||||||
|
<color name="tachiyomi_onTertiaryContainer">#002202</color>
|
||||||
|
<color name="tachiyomi_background">#FDFBFF</color>
|
||||||
|
<color name="tachiyomi_onBackground">#1B1B1E</color>
|
||||||
|
<color name="tachiyomi_surface">#FDFBFF</color>
|
||||||
|
<color name="tachiyomi_onSurface">#1B1B1E</color>
|
||||||
|
<color name="tachiyomi_surfaceVariant">#E1E2EC</color>
|
||||||
|
<color name="tachiyomi_onSurfaceVariant">#44464E</color>
|
||||||
|
<color name="tachiyomi_outline">#757780</color>
|
||||||
|
<color name="tachiyomi_inverseOnSurface">#F2F0F4</color>
|
||||||
|
<color name="tachiyomi_inverseSurface">#303033</color>
|
||||||
|
<color name="tachiyomi_primaryInverse">#AEC6FF</color>
|
||||||
|
|
||||||
|
<color name="cover_placeholder">#1F888888</color>
|
||||||
|
|
||||||
<!-- Application Colors -->
|
<!-- Application Colors -->
|
||||||
<color name="primaryVariantTachiyomi">#E5ECF4</color>
|
<color name="primaryVariantTachiyomi">#E5ECF4</color>
|
||||||
<color name="colorPrimaryInactive">#C2424242</color>
|
<color name="colorPrimaryInactive">#C2424242</color>
|
||||||
|
|
9
app/src/main/res/values/colors_appwidget.xml
Normal file
9
app/src/main/res/values/colors_appwidget.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="appwidget_background">@color/tachiyomi_surface</color>
|
||||||
|
<color name="appwidget_on_background">@color/tachiyomi_onSurface</color>
|
||||||
|
<color name="appwidget_surface_variant">@color/tachiyomi_surfaceVariant</color>
|
||||||
|
<color name="appwidget_on_surface_variant">@color/tachiyomi_onSurfaceVariant</color>
|
||||||
|
<color name="appwidget_secondary_container">@color/tachiyomi_secondaryContainer</color>
|
||||||
|
<color name="appwidget_on_secondary_container">@color/tachiyomi_onSecondaryContainer</color>
|
||||||
|
</resources>
|
|
@ -27,4 +27,7 @@
|
||||||
<dimen name="marginSmall">8dp</dimen>
|
<dimen name="marginSmall">8dp</dimen>
|
||||||
<dimen name="marginNormal">12dp</dimen>
|
<dimen name="marginNormal">12dp</dimen>
|
||||||
<dimen name="marginFar">56dp</dimen>
|
<dimen name="marginFar">56dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="appwidget_background_radius">16dp</dimen>
|
||||||
|
<dimen name="appwidget_inner_radius">12dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1042,6 +1042,10 @@
|
||||||
<!-- Do not translate "WebView" -->
|
<!-- Do not translate "WebView" -->
|
||||||
<string name="webview_is_required">WebView is required for Tachiyomi</string>
|
<string name="webview_is_required">WebView is required for Tachiyomi</string>
|
||||||
|
|
||||||
|
<!-- App widget -->
|
||||||
|
<string name="appwidget_updates_description">See your recently updated library entries</string>
|
||||||
|
<string name="appwidget_unavailable_locked">Widget not available when app lock is enabled</string>
|
||||||
|
|
||||||
<!-- Miscellaneous -->
|
<!-- Miscellaneous -->
|
||||||
<string name="add">Add</string>
|
<string name="add">Add</string>
|
||||||
<string name="add_to_">Add to %1$s</string>
|
<string name="add_to_">Add to %1$s</string>
|
||||||
|
|
15
app/src/main/res/xml/updates_grid_glance_widget_info.xml
Normal file
15
app/src/main/res/xml/updates_grid_glance_widget_info.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:description="@string/appwidget_updates_description"
|
||||||
|
android:previewImage="@drawable/updates_grid_widget_preview"
|
||||||
|
android:initialLayout="@layout/appwidget_loading"
|
||||||
|
android:minWidth="240dp"
|
||||||
|
android:minHeight="60dp"
|
||||||
|
android:minResizeWidth="80dp"
|
||||||
|
android:minResizeHeight="40dp"
|
||||||
|
android:maxResizeWidth="600dp"
|
||||||
|
android:maxResizeHeight="600dp"
|
||||||
|
android:targetCellWidth="4"
|
||||||
|
android:targetCellHeight="2"
|
||||||
|
android:resizeMode="horizontal|vertical"
|
||||||
|
android:widgetCategory="home_screen" />
|
|
@ -26,9 +26,9 @@ subprojects {
|
||||||
buildscript {
|
buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.android.tools.build:gradle:7.4.1")
|
classpath("com.android.tools.build:gradle:7.4.1")
|
||||||
classpath("com.google.gms:google-services:4.3.14")
|
classpath("com.google.gms:google-services:4.3.15")
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${AndroidVersions.kotlin}")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${AndroidVersions.kotlin}")
|
||||||
classpath("com.google.android.gms:oss-licenses-plugin:0.10.5")
|
classpath("com.google.android.gms:oss-licenses-plugin:0.10.6")
|
||||||
classpath("org.jetbrains.kotlin:kotlin-serialization:${AndroidVersions.kotlin}")
|
classpath("org.jetbrains.kotlin:kotlin-serialization:${AndroidVersions.kotlin}")
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
|
|
@ -7,7 +7,7 @@ object AndroidVersions {
|
||||||
const val versionCode = 99
|
const val versionCode = 99
|
||||||
const val versionName = "1.6.1"
|
const val versionName = "1.6.1"
|
||||||
const val ndk = "23.1.7779620"
|
const val ndk = "23.1.7779620"
|
||||||
const val kotlin = "1.7.20"
|
const val kotlin = "1.8.10"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Plugins {
|
object Plugins {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue