mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-28 17:19:00 +03:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
d51fb8de47
26 changed files with 173 additions and 86 deletions
|
@ -40,8 +40,6 @@ android {
|
|||
// Please disable ACRA or use your own instance in forked versions of the project
|
||||
buildConfigField("String", "ACRA_URI", "\"https://acra.jmir.xyz/report\"")
|
||||
|
||||
multiDexEnabled = true
|
||||
|
||||
ndk {
|
||||
//abiFilters += SUPPORTED_ABIS
|
||||
setOf("armeabi-v7a", "arm64-v8a", "x86")
|
||||
|
@ -150,7 +148,6 @@ dependencies {
|
|||
implementation("androidx.coordinatorlayout:coordinatorlayout:1.1.0")
|
||||
implementation("androidx.core:core-ktx:1.7.0-alpha01")
|
||||
implementation("androidx.core:core-splashscreen:1.0.0-alpha01")
|
||||
implementation("androidx.multidex:multidex:2.0.1")
|
||||
implementation("androidx.preference:preference-ktx:1.1.1")
|
||||
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01")
|
||||
|
@ -271,7 +268,6 @@ dependencies {
|
|||
|
||||
val robolectricVersion = "3.1.4"
|
||||
testImplementation("org.robolectric:robolectric:$robolectricVersion")
|
||||
testImplementation("org.robolectric:shadows-multidex:$robolectricVersion")
|
||||
testImplementation("org.robolectric:shadows-play-services:$robolectricVersion")
|
||||
|
||||
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
||||
|
|
|
@ -11,6 +11,7 @@ import android.os.Build
|
|||
import android.os.StrictMode
|
||||
import android.os.StrictMode.VmPolicy
|
||||
import android.webkit.WebView
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.Lifecycle
|
||||
|
@ -18,7 +19,6 @@ import androidx.lifecycle.LifecycleObserver
|
|||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.multidex.MultiDex
|
||||
import coil.ImageLoader
|
||||
import coil.ImageLoaderFactory
|
||||
import coil.decode.GifDecoder
|
||||
|
@ -28,7 +28,9 @@ import eu.kanade.tachiyomi.data.coil.ByteBufferFetcher
|
|||
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
||||
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||
import eu.kanade.tachiyomi.util.system.notification
|
||||
|
@ -102,11 +104,17 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory {
|
|||
}
|
||||
}
|
||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(base)
|
||||
MultiDex.install(this)
|
||||
preferences.themeMode()
|
||||
.asImmediateFlow {
|
||||
AppCompatDelegate.setDefaultNightMode(
|
||||
when (it) {
|
||||
PreferenceValues.ThemeMode.light -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
PreferenceValues.ThemeMode.dark -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
PreferenceValues.ThemeMode.system -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
)
|
||||
}.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
||||
}
|
||||
|
||||
override fun newImageLoader(): ImageLoader {
|
||||
|
|
|
@ -70,8 +70,11 @@ open class AnimeSourceManager(private val context: Context) {
|
|||
return name
|
||||
}
|
||||
|
||||
private fun getSourceNotInstalledException(): Exception {
|
||||
return Exception(context.getString(R.string.source_not_installed, id.toString()))
|
||||
private fun getSourceNotInstalledException(): SourceNotInstalledException {
|
||||
return SourceNotInstalledException(id)
|
||||
}
|
||||
}
|
||||
|
||||
inner class SourceNotInstalledException(val id: Long) :
|
||||
Exception(context.getString(R.string.source_not_installed, id.toString()))
|
||||
}
|
||||
|
|
|
@ -316,6 +316,9 @@ class AnimelibUpdateService(
|
|||
} catch (e: Throwable) {
|
||||
val errorMessage = if (e is NoEpisodesException) {
|
||||
getString(R.string.no_chapters_error)
|
||||
} else if (e is AnimeSourceManager.SourceNotInstalledException) {
|
||||
// failedUpdates will already have the source, don't need to copy it into the message
|
||||
getString(R.string.loader_not_implemented_error)
|
||||
} else {
|
||||
e.message
|
||||
}
|
||||
|
|
|
@ -11,8 +11,10 @@ interface Anime : SAnime {
|
|||
|
||||
var favorite: Boolean
|
||||
|
||||
// last time the episode list changed in any way
|
||||
var last_update: Long
|
||||
|
||||
// predicted next update time based on latest (by date) 4 episodes' deltas
|
||||
var next_update: Long
|
||||
|
||||
var date_added: Long
|
||||
|
|
|
@ -13,8 +13,10 @@ interface Manga : SManga {
|
|||
|
||||
var favorite: Boolean
|
||||
|
||||
// last time the chapter list changed in any way
|
||||
var last_update: Long
|
||||
|
||||
// predicted next update time based on latest (by date) 4 chapters' deltas
|
||||
var next_update: Long
|
||||
|
||||
var date_added: Long
|
||||
|
|
|
@ -316,6 +316,9 @@ class LibraryUpdateService(
|
|||
} catch (e: Throwable) {
|
||||
val errorMessage = if (e is NoChaptersException) {
|
||||
getString(R.string.no_chapters_error)
|
||||
} else if (e is SourceManager.SourceNotInstalledException) {
|
||||
// failedUpdates will already have the source, don't need to copy it into the message
|
||||
getString(R.string.loader_not_implemented_error)
|
||||
} else {
|
||||
e.message
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||
*/
|
||||
private fun shareImage(context: Context, path: String, notificationId: Int) {
|
||||
dismissNotification(context, notificationId)
|
||||
context.startActivity(File(path).getUriCompat(context).toShareIntent())
|
||||
context.startActivity(File(path).getUriCompat(context).toShareIntent(context))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,7 +160,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||
*/
|
||||
private fun shareFile(context: Context, uri: Uri, fileMimeType: String, notificationId: Int) {
|
||||
dismissNotification(context, notificationId)
|
||||
context.startActivity(uri.toShareIntent(fileMimeType))
|
||||
context.startActivity(uri.toShareIntent(context, fileMimeType))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,8 +70,11 @@ open class SourceManager(private val context: Context) {
|
|||
return name
|
||||
}
|
||||
|
||||
private fun getSourceNotInstalledException(): Exception {
|
||||
return Exception(context.getString(R.string.source_not_installed, id.toString()))
|
||||
private fun getSourceNotInstalledException(): SourceNotInstalledException {
|
||||
return SourceNotInstalledException(id)
|
||||
}
|
||||
}
|
||||
|
||||
inner class SourceNotInstalledException(val id: Long) :
|
||||
Exception(context.getString(R.string.source_not_installed, id.toString()))
|
||||
}
|
||||
|
|
|
@ -705,12 +705,7 @@ class AnimeController :
|
|||
useCoverAsBitmap(activity) { coverBitmap ->
|
||||
val cover = presenter.shareCover(activity, coverBitmap)
|
||||
val uri = cover.getUriCompat(activity)
|
||||
startActivity(
|
||||
Intent.createChooser(
|
||||
uri.toShareIntent(),
|
||||
activity.getString(R.string.action_share)
|
||||
)
|
||||
)
|
||||
startActivity(uri.toShareIntent(activity))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
|
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.base.activity
|
|||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
|
@ -25,7 +24,7 @@ abstract class BaseThemedActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
applyThemePreferences(preferences)
|
||||
applyAppTheme(preferences)
|
||||
|
||||
Injekt.get<PreferencesHelper>().incognitoMode()
|
||||
.asImmediateFlow {
|
||||
|
@ -37,7 +36,7 @@ abstract class BaseThemedActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
companion object {
|
||||
fun AppCompatActivity.applyThemePreferences(preferences: PreferencesHelper) {
|
||||
fun AppCompatActivity.applyAppTheme(preferences: PreferencesHelper) {
|
||||
val resIds = mutableListOf<Int>()
|
||||
when (preferences.appTheme().get()) {
|
||||
PreferenceValues.AppTheme.MONET -> {
|
||||
|
@ -77,16 +76,6 @@ abstract class BaseThemedActivity : AppCompatActivity() {
|
|||
resIds.forEach {
|
||||
setTheme(it)
|
||||
}
|
||||
|
||||
lifecycleScope.launchWhenCreated {
|
||||
AppCompatDelegate.setDefaultNightMode(
|
||||
when (preferences.themeMode().get()) {
|
||||
PreferenceValues.ThemeMode.light -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
PreferenceValues.ThemeMode.dark -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
PreferenceValues.ThemeMode.system -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -688,12 +688,7 @@ class MangaController :
|
|||
useCoverAsBitmap(activity) { coverBitmap ->
|
||||
val cover = presenter.shareCover(activity, coverBitmap)
|
||||
val uri = cover.getUriCompat(activity)
|
||||
startActivity(
|
||||
Intent.createChooser(
|
||||
uri.toShareIntent(),
|
||||
activity.getString(R.string.action_share)
|
||||
)
|
||||
)
|
||||
startActivity(uri.toShareIntent(activity))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.app.ActionBar
|
||||
import android.app.ProgressDialog
|
||||
import android.content.ClipData
|
||||
import android.content.Context
|
||||
|
@ -45,7 +46,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||
import eu.kanade.tachiyomi.data.preference.toggle
|
||||
import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseThemedActivity.Companion.applyThemePreferences
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseThemedActivity.Companion.applyAppTheme
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
|
||||
|
@ -140,7 +141,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||
* Called when the activity is created. Initializes the presenter and configuration.
|
||||
*/
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
applyThemePreferences(preferences)
|
||||
applyAppTheme(preferences)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ReaderActivityBinding.inflate(layoutInflater)
|
||||
|
@ -189,6 +190,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||
readingModeToast?.cancel()
|
||||
progressDialog?.dismiss()
|
||||
progressDialog = null
|
||||
listeners = mutableListOf()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,12 +488,23 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||
)
|
||||
}
|
||||
|
||||
private var listeners: MutableList<ActionBar.OnMenuVisibilityListener> = mutableListOf()
|
||||
|
||||
fun addOnMenuVisibilityListener(listener: ActionBar.OnMenuVisibilityListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
fun removeOnMenuVisibilityListener(listener: ActionBar.OnMenuVisibilityListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of the menu according to [visible] and with an optional parameter to
|
||||
* [animate] the views.
|
||||
*/
|
||||
fun setMenuVisibility(visible: Boolean, animate: Boolean = true) {
|
||||
menuVisible = visible
|
||||
listeners.forEach { listener -> listener.onMenuVisibilityChanged(visible) }
|
||||
if (visible) {
|
||||
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
|
||||
binding.readerMenu.isVisible = true
|
||||
|
@ -737,6 +750,15 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the viewer to hide the menu.
|
||||
*/
|
||||
fun hideMenu() {
|
||||
if (menuVisible) {
|
||||
setMenuVisibility(false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the page sheet. It delegates the call to the presenter to do some IO, which
|
||||
* will call [onShareImageResult] with the path the image was saved on when it's ready.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActionBar
|
||||
import android.graphics.PointF
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.view.GestureDetector
|
||||
|
@ -99,9 +100,28 @@ class PagerPageHolder(
|
|||
*/
|
||||
private var readImageHeaderSubscription: Subscription? = null
|
||||
|
||||
private var visibilityListener = ActionBar.OnMenuVisibilityListener { isVisible ->
|
||||
if (isVisible.not()) {
|
||||
subsamplingImageView?.setOnStateChangedListener(null)
|
||||
return@OnMenuVisibilityListener
|
||||
}
|
||||
subsamplingImageView?.setOnStateChangedListener(
|
||||
object : SubsamplingScaleImageView.OnStateChangedListener {
|
||||
override fun onScaleChanged(newScale: Float, origin: Int) {
|
||||
viewer.activity.hideMenu()
|
||||
}
|
||||
|
||||
override fun onCenterChanged(newCenter: PointF?, origin: Int) {
|
||||
viewer.activity.hideMenu()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
addView(progressIndicator)
|
||||
observeStatus()
|
||||
viewer.activity.addOnMenuVisibilityListener(visibilityListener)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,6 +134,8 @@ class PagerPageHolder(
|
|||
unsubscribeStatus()
|
||||
unsubscribeReadImageHeader()
|
||||
subsamplingImageView?.setOnImageEventListener(null)
|
||||
subsamplingImageView?.setOnStateChangedListener(null)
|
||||
viewer.activity.removeOnMenuVisibilityListener(visibilityListener)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -153,6 +153,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
|||
* Called when a new page (either a [ReaderPage] or [ChapterTransition]) is marked as active
|
||||
*/
|
||||
private fun onPageChange(position: Int) {
|
||||
activity.hideMenu()
|
||||
val page = adapter.items.getOrNull(position)
|
||||
if (page != null && currentPage != page) {
|
||||
val allowPreload = checkAllowPreload(page as? ReaderPage)
|
||||
|
|
|
@ -243,6 +243,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||
}
|
||||
|
||||
fun onScrolled(pos: Int? = null) {
|
||||
activity.hideMenu()
|
||||
val position = pos ?: layoutManager.findLastEndVisibleItemPosition()
|
||||
val item = adapter.items.getOrNull(position)
|
||||
val allowPreload = checkAllowPreload(item as? ReaderPage)
|
||||
|
|
|
@ -65,7 +65,6 @@ class SettingsBackupController : SettingsController() {
|
|||
onClick {
|
||||
if (MiuiUtil.isMiui() && MiuiUtil.isMiuiOptimizationDisabled()) {
|
||||
context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG)
|
||||
return@onClick
|
||||
}
|
||||
|
||||
if (!BackupCreateService.isRunning(context)) {
|
||||
|
@ -85,7 +84,6 @@ class SettingsBackupController : SettingsController() {
|
|||
onClick {
|
||||
if (MiuiUtil.isMiui() && MiuiUtil.isMiuiOptimizationDisabled()) {
|
||||
context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG)
|
||||
return@onClick
|
||||
}
|
||||
|
||||
if (!BackupRestoreService.isRunning(context)) {
|
||||
|
|
|
@ -269,8 +269,8 @@ class SettingsDownloadController : SettingsController() {
|
|||
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.categories)
|
||||
.setMessage(R.string.pref_download_new_categories_details)
|
||||
.setQuadStateMultiChoiceItems(
|
||||
message = R.string.pref_download_new_categories_details,
|
||||
items = items,
|
||||
initialSelected = selected
|
||||
) { selections ->
|
||||
|
|
|
@ -112,11 +112,6 @@ class SettingsGeneralController : SettingsController() {
|
|||
}
|
||||
|
||||
summary = "%s"
|
||||
|
||||
onChange {
|
||||
activity?.recreate()
|
||||
true
|
||||
}
|
||||
}
|
||||
listPreference {
|
||||
key = Keys.appTheme
|
||||
|
|
|
@ -358,8 +358,11 @@ class SettingsLibraryController : SettingsController() {
|
|||
|
||||
return MaterialAlertDialogBuilder(activity!!)
|
||||
.setTitle(R.string.categories)
|
||||
.setMessage(R.string.pref_library_update_categories_details)
|
||||
.setQuadStateMultiChoiceItems(items = items, initialSelected = selected) { selections ->
|
||||
.setQuadStateMultiChoiceItems(
|
||||
message = R.string.pref_library_update_categories_details,
|
||||
items = items,
|
||||
initialSelected = selected
|
||||
) { selections ->
|
||||
selected = selections
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
|
|
|
@ -111,10 +111,6 @@ fun syncChaptersWithSource(
|
|||
db.updateNextUpdated(manga).executeAsBlocking()
|
||||
}
|
||||
|
||||
if (newestDate != 0L && newestDate != manga.last_update) {
|
||||
manga.last_update = newestDate
|
||||
db.updateLastUpdated(manga).executeAsBlocking()
|
||||
}
|
||||
return Pair(emptyList(), emptyList())
|
||||
}
|
||||
|
||||
|
@ -177,13 +173,8 @@ fun syncChaptersWithSource(
|
|||
db.fixChaptersSourceOrder(sourceChapters).executeAsBlocking()
|
||||
|
||||
// Set this manga as updated since chapters were changed
|
||||
val newestChapter = topChapters.getOrNull(0)
|
||||
val dateFetch = newestChapter?.date_upload ?: manga.last_update
|
||||
if (dateFetch == 0L) {
|
||||
if (toAdd.isNotEmpty()) {
|
||||
manga.last_update = Date().time
|
||||
}
|
||||
} else manga.last_update = dateFetch
|
||||
// Note that last_update actually represents last time the chapter list changed at all
|
||||
manga.last_update = Date().time
|
||||
db.updateLastUpdated(manga).executeAsBlocking()
|
||||
}
|
||||
|
||||
|
|
|
@ -111,10 +111,6 @@ fun syncEpisodesWithSource(
|
|||
db.updateNextUpdated(anime).executeAsBlocking()
|
||||
}
|
||||
|
||||
if (newestDate != 0L && newestDate != anime.last_update) {
|
||||
anime.last_update = newestDate
|
||||
db.updateLastUpdated(anime).executeAsBlocking()
|
||||
}
|
||||
return Pair(emptyList(), emptyList())
|
||||
}
|
||||
|
||||
|
@ -176,13 +172,8 @@ fun syncEpisodesWithSource(
|
|||
db.fixEpisodesSourceOrder(sourceEpisodes).executeAsBlocking()
|
||||
|
||||
// Set this anime as updated since episodes were changed
|
||||
val newestEpisode = topEpisodes.getOrNull(0)
|
||||
val dateFetch = newestEpisode?.date_upload ?: anime.last_update
|
||||
if (dateFetch == 0L) {
|
||||
if (toAdd.isNotEmpty()) {
|
||||
anime.last_update = Date().time
|
||||
}
|
||||
} else anime.last_update = dateFetch
|
||||
// Note that last_update actually represents last time the chapter list changed at all
|
||||
anime.last_update = Date().time
|
||||
db.updateLastUpdated(anime).executeAsBlocking()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
fun Uri.toShareIntent(type: String = "image/*"): Intent {
|
||||
fun Uri.toShareIntent(context: Context, type: String = "image/*"): Intent {
|
||||
val uri = this
|
||||
return Intent(Intent.ACTION_SEND).apply {
|
||||
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
clipData = ClipData.newRawUri(null, uri)
|
||||
setType(type)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
|
||||
return Intent.createChooser(shareIntent, context.getString(R.string.action_share)).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.widget.materialdialogs
|
|||
import android.view.LayoutInflater
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
@ -36,6 +38,7 @@ fun MaterialAlertDialogBuilder.setTextInput(
|
|||
* @see eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView
|
||||
*/
|
||||
fun MaterialAlertDialogBuilder.setQuadStateMultiChoiceItems(
|
||||
@StringRes message: Int? = null,
|
||||
items: List<CharSequence>,
|
||||
initialSelected: IntArray,
|
||||
disabledIndices: IntArray? = null,
|
||||
|
@ -49,6 +52,20 @@ fun MaterialAlertDialogBuilder.setQuadStateMultiChoiceItems(
|
|||
initialSelected = initialSelected,
|
||||
listener = selection
|
||||
)
|
||||
setView(binding.root)
|
||||
return this
|
||||
val updateScrollIndicators = {
|
||||
binding.scrollIndicatorUp.isVisible = binding.list.canScrollVertically(-1)
|
||||
binding.scrollIndicatorDown.isVisible = binding.list.canScrollVertically(1)
|
||||
}
|
||||
binding.list.setOnScrollChangeListener { _, _, _, _, _ ->
|
||||
updateScrollIndicators()
|
||||
}
|
||||
binding.list.post {
|
||||
updateScrollIndicators()
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
binding.message.setText(message)
|
||||
binding.message.isVisible = true
|
||||
}
|
||||
return setView(binding.root)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:scrollIndicators="none"
|
||||
tools:listitem="@layout/dialog_quadstatemultichoice_item" />
|
||||
android:orientation="vertical"
|
||||
android:minHeight="48dp">
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/abc_dialog_title_divider_material" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/message"
|
||||
style="?attr/materialAlertDialogBodyTextStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/abc_dialog_title_divider_material"
|
||||
android:paddingHorizontal="?attr/dialogPreferredPadding"
|
||||
android:visibility="gone"
|
||||
tools:text="Dialog Message for quad-state dialog"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:id="@+id/scrollIndicatorUp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollIndicators="none"
|
||||
tools:listitem="@layout/dialog_quadstatemultichoice_item" />
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:id="@+id/scrollIndicatorDown"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -424,7 +424,7 @@
|
|||
|
||||
<!-- Tracking section -->
|
||||
<string name="tracking_guide">Tracking guide</string>
|
||||
<string name="pref_auto_update_manga_sync">Update chapter progress after reading</string>
|
||||
<string name="pref_auto_update_manga_sync">Update progress after reading</string>
|
||||
<string name="services">Services</string>
|
||||
<string name="tracking_info">One-way sync to update the chapter progress in tracking services. Set up tracking for individual manga entries from their tracking button.</string>
|
||||
<string name="enhanced_services">Enhanced services</string>
|
||||
|
@ -464,7 +464,7 @@
|
|||
<string name="backup_choice">What do you want to backup?</string>
|
||||
<string name="creating_backup">Creating backup</string>
|
||||
<string name="creating_backup_error">Backup failed</string>
|
||||
<string name="restore_miui_warning">MIUI Optimization must be enabled for backup/restore to work correctly.</string>
|
||||
<string name="restore_miui_warning">Backup/restore may not function properly if MIUI Optimization is disabled.</string>
|
||||
<string name="restore_in_progress">Restore is already in progress</string>
|
||||
<string name="restoring_backup">Restoring backup</string>
|
||||
<string name="restoring_backup_error">Restoring backup failed</string>
|
||||
|
|
Loading…
Reference in a new issue