mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2025-01-23 17:51:13 +01:00
Added Source Migration to browse section
Don't ask me how I did it.
This commit is contained in:
parent
90a6543334
commit
d6b07b7f40
@ -1,19 +1,33 @@
|
|||||||
package eu.kanade.tachiyomi.ui.extension
|
package eu.kanade.tachiyomi.ui.extension
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionsChangedListener
|
import eu.kanade.tachiyomi.extension.ExtensionsChangedListener
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||||
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.MangaItem
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.SelectionHeader
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.SourceItem
|
||||||
|
import eu.kanade.tachiyomi.util.lang.combineLatest
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
|
import eu.kanade.tachiyomi.util.system.executeOnIO
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -32,23 +46,64 @@ class ExtensionBottomPresenter(
|
|||||||
|
|
||||||
private var extensions = emptyList<ExtensionItem>()
|
private var extensions = emptyList<ExtensionItem>()
|
||||||
|
|
||||||
|
var sourceItems = emptyList<SourceItem>()
|
||||||
|
private set
|
||||||
|
|
||||||
|
var mangaItems = hashMapOf<Long, List<MangaItem>>()
|
||||||
|
private set
|
||||||
|
|
||||||
private var currentDownloads = hashMapOf<String, InstallStep>()
|
private var currentDownloads = hashMapOf<String, InstallStep>()
|
||||||
|
|
||||||
|
private val sourceManager: SourceManager = Injekt.get()
|
||||||
|
|
||||||
|
private var selectedSource: Long? = null
|
||||||
|
private val db: DatabaseHelper = Injekt.get()
|
||||||
|
|
||||||
fun onCreate() {
|
fun onCreate() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
extensionManager.findAvailableExtensionsAsync()
|
val extensionJob = async {
|
||||||
extensions = toItems(
|
extensionManager.findAvailableExtensionsAsync()
|
||||||
Triple(
|
extensions = toItems(
|
||||||
extensionManager.installedExtensions,
|
Triple(
|
||||||
extensionManager.untrustedExtensions,
|
extensionManager.installedExtensions,
|
||||||
extensionManager.availableExtensions
|
extensionManager.untrustedExtensions,
|
||||||
|
extensionManager.availableExtensions
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
withContext(Dispatchers.Main) { bottomSheet.setExtensions(extensions) }
|
||||||
withContext(Dispatchers.Main) { bottomSheet.setExtensions(extensions) }
|
extensionManager.setListener(this@ExtensionBottomPresenter)
|
||||||
extensionManager.setListener(this@ExtensionBottomPresenter)
|
}
|
||||||
|
val migrationJob = async {
|
||||||
|
val favs = db.getFavoriteMangas().executeOnIO()
|
||||||
|
sourceItems = findSourcesWithManga(favs)
|
||||||
|
mangaItems = HashMap(sourceItems.associate {
|
||||||
|
it.source.id to this@ExtensionBottomPresenter.libraryToMigrationItem(favs, it.source.id)
|
||||||
|
})
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
if (selectedSource != null) {
|
||||||
|
bottomSheet.setMigrationManga(mangaItems[selectedSource])
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bottomSheet.setMigrationSources(sourceItems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listOf(migrationJob, extensionJob).awaitAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> {
|
||||||
|
val header = SelectionHeader()
|
||||||
|
return library.map { it.source }.toSet()
|
||||||
|
.mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null }
|
||||||
|
.sortedBy { it.name }
|
||||||
|
.map { SourceItem(it, header) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun libraryToMigrationItem(library: List<Manga>, sourceId: Long): List<MangaItem> {
|
||||||
|
return library.filter { it.source == sourceId }.map(::MangaItem)
|
||||||
|
}
|
||||||
|
|
||||||
fun onDestroy() {
|
fun onDestroy() {
|
||||||
extensionManager.removeListener(this)
|
extensionManager.removeListener(this)
|
||||||
}
|
}
|
||||||
@ -66,6 +121,24 @@ class ExtensionBottomPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun refreshMigrations() {
|
||||||
|
scope.launch {
|
||||||
|
val favs = db.getFavoriteMangas().executeOnIO()
|
||||||
|
sourceItems = findSourcesWithManga(favs)
|
||||||
|
mangaItems = HashMap(sourceItems.associate {
|
||||||
|
it.source.id to this@ExtensionBottomPresenter.libraryToMigrationItem(favs, it.source.id)
|
||||||
|
})
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
if (selectedSource != null) {
|
||||||
|
bottomSheet.setMigrationManga(mangaItems[selectedSource])
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bottomSheet.setMigrationSources(sourceItems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun extensionsUpdated() {
|
override fun extensionsUpdated() {
|
||||||
refreshExtensions()
|
refreshExtensions()
|
||||||
}
|
}
|
||||||
@ -166,4 +239,18 @@ class ExtensionBottomPresenter(
|
|||||||
fun trustSignature(signatureHash: String) {
|
fun trustSignature(signatureHash: String) {
|
||||||
extensionManager.trustSignature(signatureHash)
|
extensionManager.trustSignature(signatureHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setSelectedSource(source: Source) {
|
||||||
|
selectedSource = source.id
|
||||||
|
scope.launch {
|
||||||
|
withContext(Dispatchers.Main) { bottomSheet.setMigrationManga(mangaItems[source.id]) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deselectSource() {
|
||||||
|
selectedSource = null
|
||||||
|
scope.launch {
|
||||||
|
withContext(Dispatchers.Main) { bottomSheet.setMigrationSources(sourceItems) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,33 @@ package eu.kanade.tachiyomi.ui.extension
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import androidx.core.view.get
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.MangaAdapter
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.MangaItem
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.SourceAdapter
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.SourceItem
|
||||||
|
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
|
||||||
|
import eu.kanade.tachiyomi.ui.recents.RecentMangaHolder
|
||||||
import eu.kanade.tachiyomi.ui.source.SourceController
|
import eu.kanade.tachiyomi.ui.source.SourceController
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.await
|
||||||
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.view.collapse
|
import eu.kanade.tachiyomi.util.view.collapse
|
||||||
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||||
import eu.kanade.tachiyomi.util.view.expand
|
import eu.kanade.tachiyomi.util.view.expand
|
||||||
@ -19,15 +36,25 @@ import eu.kanade.tachiyomi.util.view.isExpanded
|
|||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||||
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||||
import kotlinx.android.synthetic.main.extensions_bottom_sheet.view.*
|
import kotlinx.android.synthetic.main.extensions_bottom_sheet.view.*
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
|
import kotlinx.android.synthetic.main.migration_controller.*
|
||||||
|
import kotlinx.android.synthetic.main.recents_controller.*
|
||||||
|
import kotlinx.android.synthetic.main.recycler_with_scroller.view.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
LinearLayout(context, attrs),
|
LinearLayout(context, attrs),
|
||||||
ExtensionAdapter.OnButtonClickListener,
|
ExtensionAdapter.OnButtonClickListener,
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
FlexibleAdapter.OnItemLongClickListener,
|
||||||
ExtensionTrustDialog.Listener {
|
ExtensionTrustDialog.Listener,
|
||||||
|
SourceAdapter.OnAllClickListener {
|
||||||
|
|
||||||
var sheetBehavior: BottomSheetBehavior<*>? = null
|
var sheetBehavior: BottomSheetBehavior<*>? = null
|
||||||
|
|
||||||
@ -37,28 +64,79 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
|||||||
* Adapter containing the list of extensions
|
* Adapter containing the list of extensions
|
||||||
*/
|
*/
|
||||||
private var adapter: FlexibleAdapter<IFlexible<*>>? = null
|
private var adapter: FlexibleAdapter<IFlexible<*>>? = null
|
||||||
|
private var migAdapter: FlexibleAdapter<IFlexible<*>>? = null
|
||||||
|
|
||||||
val presenter = ExtensionBottomPresenter(this)
|
val presenter = ExtensionBottomPresenter(this)
|
||||||
|
|
||||||
private var extensions: List<ExtensionItem> = emptyList()
|
private var extensions: List<ExtensionItem> = emptyList()
|
||||||
|
var canExpand = false
|
||||||
|
|
||||||
lateinit var controller: SourceController
|
lateinit var controller: SourceController
|
||||||
|
|
||||||
|
private val pAdapter = FlexibleAdapter<IFlexible<*>>(null, this, true)
|
||||||
|
|
||||||
|
val extensionFrameLayout =
|
||||||
|
inflate(context, R.layout.recycler_with_scroller, null) as FrameLayout
|
||||||
|
val migrationFrameLayout =
|
||||||
|
inflate(context, R.layout.recycler_with_scroller, null) as FrameLayout
|
||||||
|
|
||||||
fun onCreate(controller: SourceController) {
|
fun onCreate(controller: SourceController) {
|
||||||
// Initialize adapter, scroll listener and recycler views
|
// Initialize adapter, scroll listener and recycler views
|
||||||
adapter = ExtensionAdapter(this)
|
adapter = ExtensionAdapter(this)
|
||||||
|
migAdapter = ExtensionAdapter(this)
|
||||||
sheetBehavior = BottomSheetBehavior.from(this)
|
sheetBehavior = BottomSheetBehavior.from(this)
|
||||||
// Create recycler and set adapter.
|
// Create recycler and set adapter.
|
||||||
ext_recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
|
val extRecyler = extensionFrameLayout.recycler
|
||||||
ext_recycler.adapter = adapter
|
val migRecyler = migrationFrameLayout.recycler
|
||||||
ext_recycler.setHasFixedSize(true)
|
|
||||||
ext_recycler.addItemDecoration(ExtensionDividerItemDecoration(context))
|
extRecyler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
|
||||||
adapter?.fastScroller = fast_scroller
|
extRecyler.adapter = adapter
|
||||||
|
extRecyler.setHasFixedSize(true)
|
||||||
|
extRecyler.addItemDecoration(ExtensionDividerItemDecoration(context))
|
||||||
|
|
||||||
|
migRecyler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
|
||||||
|
migRecyler.setHasFixedSize(true)
|
||||||
|
|
||||||
|
adapter?.fastScroller = extensionFrameLayout.fast_scroller
|
||||||
this.controller = controller
|
this.controller = controller
|
||||||
ext_recycler.doOnApplyWindowInsets { view, _, _ ->
|
pager.doOnApplyWindowInsets { _, _, _ ->
|
||||||
val bottomBar = (this@ExtensionBottomSheet.controller.activity as? MainActivity)?.bottom_nav
|
val bottomBar =
|
||||||
view.updatePaddingRelative(bottom = bottomBar?.height ?: 0)
|
(this@ExtensionBottomSheet.controller.activity as? MainActivity)?.bottom_nav
|
||||||
|
extRecyler.updatePaddingRelative(bottom = bottomBar?.height ?: 0)
|
||||||
|
migRecyler.updatePaddingRelative(bottom = bottomBar?.height ?: 0)
|
||||||
}
|
}
|
||||||
|
pager.adapter = TabbedSheetAdapter()
|
||||||
|
tabs.setupWithViewPager(pager)
|
||||||
|
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||||
|
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||||
|
if (canExpand) {
|
||||||
|
this@ExtensionBottomSheet.sheetBehavior?.expand()
|
||||||
|
}
|
||||||
|
this@ExtensionBottomSheet.controller.updateTitleAndMenu()
|
||||||
|
when (tab?.position) {
|
||||||
|
0 -> extensionFrameLayout
|
||||||
|
else -> migrationFrameLayout
|
||||||
|
}.recycler?.isNestedScrollingEnabled = true
|
||||||
|
when (tab?.position) {
|
||||||
|
0 -> extensionFrameLayout
|
||||||
|
else -> migrationFrameLayout
|
||||||
|
}.recycler?.requestLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||||
|
when (tab?.position) {
|
||||||
|
0 -> extensionFrameLayout
|
||||||
|
else -> migrationFrameLayout
|
||||||
|
}.recycler?.isNestedScrollingEnabled = false
|
||||||
|
}
|
||||||
|
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||||
|
this@ExtensionBottomSheet.sheetBehavior?.expand()
|
||||||
|
when (tab?.position) {
|
||||||
|
0 -> extensionFrameLayout
|
||||||
|
else -> migrationFrameLayout
|
||||||
|
}.recycler?.isNestedScrollingEnabled = true
|
||||||
|
}
|
||||||
|
})
|
||||||
presenter.onCreate()
|
presenter.onCreate()
|
||||||
updateExtTitle()
|
updateExtTitle()
|
||||||
|
|
||||||
@ -66,12 +144,6 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
|||||||
val array = context.obtainStyledAttributes(attrsArray)
|
val array = context.obtainStyledAttributes(attrsArray)
|
||||||
val headerHeight = array.getDimensionPixelSize(0, 0)
|
val headerHeight = array.getDimensionPixelSize(0, 0)
|
||||||
array.recycle()
|
array.recycle()
|
||||||
ext_recycler_layout.doOnApplyWindowInsets { v, windowInsets, _ ->
|
|
||||||
v.updateLayoutParams<MarginLayoutParams> {
|
|
||||||
topMargin = windowInsets.systemWindowInsetTop + headerHeight -
|
|
||||||
(sheet_layout.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sheet_layout.setOnClickListener {
|
sheet_layout.setOnClickListener {
|
||||||
if (!sheetBehavior.isExpanded()) {
|
if (!sheetBehavior.isExpanded()) {
|
||||||
sheetBehavior?.expand()
|
sheetBehavior?.expand()
|
||||||
@ -92,18 +164,8 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
|||||||
|
|
||||||
fun updateExtTitle() {
|
fun updateExtTitle() {
|
||||||
val extCount = presenter.getExtensionUpdateCount()
|
val extCount = presenter.getExtensionUpdateCount()
|
||||||
title_text.text = if (extCount == 0) context.getString(R.string.extensions)
|
if (extCount > 0) tabs.getTabAt(0)?.orCreateBadge?.number = extCount
|
||||||
else resources.getQuantityString(
|
else tabs.getTabAt(0)?.removeBadge()
|
||||||
R.plurals.extension_updates_available,
|
|
||||||
extCount,
|
|
||||||
extCount
|
|
||||||
)
|
|
||||||
|
|
||||||
title_text.setTextColor(
|
|
||||||
context.getResourceColor(
|
|
||||||
if (extCount == 0) R.attr.actionBarTintColor else R.attr.colorAccent
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onButtonClick(position: Int) {
|
override fun onButtonClick(position: Int) {
|
||||||
@ -126,23 +188,55 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClick(view: View?, position: Int): Boolean {
|
override fun onItemClick(view: View?, position: Int): Boolean {
|
||||||
val extension = (adapter?.getItem(position) as? ExtensionItem)?.extension ?: return false
|
when (tabs.selectedTabPosition) {
|
||||||
if (extension is Extension.Installed) {
|
0 -> {
|
||||||
openDetails(extension)
|
val extension =
|
||||||
} else if (extension is Extension.Untrusted) {
|
(adapter?.getItem(position) as? ExtensionItem)?.extension ?: return false
|
||||||
openTrustDialog(extension)
|
if (extension is Extension.Installed) {
|
||||||
}
|
openDetails(extension)
|
||||||
|
} else if (extension is Extension.Untrusted) {
|
||||||
|
openTrustDialog(extension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val item = migAdapter?.getItem(position) ?: return false
|
||||||
|
|
||||||
|
if (item is MangaItem) {
|
||||||
|
PreMigrationController.navigateToMigration(
|
||||||
|
Injekt.get<PreferencesHelper>().skipPreMigration().getOrDefault(),
|
||||||
|
controller.router,
|
||||||
|
listOf(item.manga.id!!)
|
||||||
|
)
|
||||||
|
} else if (item is SourceItem) {
|
||||||
|
presenter.setSelectedSource(item.source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemLongClick(position: Int) {
|
override fun onItemLongClick(position: Int) {
|
||||||
val extension = (adapter?.getItem(position) as? ExtensionItem)?.extension ?: return
|
if (tabs.selectedTabPosition == 0) {
|
||||||
if (extension is Extension.Installed || extension is Extension.Untrusted) {
|
val extension = (adapter?.getItem(position) as? ExtensionItem)?.extension ?: return
|
||||||
uninstallExtension(extension.pkgName)
|
if (extension is Extension.Installed || extension is Extension.Untrusted) {
|
||||||
|
uninstallExtension(extension.pkgName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAllClick(position: Int) {
|
||||||
|
val item = migAdapter?.getItem(position) as? SourceItem ?: return
|
||||||
|
|
||||||
|
val sourceMangas =
|
||||||
|
presenter.mangaItems[item.source.id]?.mapNotNull { it.manga.id }?.toList()
|
||||||
|
?: emptyList()
|
||||||
|
PreMigrationController.navigateToMigration(
|
||||||
|
Injekt.get<PreferencesHelper>().skipPreMigration().getOrDefault(),
|
||||||
|
controller.router,
|
||||||
|
sourceMangas
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun openDetails(extension: Extension.Installed) {
|
private fun openDetails(extension: Extension.Installed) {
|
||||||
val controller = ExtensionDetailsController(extension.pkgName)
|
val controller = ExtensionDetailsController(extension.pkgName)
|
||||||
this.controller.router.pushController(controller.withFadeTransaction())
|
this.controller.router.pushController(controller.withFadeTransaction())
|
||||||
@ -159,8 +253,28 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
|||||||
drawExtensions()
|
drawExtensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setMigrationSources(sources: List<SourceItem>) {
|
||||||
|
val migRecyler = migrationFrameLayout.recycler
|
||||||
|
if (migAdapter !is SourceAdapter) {
|
||||||
|
migAdapter = SourceAdapter(this)
|
||||||
|
migRecyler.adapter = migAdapter
|
||||||
|
migAdapter?.fastScroller = migrationFrameLayout.fast_scroller
|
||||||
|
}
|
||||||
|
migAdapter?.updateDataSet(sources)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMigrationManga(manga: List<MangaItem>?) {
|
||||||
|
val migRecyler = migrationFrameLayout.recycler
|
||||||
|
if (migAdapter !is MangaAdapter) {
|
||||||
|
migAdapter = MangaAdapter(this)
|
||||||
|
migRecyler.adapter = migAdapter
|
||||||
|
migAdapter?.fastScroller = migrationFrameLayout.fast_scroller
|
||||||
|
}
|
||||||
|
migAdapter?.updateDataSet(manga)
|
||||||
|
}
|
||||||
|
|
||||||
fun drawExtensions() {
|
fun drawExtensions() {
|
||||||
if (!controller.extQuery.isBlank()) {
|
if (controller.extQuery.isNotBlank()) {
|
||||||
adapter?.updateDataSet(
|
adapter?.updateDataSet(
|
||||||
extensions.filter {
|
extensions.filter {
|
||||||
it.extension.name.contains(controller.extQuery, ignoreCase = true)
|
it.extension.name.contains(controller.extQuery, ignoreCase = true)
|
||||||
@ -172,6 +286,14 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
|||||||
updateExtTitle()
|
updateExtTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun canGoBack(): Boolean {
|
||||||
|
if (tabs.selectedTabPosition == 1 && migAdapter is MangaAdapter) {
|
||||||
|
presenter.deselectSource()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fun downloadUpdate(item: ExtensionItem) {
|
fun downloadUpdate(item: ExtensionItem) {
|
||||||
adapter?.updateItem(item, item.installStep)
|
adapter?.updateItem(item, item.installStep)
|
||||||
}
|
}
|
||||||
@ -183,4 +305,25 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
|||||||
override fun uninstallExtension(pkgName: String) {
|
override fun uninstallExtension(pkgName: String) {
|
||||||
presenter.uninstallExtension(pkgName)
|
presenter.uninstallExtension(pkgName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class TabbedSheetAdapter : ViewPagerAdapter() {
|
||||||
|
|
||||||
|
override fun createView(container: ViewGroup, position: Int): View {
|
||||||
|
return when (position) {
|
||||||
|
0 -> extensionFrameLayout
|
||||||
|
else -> migrationFrameLayout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCount(): Int {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
|
return context.getString(when (position) {
|
||||||
|
0 -> R.string.extensions
|
||||||
|
else -> R.string.migration
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.migration
|
|||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
|
||||||
class MangaAdapter(controller: MigrationController) :
|
class MangaAdapter(listener: Any) :
|
||||||
FlexibleAdapter<IFlexible<*>>(null, controller) {
|
FlexibleAdapter<IFlexible<*>>(null, listener) {
|
||||||
|
|
||||||
private var items: List<IFlexible<*>>? = null
|
private var items: List<IFlexible<*>>? = null
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ import eu.davidea.flexibleadapter.items.IFlexible
|
|||||||
*
|
*
|
||||||
* @param controller instance of [MigrationController].
|
* @param controller instance of [MigrationController].
|
||||||
*/
|
*/
|
||||||
class SourceAdapter(val controller: MigrationController) :
|
class SourceAdapter(val allClickListener: OnAllClickListener) :
|
||||||
FlexibleAdapter<IFlexible<*>>(null, controller, true) {
|
FlexibleAdapter<IFlexible<*>>(null, allClickListener, true) {
|
||||||
|
|
||||||
private var items: List<IFlexible<*>>? = null
|
private var items: List<IFlexible<*>>? = null
|
||||||
|
|
||||||
@ -17,11 +17,6 @@ class SourceAdapter(val controller: MigrationController) :
|
|||||||
setDisplayHeadersAtStartUp(true)
|
setDisplayHeadersAtStartUp(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for auto item clicks.
|
|
||||||
*/
|
|
||||||
val allClickListener: OnAllClickListener? = controller
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener which should be called when user clicks select.
|
* Listener which should be called when user clicks select.
|
||||||
*/
|
*/
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.source
|
|||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
@ -10,6 +11,8 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.ColorUtils
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
@ -29,12 +32,15 @@ import eu.kanade.tachiyomi.ui.extension.SettingsExtensionsController
|
|||||||
import eu.kanade.tachiyomi.ui.main.BottomSheetController
|
import eu.kanade.tachiyomi.ui.main.BottomSheetController
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.main.RootSearchInterface
|
import eu.kanade.tachiyomi.ui.main.RootSearchInterface
|
||||||
|
import eu.kanade.tachiyomi.ui.setting.SettingsBrowseController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
|
import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
|
||||||
import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
|
import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
|
||||||
import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController
|
import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController
|
||||||
import eu.kanade.tachiyomi.ui.source.latest.LatestUpdatesController
|
import eu.kanade.tachiyomi.ui.source.latest.LatestUpdatesController
|
||||||
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getBottomGestureInsets
|
import eu.kanade.tachiyomi.util.system.getBottomGestureInsets
|
||||||
import eu.kanade.tachiyomi.util.system.spToPx
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
import eu.kanade.tachiyomi.util.view.collapse
|
import eu.kanade.tachiyomi.util.view.collapse
|
||||||
import eu.kanade.tachiyomi.util.view.expand
|
import eu.kanade.tachiyomi.util.view.expand
|
||||||
import eu.kanade.tachiyomi.util.view.isCollapsed
|
import eu.kanade.tachiyomi.util.view.isCollapsed
|
||||||
@ -48,17 +54,20 @@ import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
|||||||
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.extensions_bottom_sheet.*
|
import kotlinx.android.synthetic.main.extensions_bottom_sheet.*
|
||||||
|
import kotlinx.android.synthetic.main.extensions_bottom_sheet.ext_bottom_sheet
|
||||||
import kotlinx.android.synthetic.main.extensions_bottom_sheet.sheet_layout
|
import kotlinx.android.synthetic.main.extensions_bottom_sheet.sheet_layout
|
||||||
import kotlinx.android.synthetic.main.extensions_bottom_sheet.view.*
|
import kotlinx.android.synthetic.main.extensions_bottom_sheet.view.*
|
||||||
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
|
||||||
import kotlinx.android.synthetic.main.library_list_controller.*
|
import kotlinx.android.synthetic.main.library_list_controller.*
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
|
import kotlinx.android.synthetic.main.recycler_with_scroller.view.*
|
||||||
import kotlinx.android.synthetic.main.rounded_category_hopper.*
|
import kotlinx.android.synthetic.main.rounded_category_hopper.*
|
||||||
import kotlinx.android.synthetic.main.source_controller.*
|
import kotlinx.android.synthetic.main.source_controller.*
|
||||||
import kotlinx.android.synthetic.main.source_controller.shadow2
|
import kotlinx.android.synthetic.main.source_controller.shadow2
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller shows and manages the different catalogues enabled by the user.
|
* This controller shows and manages the different catalogues enabled by the user.
|
||||||
@ -101,7 +110,12 @@ class SourceController :
|
|||||||
|
|
||||||
override fun getTitle(): String? {
|
override fun getTitle(): String? {
|
||||||
return if (showingExtensions)
|
return if (showingExtensions)
|
||||||
view?.context?.getString(R.string.extensions)
|
view?.context?.getString(
|
||||||
|
when (ext_bottom_sheet.tabs.selectedTabPosition) {
|
||||||
|
0 -> R.string.extensions
|
||||||
|
else -> R.string.source_migration
|
||||||
|
}
|
||||||
|
)
|
||||||
else view?.context?.getString(R.string.sources)
|
else view?.context?.getString(R.string.sources)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,6 +158,7 @@ class SourceController :
|
|||||||
|
|
||||||
recycler?.post {
|
recycler?.post {
|
||||||
setBottomPadding()
|
setBottomPadding()
|
||||||
|
setBottomSheetTabs(if (ext_bottom_sheet?.sheetBehavior.isCollapsed()) 0f else 1f)
|
||||||
}
|
}
|
||||||
recycler.addOnScrollListener(
|
recycler.addOnScrollListener(
|
||||||
object : RecyclerView.OnScrollListener() {
|
object : RecyclerView.OnScrollListener() {
|
||||||
@ -163,12 +178,10 @@ class SourceController :
|
|||||||
override fun onSlide(bottomSheet: View, progress: Float) {
|
override fun onSlide(bottomSheet: View, progress: Float) {
|
||||||
val recycler = recycler ?: return
|
val recycler = recycler ?: return
|
||||||
shadow2?.alpha = (1 - max(0f, progress)) * 0.25f
|
shadow2?.alpha = (1 - max(0f, progress)) * 0.25f
|
||||||
activity?.appbar?.elevation = max(
|
activity?.appbar?.elevation = min(
|
||||||
progress * 15f,
|
(1f - progress) * 15f,
|
||||||
if (recycler.canScrollVertically(-1)) 15f else 0f
|
if (recycler.canScrollVertically(-1)) 15f else 0f
|
||||||
)
|
)
|
||||||
|
|
||||||
sheet_layout?.alpha = 1 - progress
|
|
||||||
activity?.appbar?.y = max(activity!!.appbar.y, -headerHeight * (1 - progress))
|
activity?.appbar?.y = max(activity!!.appbar.y, -headerHeight * (1 - progress))
|
||||||
val oldShow = showingExtensions
|
val oldShow = showingExtensions
|
||||||
showingExtensions = progress > 0.92f
|
showingExtensions = progress > 0.92f
|
||||||
@ -176,9 +189,7 @@ class SourceController :
|
|||||||
setTitle()
|
setTitle()
|
||||||
activity?.invalidateOptionsMenu()
|
activity?.invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
val bottomBar = activity?.bottom_nav ?: return
|
setBottomSheetTabs(max(0f, progress))
|
||||||
val pad = bottomBar.translationY - bottomBar.height
|
|
||||||
ext_bottom_sheet.updatePaddingRelative(bottom = (pad * (1 - max(progress, 0f))).toInt())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStateChanged(p0: View, state: Int) {
|
override fun onStateChanged(p0: View, state: Int) {
|
||||||
@ -189,8 +200,6 @@ class SourceController :
|
|||||||
if (state == BottomSheetBehavior.STATE_EXPANDED ||
|
if (state == BottomSheetBehavior.STATE_EXPANDED ||
|
||||||
state == BottomSheetBehavior.STATE_COLLAPSED
|
state == BottomSheetBehavior.STATE_COLLAPSED
|
||||||
) {
|
) {
|
||||||
sheet_layout?.alpha =
|
|
||||||
if (state == BottomSheetBehavior.STATE_COLLAPSED) 1f else 0f
|
|
||||||
showingExtensions = state == BottomSheetBehavior.STATE_EXPANDED
|
showingExtensions = state == BottomSheetBehavior.STATE_EXPANDED
|
||||||
setTitle()
|
setTitle()
|
||||||
if (state == BottomSheetBehavior.STATE_EXPANDED)
|
if (state == BottomSheetBehavior.STATE_EXPANDED)
|
||||||
@ -203,6 +212,7 @@ class SourceController :
|
|||||||
RetainViewMode.RETAIN_DETACH else RetainViewMode.RELEASE_DETACH
|
RetainViewMode.RETAIN_DETACH else RetainViewMode.RELEASE_DETACH
|
||||||
sheet_layout.isClickable = state == BottomSheetBehavior.STATE_COLLAPSED
|
sheet_layout.isClickable = state == BottomSheetBehavior.STATE_COLLAPSED
|
||||||
sheet_layout.isFocusable = state == BottomSheetBehavior.STATE_COLLAPSED
|
sheet_layout.isFocusable = state == BottomSheetBehavior.STATE_COLLAPSED
|
||||||
|
setBottomSheetTabs(if (state == BottomSheetBehavior.STATE_COLLAPSED) 0f else 1f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -212,21 +222,73 @@ class SourceController :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setBottomPadding() {
|
fun updateTitleAndMenu() {
|
||||||
|
setTitle()
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBottomSheetTabs(progress: Float) {
|
||||||
|
val bottomSheet = ext_bottom_sheet ?: return
|
||||||
val bottomBar = activity?.bottom_nav ?: return
|
val bottomBar = activity?.bottom_nav ?: return
|
||||||
ext_bottom_sheet.updatePaddingRelative(
|
ext_bottom_sheet.tabs.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
bottom =
|
topMargin = ((activity?.appbar?.height?.minus(9f.dpToPx) ?: 0f) * progress).toInt()
|
||||||
if (ext_bottom_sheet.sheetBehavior.isExpanded()) 0 else
|
}
|
||||||
max(
|
val selectedColor = ColorUtils.setAlphaComponent(
|
||||||
(-bottomBar.translationY + bottomBar.height).toInt(),
|
ContextCompat.getColor(ext_bottom_sheet.tabs.context, R.color.colorAccent),
|
||||||
this@SourceController.view?.rootWindowInsets?.getBottomGestureInsets()
|
(progress * 255).toInt()
|
||||||
?: 0
|
)
|
||||||
)
|
val unselectedColor = ColorUtils.setAlphaComponent(
|
||||||
|
bottomSheet.context.getResourceColor(R.attr.colorOnBackground),
|
||||||
|
153
|
||||||
|
)
|
||||||
|
ext_bottom_sheet.sheet_layout.elevation = progress * 5
|
||||||
|
ext_bottom_sheet.pager.alpha = progress * 10
|
||||||
|
ext_bottom_sheet.tabs.setSelectedTabIndicatorColor(selectedColor)
|
||||||
|
ext_bottom_sheet.tabs.setTabTextColors(
|
||||||
|
ColorUtils.blendARGB(
|
||||||
|
bottomSheet.context.getResourceColor(R.attr.actionBarTintColor),
|
||||||
|
unselectedColor,
|
||||||
|
progress),
|
||||||
|
ColorUtils.blendARGB(
|
||||||
|
bottomSheet.context.getResourceColor(R.attr.actionBarTintColor),
|
||||||
|
selectedColor,
|
||||||
|
progress)
|
||||||
)
|
)
|
||||||
val pad = bottomBar.translationY - bottomBar.height
|
val pad = bottomBar.translationY - bottomBar.height
|
||||||
|
val padding = (max(
|
||||||
|
(-pad).toInt(),
|
||||||
|
this@SourceController.view?.rootWindowInsets?.getBottomGestureInsets() ?: 0
|
||||||
|
) * (1f - progress)).toInt()
|
||||||
|
ext_bottom_sheet.updatePaddingRelative(
|
||||||
|
bottom = padding
|
||||||
|
)
|
||||||
|
ext_bottom_sheet.sheet_layout.backgroundTintList = ColorStateList.valueOf(
|
||||||
|
ColorUtils.blendARGB(
|
||||||
|
bottomSheet.context.getResourceColor(R.attr.colorPrimaryVariant),
|
||||||
|
bottomSheet.context.getResourceColor(R.attr.colorSecondary),
|
||||||
|
progress)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBottomPadding() {
|
||||||
|
val bottomBar = activity?.bottom_nav ?: return
|
||||||
|
ext_bottom_sheet ?: return
|
||||||
|
val pad = bottomBar.translationY - bottomBar.height
|
||||||
|
val padding = max(
|
||||||
|
(-pad).toInt(),
|
||||||
|
if (ext_bottom_sheet.sheetBehavior.isExpanded()) 0 else
|
||||||
|
this@SourceController.view?.rootWindowInsets?.getBottomGestureInsets()
|
||||||
|
?: 0
|
||||||
|
)
|
||||||
|
ext_bottom_sheet.updatePaddingRelative(
|
||||||
|
bottom = padding
|
||||||
|
)
|
||||||
shadow2.translationY = pad
|
shadow2.translationY = pad
|
||||||
ext_bottom_sheet.sheetBehavior?.peekHeight = 48.spToPx + ext_bottom_sheet.paddingBottom
|
ext_bottom_sheet.sheetBehavior?.peekHeight = 60.dpToPx + padding
|
||||||
ext_bottom_sheet.fast_scroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
ext_bottom_sheet.extensionFrameLayout.fast_scroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
bottomMargin = -pad.toInt()
|
||||||
|
}
|
||||||
|
ext_bottom_sheet.migrationFrameLayout.fast_scroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
bottomMargin = -pad.toInt()
|
bottomMargin = -pad.toInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,7 +309,9 @@ class SourceController :
|
|||||||
|
|
||||||
override fun handleSheetBack(): Boolean {
|
override fun handleSheetBack(): Boolean {
|
||||||
if (!ext_bottom_sheet.sheetBehavior.isCollapsed()) {
|
if (!ext_bottom_sheet.sheetBehavior.isCollapsed()) {
|
||||||
ext_bottom_sheet.sheetBehavior?.collapse()
|
if (ext_bottom_sheet.canGoBack()) {
|
||||||
|
ext_bottom_sheet.sheetBehavior?.collapse()
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -265,6 +329,23 @@ class SourceController :
|
|||||||
ext_bottom_sheet.presenter.refreshExtensions()
|
ext_bottom_sheet.presenter.refreshExtensions()
|
||||||
}
|
}
|
||||||
if (!type.isEnter) {
|
if (!type.isEnter) {
|
||||||
|
ext_bottom_sheet.canExpand = false
|
||||||
|
activity?.appbar?.elevation =
|
||||||
|
when {
|
||||||
|
ext_bottom_sheet.sheetBehavior.isExpanded() -> 0f
|
||||||
|
recycler.canScrollVertically(-1) -> 15f
|
||||||
|
else -> 0f
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ext_bottom_sheet.presenter.refreshMigrations()
|
||||||
|
}
|
||||||
|
setBottomPadding()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||||
|
super.onChangeEnded(handler, type)
|
||||||
|
if (type.isEnter) {
|
||||||
|
ext_bottom_sheet.canExpand = true
|
||||||
setBottomPadding()
|
setBottomPadding()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,6 +353,8 @@ class SourceController :
|
|||||||
override fun onActivityResumed(activity: Activity) {
|
override fun onActivityResumed(activity: Activity) {
|
||||||
super.onActivityResumed(activity)
|
super.onActivityResumed(activity)
|
||||||
ext_bottom_sheet?.presenter?.refreshExtensions()
|
ext_bottom_sheet?.presenter?.refreshExtensions()
|
||||||
|
ext_bottom_sheet?.presenter?.refreshMigrations()
|
||||||
|
setBottomPadding()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClick(view: View, position: Int): Boolean {
|
override fun onItemClick(view: View, position: Int): Boolean {
|
||||||
@ -351,21 +434,25 @@ class SourceController :
|
|||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
if (onRoot) (activity as? MainActivity)?.setDismissIcon(showingExtensions)
|
if (onRoot) (activity as? MainActivity)?.setDismissIcon(showingExtensions)
|
||||||
if (showingExtensions) {
|
if (showingExtensions) {
|
||||||
// Inflate menu
|
if (ext_bottom_sheet.tabs.selectedTabPosition == 0) {
|
||||||
inflater.inflate(R.menu.extension_main, menu)
|
// Inflate menu
|
||||||
|
inflater.inflate(R.menu.extension_main, menu)
|
||||||
|
|
||||||
// Initialize search option.
|
// Initialize search option.
|
||||||
val searchItem = menu.findItem(R.id.action_search)
|
val searchItem = menu.findItem(R.id.action_search)
|
||||||
val searchView = searchItem.actionView as SearchView
|
val searchView = searchItem.actionView as SearchView
|
||||||
|
|
||||||
// Change hint to show global search.
|
// Change hint to show global search.
|
||||||
searchView.queryHint = view?.context?.getString(R.string.search_extensions)
|
searchView.queryHint = view?.context?.getString(R.string.search_extensions)
|
||||||
|
|
||||||
// Create query listener which opens the global search view.
|
// Create query listener which opens the global search view.
|
||||||
setOnQueryTextChangeListener(searchView) {
|
setOnQueryTextChangeListener(searchView) {
|
||||||
extQuery = it ?: ""
|
extQuery = it ?: ""
|
||||||
ext_bottom_sheet.drawExtensions()
|
ext_bottom_sheet.drawExtensions()
|
||||||
true
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inflater.inflate(R.menu.migration_main, menu)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Inflate menu
|
// Inflate menu
|
||||||
@ -410,6 +497,12 @@ class SourceController :
|
|||||||
).pushChangeHandler(FadeChangeHandler())
|
).pushChangeHandler(FadeChangeHandler())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
R.id.action_migration_guide -> {
|
||||||
|
activity?.openInBrowser(HELP_URL)
|
||||||
|
}
|
||||||
|
R.id.action_sources_settings -> {
|
||||||
|
router.pushController(SettingsBrowseController().withFadeTransaction())
|
||||||
|
}
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -437,4 +530,8 @@ class SourceController :
|
|||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class SmartSearchConfig(val origTitle: String, val origMangaId: Long) : Parcelable
|
data class SmartSearchConfig(val origTitle: String, val origMangaId: Long) : Parcelable
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val HELP_URL = "https://tachiyomi.org/help/guides/source-migration/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24.0"
|
android:tint="?attr/actionBarTintColor"
|
||||||
android:viewportHeight="24.0">
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M12,10.9c-0.61,0 -1.1,0.49 -1.1,1.1s0.49,1.1 1.1,1.1c0.61,0 1.1,-0.49 1.1,-1.1s-0.49,-1.1 -1.1,-1.1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM14.19,14.19L6,18l3.81,-8.19L18,6l-3.81,8.19z"/>
|
android:pathData="M12,10.9c-0.61,0 -1.1,0.49 -1.1,1.1s0.49,1.1 1.1,1.1c0.61,0 1.1,-0.49 1.1,-1.1s-0.49,-1.1 -1.1,-1.1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM14.19,14.19L6,18l3.81,-8.19L18,6l-3.81,8.19z"/>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<!-- drawable/pin.xml -->
|
<!-- drawable/pin.xml -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
android:tint="?attr/actionBarTintColor"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
android:background="@drawable/bottom_sheet_rounded_background"
|
android:background="@drawable/bottom_sheet_rounded_background"
|
||||||
android:backgroundTint="?android:attr/colorBackground"
|
android:backgroundTint="?android:attr/colorBackground"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:behavior_peekHeight="48sp"
|
app:behavior_peekHeight="60sp"
|
||||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -19,6 +19,7 @@
|
|||||||
android:background="@drawable/bottom_sheet_rounded_background"
|
android:background="@drawable/bottom_sheet_rounded_background"
|
||||||
android:backgroundTint="?attr/colorPrimaryVariant"
|
android:backgroundTint="?attr/colorPrimaryVariant"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:elevation="5dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@ -37,41 +38,25 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.tabs.TabLayout
|
||||||
android:id="@+id/title_text"
|
android:id="@+id/tabs"
|
||||||
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
|
style="@style/Theme.Widget.Tabs"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:background="@android:color/transparent"
|
||||||
android:layout_marginTop="6dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:layout_marginBottom="10dp"
|
app:layout_constraintEnd_toStartOf="@+id/menu"
|
||||||
android:ellipsize="end"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:gravity="center"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:maxLines="1"
|
app:tabTextColor="@color/tabs_selector_background"
|
||||||
android:textAlignment="center"
|
app:tabIndicatorColor="?attr/colorAccent"
|
||||||
android:textColor="?actionBarTintColor"
|
app:tabRippleColor="@color/rippleColor"
|
||||||
android:textSize="18sp"
|
app:tabGravity="fill"
|
||||||
tools:text="Extensions" />
|
app:tabMode="fixed" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<androidx.viewpager.widget.ViewPager
|
||||||
android:id="@+id/ext_recycler_layout"
|
android:id="@+id/pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/ext_recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?android:attr/colorBackground"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
tools:listitem="@layout/extension_card_header" />
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.ui.base.MaterialFastScroll
|
|
||||||
android:id="@+id/fast_scroller"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:fastScrollerBubbleEnabled="false" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
</eu.kanade.tachiyomi.ui.extension.ExtensionBottomSheet>
|
</eu.kanade.tachiyomi.ui.extension.ExtensionBottomSheet>
|
24
app/src/main/res/layout/recycler_with_scroller.xml
Normal file
24
app/src/main/res/layout/recycler_with_scroller.xml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/recycler_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:attr/colorBackground"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:nestedScrollingEnabled="false"
|
||||||
|
tools:listitem="@layout/extension_card_header" />
|
||||||
|
|
||||||
|
<eu.kanade.tachiyomi.ui.base.MaterialFastScroll
|
||||||
|
android:id="@+id/fast_scroller"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:fastScrollerBubbleEnabled="false" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
15
app/src/main/res/menu/migration_main.xml
Normal file
15
app/src/main/res/menu/migration_main.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sources_settings"
|
||||||
|
android:icon="@drawable/ic_tune_24dp"
|
||||||
|
android:title="@string/options"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_migration_guide"
|
||||||
|
android:title="@string/help"
|
||||||
|
android:icon="@drawable/ic_help_24dp"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
|
</menu>
|
@ -620,6 +620,7 @@
|
|||||||
<string name="migration_sources_changed">Migration sources changed</string>
|
<string name="migration_sources_changed">Migration sources changed</string>
|
||||||
<string name="you_can_migrate_in_library">You can also migrate by selecting manga in your
|
<string name="you_can_migrate_in_library">You can also migrate by selecting manga in your
|
||||||
library</string>
|
library</string>
|
||||||
|
<string name="source_migration_guide">Source migration guide</string>
|
||||||
|
|
||||||
<!-- About section -->
|
<!-- About section -->
|
||||||
<string name="version">Version</string>
|
<string name="version">Version</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user