mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-21 11:01:50 +01:00
Split UpdatesGridGlanceWidget into smaller bits (#8991)
- Renamed Composables - Moved Constants to core module
This commit is contained in:
parent
12e41b6e6f
commit
2501fef9e4
@ -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(
|
||||||
|
@ -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()) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
|
@ -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"
|
||||||
|
@ -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)
|
||||||
},
|
},
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.util
|
|
||||||
|
|
||||||
object Constants {
|
|
||||||
const val URL_HELP = "https://tachiyomi.org/help/"
|
|
||||||
|
|
||||||
const val MANGA_EXTRA = "manga"
|
|
||||||
}
|
|
18
core/src/main/java/tachiyomi/core/Constants.kt
Normal file
18
core/src/main/java/tachiyomi/core/Constants.kt
Normal 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"
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
@ -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()
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
|
@ -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,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user