Misc fixes
This commit is contained in:
@@ -16,7 +16,7 @@ android {
|
|||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode gitCommits
|
versionCode gitCommits
|
||||||
versionName '1.0-a1'
|
versionName '1.0-b1'
|
||||||
|
|
||||||
kapt {
|
kapt {
|
||||||
arguments {
|
arguments {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ abstract class BaseFullscreenActivity<B : ViewBinding> : BaseActivity<B>() {
|
|||||||
|
|
||||||
protected fun hideSystemUI() {
|
protected fun hideSystemUI() {
|
||||||
insetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars())
|
insetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun showSystemUI() {
|
protected fun showSystemUI() {
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import org.koitharu.kotatsu.R
|
|||||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||||
import org.koitharu.kotatsu.browser.BrowserActivity
|
import org.koitharu.kotatsu.browser.BrowserActivity
|
||||||
|
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog
|
||||||
|
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
import org.koitharu.kotatsu.core.model.MangaSource
|
import org.koitharu.kotatsu.core.model.MangaSource
|
||||||
import org.koitharu.kotatsu.databinding.ActivityDetailsBinding
|
import org.koitharu.kotatsu.databinding.ActivityDetailsBinding
|
||||||
@@ -71,12 +73,19 @@ class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onError(e: Throwable) {
|
private fun onError(e: Throwable) {
|
||||||
if (viewModel.manga.value == null) {
|
when {
|
||||||
Toast.makeText(this, e.getDisplayMessage(resources), Toast.LENGTH_LONG).show()
|
e is CloudFlareProtectedException -> {
|
||||||
finishAfterTransition()
|
CloudFlareDialog.newInstance(e.url)
|
||||||
} else {
|
.show(supportFragmentManager, CloudFlareDialog.TAG)
|
||||||
Snackbar.make(binding.pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG)
|
}
|
||||||
.show()
|
viewModel.manga.value == null -> {
|
||||||
|
Toast.makeText(this, e.getDisplayMessage(resources), Toast.LENGTH_LONG).show()
|
||||||
|
finishAfterTransition()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Snackbar.make(binding.pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ class FavouritesContainerFragment : BaseFragment<FragmentFavouritesBinding>(),
|
|||||||
|
|
||||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||||
super.onViewStateRestored(savedInstanceState)
|
super.onViewStateRestored(savedInstanceState)
|
||||||
(savedInstanceState?.getParcelable(KEY_ADAPTER_STATE) ?: adapterState)?.let {
|
// (savedInstanceState?.getParcelable(KEY_ADAPTER_STATE) ?: adapterState)?.let {
|
||||||
(binding.pager.adapter as FavouritesPagerAdapter).restoreState(it)
|
// (binding.pager.adapter as FavouritesPagerAdapter).restoreState(it)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class CategoriesEditDelegate(
|
|||||||
.setHint(R.string.enter_category_name)
|
.setHint(R.string.enter_category_name)
|
||||||
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
||||||
.setNegativeButton(android.R.string.cancel)
|
.setNegativeButton(android.R.string.cancel)
|
||||||
.setMaxLength(12, false)
|
.setMaxLength(MAX_TITLE_LENGTH, false)
|
||||||
.setPositiveButton(R.string.rename) { _, name ->
|
.setPositiveButton(R.string.rename) { _, name ->
|
||||||
callback.onRenameCategory(category, name)
|
callback.onRenameCategory(category, name)
|
||||||
}.create()
|
}.create()
|
||||||
@@ -43,7 +43,7 @@ class CategoriesEditDelegate(
|
|||||||
.setHint(R.string.enter_category_name)
|
.setHint(R.string.enter_category_name)
|
||||||
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
||||||
.setNegativeButton(android.R.string.cancel)
|
.setNegativeButton(android.R.string.cancel)
|
||||||
.setMaxLength(12, false)
|
.setMaxLength(MAX_TITLE_LENGTH, false)
|
||||||
.setPositiveButton(R.string.add) { _, name ->
|
.setPositiveButton(R.string.add) { _, name ->
|
||||||
callback.onCreateCategory(name)
|
callback.onCreateCategory(name)
|
||||||
}.create()
|
}.create()
|
||||||
@@ -58,4 +58,9 @@ class CategoriesEditDelegate(
|
|||||||
|
|
||||||
fun onCreateCategory(name: String)
|
fun onCreateCategory(name: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
|
||||||
|
const val MAX_TITLE_LENGTH = 24
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.list.ui
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import org.koin.android.ext.android.get
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.PaginationScrollListener
|
|
||||||
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
|
|
||||||
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog
|
|
||||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
|
||||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
|
||||||
import org.koitharu.kotatsu.databinding.SheetListBinding
|
|
||||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter
|
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
|
||||||
import org.koitharu.kotatsu.utils.ext.*
|
|
||||||
|
|
||||||
abstract class MangaListSheet : BaseBottomSheet<SheetListBinding>(),
|
|
||||||
PaginationScrollListener.Callback, OnListItemClickListener<Manga>,
|
|
||||||
Toolbar.OnMenuItemClickListener {
|
|
||||||
|
|
||||||
private var listAdapter: MangaListAdapter? = null
|
|
||||||
private var paginationListener: PaginationScrollListener? = null
|
|
||||||
private val spanResolver = MangaListSpanResolver()
|
|
||||||
private val spanSizeLookup = SpanSizeLookup()
|
|
||||||
open val isSwipeRefreshEnabled = true
|
|
||||||
|
|
||||||
protected abstract val viewModel: MangaListViewModel
|
|
||||||
|
|
||||||
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): SheetListBinding {
|
|
||||||
return SheetListBinding.inflate(inflater, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
listAdapter = MangaListAdapter(get(), viewLifecycleOwner, this) {
|
|
||||||
viewModel.onRetry()
|
|
||||||
}
|
|
||||||
paginationListener = PaginationScrollListener(4, this)
|
|
||||||
with(binding.recyclerView) {
|
|
||||||
setHasFixedSize(true)
|
|
||||||
adapter = listAdapter
|
|
||||||
addOnScrollListener(paginationListener!!)
|
|
||||||
}
|
|
||||||
with(binding.toolbar) {
|
|
||||||
inflateMenu(R.menu.opt_list_sheet)
|
|
||||||
setOnMenuItemClickListener(this@MangaListSheet)
|
|
||||||
setNavigationOnClickListener {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dialog !is BottomSheetDialog) {
|
|
||||||
binding.toolbar.isVisible = true
|
|
||||||
binding.textViewTitle.isVisible = false
|
|
||||||
binding.appbar.elevation = resources.getDimension(R.dimen.elevation_large)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.content.observe(viewLifecycleOwner, ::onListChanged)
|
|
||||||
viewModel.onError.observe(viewLifecycleOwner, ::onError)
|
|
||||||
viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged)
|
|
||||||
viewModel.listMode.observe(viewLifecycleOwner, ::onListModeChanged)
|
|
||||||
viewModel.gridScale.observe(viewLifecycleOwner, ::onGridScaleChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
listAdapter = null
|
|
||||||
paginationListener = null
|
|
||||||
spanSizeLookup.invalidateCache()
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun setTitle(title: CharSequence) {
|
|
||||||
binding.toolbar.title = title
|
|
||||||
binding.textViewTitle.text = title
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun setSubtitle(subtitle: CharSequence) {
|
|
||||||
binding.toolbar.subtitle = subtitle
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?) =
|
|
||||||
super.onCreateDialog(savedInstanceState).also {
|
|
||||||
val behavior = (it as? BottomSheetDialog)?.behavior ?: return@also
|
|
||||||
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
|
||||||
private val elevation = resources.getDimension(R.dimen.elevation_large)
|
|
||||||
|
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit
|
|
||||||
|
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
|
||||||
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
|
|
||||||
binding.toolbar.isVisible = true
|
|
||||||
binding.textViewTitle.isVisible = false
|
|
||||||
binding.appbar.elevation = elevation
|
|
||||||
} else {
|
|
||||||
binding.toolbar.isVisible = false
|
|
||||||
binding.textViewTitle.isVisible = true
|
|
||||||
binding.appbar.elevation = 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemClick(item: MenuItem) = when (item.itemId) {
|
|
||||||
R.id.action_list_mode -> {
|
|
||||||
ListModeSelectDialog.show(childFragmentManager)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemClick(item: Manga, view: View) {
|
|
||||||
startActivity(DetailsActivity.newIntent(context ?: return, item))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onListChanged(list: List<ListModel>) {
|
|
||||||
spanSizeLookup.invalidateCache()
|
|
||||||
listAdapter?.items = list
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onError(e: Throwable) {
|
|
||||||
if (e is CloudFlareProtectedException) {
|
|
||||||
CloudFlareDialog.newInstance(e.url).show(childFragmentManager, CloudFlareDialog.TAG)
|
|
||||||
} else {
|
|
||||||
Snackbar.make(
|
|
||||||
binding.recyclerView,
|
|
||||||
e.getDisplayMessage(resources),
|
|
||||||
Snackbar.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
|
||||||
binding.progressBar.isVisible =
|
|
||||||
isLoading && !binding.recyclerView.hasItems
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onGridScaleChanged(scale: Float) {
|
|
||||||
spanSizeLookup.invalidateCache()
|
|
||||||
spanResolver.setGridSize(scale, binding.recyclerView)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onListModeChanged(mode: ListMode) {
|
|
||||||
spanSizeLookup.invalidateCache()
|
|
||||||
with(binding.recyclerView) {
|
|
||||||
clearItemDecorations()
|
|
||||||
removeOnLayoutChangeListener(spanResolver)
|
|
||||||
when (mode) {
|
|
||||||
ListMode.LIST -> {
|
|
||||||
layoutManager = LinearLayoutManager(context)
|
|
||||||
addItemDecoration(
|
|
||||||
DividerItemDecoration(
|
|
||||||
context,
|
|
||||||
RecyclerView.VERTICAL
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ListMode.DETAILED_LIST -> {
|
|
||||||
layoutManager = LinearLayoutManager(context)
|
|
||||||
addItemDecoration(
|
|
||||||
SpacingItemDecoration(
|
|
||||||
resources.getDimensionPixelOffset(R.dimen.grid_spacing)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ListMode.GRID -> {
|
|
||||||
layoutManager = GridLayoutManager(context, spanResolver.spanCount).also {
|
|
||||||
it.spanSizeLookup = spanSizeLookup
|
|
||||||
}
|
|
||||||
addItemDecoration(
|
|
||||||
SpacingItemDecoration(
|
|
||||||
resources.getDimensionPixelOffset(R.dimen.grid_spacing)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
addOnLayoutChangeListener(spanResolver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class SpanSizeLookup : GridLayoutManager.SpanSizeLookup() {
|
|
||||||
|
|
||||||
init {
|
|
||||||
isSpanIndexCacheEnabled = true
|
|
||||||
isSpanGroupIndexCacheEnabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSpanSize(position: Int): Int {
|
|
||||||
val total =
|
|
||||||
(binding.recyclerView.layoutManager as? GridLayoutManager)?.spanCount ?: return 1
|
|
||||||
return when (listAdapter?.getItemViewType(position)) {
|
|
||||||
MangaListAdapter.ITEM_TYPE_MANGA_GRID -> 1
|
|
||||||
else -> total
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun invalidateCache() {
|
|
||||||
invalidateSpanGroupIndexCache()
|
|
||||||
invalidateSpanIndexCache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -52,6 +52,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
if (protectHelper.check(this)) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
setContentView(ActivityMainBinding.inflate(layoutInflater))
|
setContentView(ActivityMainBinding.inflate(layoutInflater))
|
||||||
drawerToggle =
|
drawerToggle =
|
||||||
ActionBarDrawerToggle(
|
ActionBarDrawerToggle(
|
||||||
@@ -76,10 +80,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
|
|||||||
} ?: run {
|
} ?: run {
|
||||||
openDefaultSection()
|
openDefaultSection()
|
||||||
}
|
}
|
||||||
if (protectHelper.check(this)) {
|
|
||||||
finish()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
TrackWorker.setup(applicationContext)
|
TrackWorker.setup(applicationContext)
|
||||||
AppUpdateChecker(this).launchIfNeeded()
|
AppUpdateChecker(this).launchIfNeeded()
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class PageLoader(
|
|||||||
"Null response"
|
"Null response"
|
||||||
}
|
}
|
||||||
cache.put(url) { out ->
|
cache.put(url) { out ->
|
||||||
body.byteStream().copyTo(out)
|
body.byteStream().use { it.copyTo(out) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import org.koitharu.kotatsu.core.model.MangaChapter
|
|||||||
import org.koitharu.kotatsu.core.model.MangaPage
|
import org.koitharu.kotatsu.core.model.MangaPage
|
||||||
import org.koitharu.kotatsu.core.prefs.ReaderMode
|
import org.koitharu.kotatsu.core.prefs.ReaderMode
|
||||||
import org.koitharu.kotatsu.databinding.ActivityReaderBinding
|
import org.koitharu.kotatsu.databinding.ActivityReaderBinding
|
||||||
import org.koitharu.kotatsu.reader.ReaderControlDelegate
|
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
|
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.reversed.ReversedReaderFragment
|
import org.koitharu.kotatsu.reader.ui.pager.reversed.ReversedReaderFragment
|
||||||
@@ -63,6 +62,10 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
|
|||||||
private lateinit var touchHelper: GridTouchHelper
|
private lateinit var touchHelper: GridTouchHelper
|
||||||
private lateinit var orientationHelper: ScreenOrientationHelper
|
private lateinit var orientationHelper: ScreenOrientationHelper
|
||||||
private lateinit var controlDelegate: ReaderControlDelegate
|
private lateinit var controlDelegate: ReaderControlDelegate
|
||||||
|
private val permissionsRequest = registerForActivityResult(
|
||||||
|
ActivityResultContracts.RequestPermission(),
|
||||||
|
this
|
||||||
|
)
|
||||||
private var gestureInsets: Insets = Insets.NONE
|
private var gestureInsets: Insets = Insets.NONE
|
||||||
|
|
||||||
private val reader
|
private val reader
|
||||||
@@ -184,10 +187,7 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
|
|||||||
) {
|
) {
|
||||||
onActivityResult(true)
|
onActivityResult(true)
|
||||||
} else {
|
} else {
|
||||||
registerForActivityResult(
|
permissionsRequest.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
ActivityResultContracts.RequestPermission(),
|
|
||||||
this
|
|
||||||
).launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showWaitWhileLoading()
|
showWaitWhileLoading()
|
||||||
@@ -273,6 +273,7 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onReaderModeChanged(mode: ReaderMode) {
|
override fun onReaderModeChanged(mode: ReaderMode) {
|
||||||
|
viewModel.saveCurrentState(reader?.getCurrentState())
|
||||||
viewModel.switchMode(mode)
|
viewModel.switchMode(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.koitharu.kotatsu.reader
|
package org.koitharu.kotatsu.reader.ui
|
||||||
|
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
@@ -39,7 +39,7 @@ class ReaderViewModel(
|
|||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private var loadingJob: Job? = null
|
private var loadingJob: Job? = null
|
||||||
private val currentState = MutableStateFlow(state)
|
private val currentState = MutableStateFlow<ReaderState?>(null)
|
||||||
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
||||||
private val chapters = LongSparseArray<MangaChapter>()
|
private val chapters = LongSparseArray<MangaChapter>()
|
||||||
|
|
||||||
@@ -98,14 +98,12 @@ class ReaderViewModel(
|
|||||||
newMode
|
newMode
|
||||||
} ?: error("There are no chapters in this manga")
|
} ?: error("There are no chapters in this manga")
|
||||||
// obtain state
|
// obtain state
|
||||||
if (state == null) {
|
currentState.value = state ?: historyRepository.getOne(manga)?.let {
|
||||||
currentState.value = historyRepository.getOne(manga)?.let {
|
ReaderState.from(it)
|
||||||
ReaderState.from(it)
|
} ?: ReaderState.initial(manga)
|
||||||
} ?: ReaderState.initial(manga)
|
|
||||||
}
|
|
||||||
readerMode.postValue(mode)
|
readerMode.postValue(mode)
|
||||||
|
|
||||||
val pages = loadChapter(checkNotNull(manga.chapters?.firstOrNull()).id)
|
val pages = loadChapter(requireNotNull(currentState.value).chapterId)
|
||||||
content.postValue(ReaderContent(pages, currentState.value))
|
content.postValue(ReaderContent(pages, currentState.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,10 +116,18 @@ class ReaderViewModel(
|
|||||||
mode = newMode
|
mode = newMode
|
||||||
)
|
)
|
||||||
readerMode.value = newMode
|
readerMode.value = newMode
|
||||||
|
content.value?.run {
|
||||||
|
content.value = copy(
|
||||||
|
state = getCurrentState()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveCurrentState(state: ReaderState? = null) {
|
fun saveCurrentState(state: ReaderState? = null) {
|
||||||
|
if (state != null) {
|
||||||
|
currentState.value = state
|
||||||
|
}
|
||||||
saveState(
|
saveState(
|
||||||
mangaData.value ?: return,
|
mangaData.value ?: return,
|
||||||
state ?: currentState.value ?: return
|
state ?: currentState.value ?: return
|
||||||
@@ -184,17 +190,14 @@ class ReaderViewModel(
|
|||||||
currentState.value = currentValue.copy(chapterId = it.chapterId)
|
currentState.value = currentValue.copy(chapterId = it.chapterId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
when {
|
if (pages.isEmpty() || loadingJob?.isActive == true) {
|
||||||
loadingJob?.isActive == true -> return
|
return
|
||||||
pages.isEmpty() -> return
|
}
|
||||||
position <= BOUNDS_PAGE_OFFSET -> {
|
if (position <= BOUNDS_PAGE_OFFSET) {
|
||||||
val chapterId = pages.first().chapterId
|
loadPrevNextChapter(pages.first().chapterId, -1)
|
||||||
loadPrevNextChapter(chapterId, -1)
|
}
|
||||||
}
|
if (position >= pages.size - BOUNDS_PAGE_OFFSET) {
|
||||||
position >= pages.size - BOUNDS_PAGE_OFFSET -> {
|
loadPrevNextChapter(pages.last().chapterId, 1)
|
||||||
val chapterId = pages.last().chapterId
|
|
||||||
loadPrevNextChapter(chapterId, 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,17 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import org.koin.android.ext.android.get
|
import org.koin.android.ext.android.get
|
||||||
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
|
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
|
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
||||||
|
import org.koitharu.kotatsu.utils.ext.callOnPageChaneListeners
|
||||||
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
|
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
|
||||||
|
import org.koitharu.kotatsu.utils.ext.swapAdapter
|
||||||
|
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
||||||
|
|
||||||
class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
|
class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
|
||||||
|
|
||||||
@@ -29,6 +33,15 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
|
|||||||
offscreenPageLimit = 2
|
offscreenPageLimit = 2
|
||||||
doOnPageChanged(::notifyPageChanged)
|
doOnPageChanged(::notifyPageChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.readerAnimation.observe(viewLifecycleOwner) {
|
||||||
|
val transformer = if (it) ReversedPageAnimTransformer() else null
|
||||||
|
binding.pager.setPageTransformer(transformer)
|
||||||
|
}
|
||||||
|
viewModel.onZoomChanged.observe(viewLifecycleOwner) {
|
||||||
|
pagerAdapter = ReversedPagesAdapter(loader, get())
|
||||||
|
binding.pager.swapAdapter(pagerAdapter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
@@ -47,13 +60,24 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) {
|
override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) {
|
||||||
pagerAdapter?.setItems(pages.asReversed()) {
|
val reversedPages = pages.asReversed()
|
||||||
|
viewLifecycleScope.launchWhenCreated {
|
||||||
|
val items = async {
|
||||||
|
pagerAdapter?.setItems(reversedPages)
|
||||||
|
}
|
||||||
if (pendingState != null) {
|
if (pendingState != null) {
|
||||||
val position = pages.indexOfFirst {
|
val position = reversedPages.indexOfLast {
|
||||||
it.chapterId == pendingState.chapterId && it.index == pendingState.page
|
it.chapterId == pendingState.chapterId && it.index == pendingState.page
|
||||||
}
|
}
|
||||||
if (position == -1) return@setItems
|
items.await() ?: return@launchWhenCreated
|
||||||
binding.pager.setCurrentItem(position, false)
|
if (position != -1) {
|
||||||
|
binding.pager.setCurrentItem(position, false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items.await()
|
||||||
|
}
|
||||||
|
binding.pager.post {
|
||||||
|
bindingOrNull()?.pager?.callOnPageChaneListeners()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.koitharu.kotatsu.reader.ui.ReaderState
|
|||||||
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
|
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
||||||
|
import org.koitharu.kotatsu.utils.ext.callOnPageChaneListeners
|
||||||
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
|
import org.koitharu.kotatsu.utils.ext.doOnPageChanged
|
||||||
import org.koitharu.kotatsu.utils.ext.swapAdapter
|
import org.koitharu.kotatsu.utils.ext.swapAdapter
|
||||||
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
||||||
@@ -64,6 +65,9 @@ class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
|
|||||||
} else {
|
} else {
|
||||||
items.await()
|
items.await()
|
||||||
}
|
}
|
||||||
|
binding.pager.post {
|
||||||
|
bindingOrNull()?.pager?.callOnPageChaneListeners()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ import org.koitharu.kotatsu.reader.ui.ReaderState
|
|||||||
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
|
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
|
||||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
||||||
import org.koitharu.kotatsu.utils.ext.doOnCurrentItemChanged
|
import org.koitharu.kotatsu.utils.ext.*
|
||||||
import org.koitharu.kotatsu.utils.ext.findCenterViewPosition
|
|
||||||
import org.koitharu.kotatsu.utils.ext.firstItem
|
|
||||||
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
|
||||||
|
|
||||||
class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
|
class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
|
||||||
|
|
||||||
@@ -51,14 +48,20 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
|
|||||||
}
|
}
|
||||||
setItems.await() ?: return@launchWhenCreated
|
setItems.await() ?: return@launchWhenCreated
|
||||||
if (position != -1) {
|
if (position != -1) {
|
||||||
binding.recyclerView.firstItem = position
|
with(binding.recyclerView) {
|
||||||
// TODO check
|
firstItem = position
|
||||||
(binding.recyclerView.findViewHolderForAdapterPosition(position) as? WebtoonHolder)
|
post {
|
||||||
?.restoreScroll(pendingState.scroll)
|
(findViewHolderForAdapterPosition(position) as? WebtoonHolder)
|
||||||
|
?.restoreScroll(pendingState.scroll)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setItems.await()
|
setItems.await()
|
||||||
}
|
}
|
||||||
|
binding.recyclerView.post {
|
||||||
|
binding.recyclerView.callOnScrollListeners()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,9 +96,12 @@ class RemoteListViewModel(
|
|||||||
|
|
||||||
fun applyFilter(newFilter: MangaFilter) {
|
fun applyFilter(newFilter: MangaFilter) {
|
||||||
appliedFilter = newFilter
|
appliedFilter = newFilter
|
||||||
mangaList.value = emptyList()
|
mangaList.value = null
|
||||||
hasNextPage.value = false
|
hasNextPage.value = false
|
||||||
loadList(false)
|
loadList(false)
|
||||||
|
filter.value?.run {
|
||||||
|
filter.value = copy(currentFilter = newFilter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadFilter() {
|
private fun loadFilter() {
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.search.ui
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
|
||||||
import org.koin.core.parameter.parametersOf
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.core.model.MangaSource
|
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListSheet
|
|
||||||
import org.koitharu.kotatsu.utils.ext.parcelableArgument
|
|
||||||
import org.koitharu.kotatsu.utils.ext.stringArgument
|
|
||||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
|
||||||
|
|
||||||
class MangaSearchSheet : MangaListSheet() {
|
|
||||||
|
|
||||||
override val viewModel by viewModel<SearchViewModel> {
|
|
||||||
parametersOf(source, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val query by stringArgument(ARG_QUERY)
|
|
||||||
private val source by parcelableArgument<MangaSource>(ARG_SOURCE)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
setTitle(query.orEmpty())
|
|
||||||
setSubtitle(getString(R.string.search_results_on_s, source.title))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onScrolledToEnd() {
|
|
||||||
viewModel.loadNextPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private const val ARG_SOURCE = "source"
|
|
||||||
private const val ARG_QUERY = "query"
|
|
||||||
|
|
||||||
private const val TAG = "MangaSearchSheet"
|
|
||||||
|
|
||||||
@Deprecated("Not ready for use")
|
|
||||||
fun show(fm: FragmentManager, source: MangaSource, query: String) {
|
|
||||||
MangaSearchSheet().withArgs(2) {
|
|
||||||
putParcelable(ARG_SOURCE, source)
|
|
||||||
putString(ARG_QUERY, query)
|
|
||||||
}.show(fm, TAG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -52,8 +52,6 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings),
|
|||||||
MultiSummaryProvider(R.string.gestures_only)
|
MultiSummaryProvider(R.string.gestures_only)
|
||||||
findPreference<MultiSelectListPreference>(AppSettings.KEY_TRACK_SOURCES)?.summaryProvider =
|
findPreference<MultiSelectListPreference>(AppSettings.KEY_TRACK_SOURCES)?.summaryProvider =
|
||||||
MultiSummaryProvider(R.string.dont_check)
|
MultiSummaryProvider(R.string.dont_check)
|
||||||
findPreference<Preference>(AppSettings.KEY_GRID_SIZE)?.isEnabled =
|
|
||||||
settings.listMode == ListMode.GRID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@@ -93,10 +91,6 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings),
|
|||||||
?: getString(R.string.not_available)
|
?: getString(R.string.not_available)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AppSettings.KEY_LIST_MODE -> {
|
|
||||||
findPreference<Preference>(AppSettings.KEY_GRID_SIZE)?.isEnabled =
|
|
||||||
settings.listMode == ListMode.GRID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ class NotificationSettingsLegacyFragment : BasePreferenceFragment(R.string.notif
|
|||||||
private val ringtonePickContract = registerForActivityResult(
|
private val ringtonePickContract = registerForActivityResult(
|
||||||
RingtonePickContract(get<Context>().getString(R.string.notification_sound))
|
RingtonePickContract(get<Context>().getString(R.string.notification_sound))
|
||||||
) { uri ->
|
) { uri ->
|
||||||
settings.notificationSound = uri?.toString().orEmpty()
|
settings.notificationSound = uri?.toString() ?: return@registerForActivityResult
|
||||||
findPreference<Preference>(AppSettings.KEY_NOTIFICATIONS_SOUND)?.run {
|
findPreference<Preference>(AppSettings.KEY_NOTIFICATIONS_SOUND)?.run {
|
||||||
summary = RingtoneManager.getRingtone(context, uri).getTitle(context)
|
summary = RingtoneManager.getRingtone(context, uri)?.getTitle(context)
|
||||||
|
?: getString(R.string.silent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +32,8 @@ class NotificationSettingsLegacyFragment : BasePreferenceFragment(R.string.notif
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
findPreference<Preference>(AppSettings.KEY_NOTIFICATIONS_SOUND)?.run {
|
findPreference<Preference>(AppSettings.KEY_NOTIFICATIONS_SOUND)?.run {
|
||||||
val uri = settings.notificationSound.toUriOrNull()
|
val uri = settings.notificationSound.toUriOrNull()
|
||||||
summary = RingtoneManager.getRingtone(context, uri).getTitle(context)
|
summary = RingtoneManager.getRingtone(context, uri)?.getTitle(context)
|
||||||
|
?: getString(R.string.silent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@id/toolbar"
|
android:id="@id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:actionBarSize"
|
android:layout_height="wrap_content"
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
app:layout_scrollFlags="scroll|enterAlways"
|
||||||
app:popupTheme="@style/AppPopupTheme" />
|
app:popupTheme="@style/AppPopupTheme" />
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="wrap_content"
|
||||||
app:popupTheme="@style/AppPopupTheme" />
|
app:popupTheme="@style/AppPopupTheme" />
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@id/toolbar"
|
android:id="@id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:actionBarSize"
|
android:layout_height="wrap_content"
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
app:layout_scrollFlags="scroll|enterAlways"
|
||||||
app:popupTheme="@style/AppPopupTheme">
|
app:popupTheme="@style/AppPopupTheme">
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@id/toolbar"
|
android:id="@id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:actionBarSize"
|
android:layout_height="wrap_content"
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
app:layout_scrollFlags="scroll|enterAlways"
|
||||||
app:popupTheme="@style/AppPopupTheme" />
|
app:popupTheme="@style/AppPopupTheme" />
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@id/toolbar"
|
android:id="@id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:actionBarSize"
|
android:layout_height="wrap_content"
|
||||||
app:layout_scrollFlags="scroll|enterAlways"
|
app:layout_scrollFlags="scroll|enterAlways"
|
||||||
app:popupTheme="@style/AppPopupTheme" />
|
app:popupTheme="@style/AppPopupTheme" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
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:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/appbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
android:background="?android:windowBackground"
|
|
||||||
android:elevation="0dp"
|
|
||||||
app:elevation="0dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
style="@style/Widget.MaterialComponents.Toolbar.Surface"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:elevation="0dp"
|
|
||||||
android:outlineProvider="@null"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:elevation="0dp"
|
|
||||||
app:navigationIcon="@drawable/ic_cross"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView_title"
|
|
||||||
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
|
||||||
tools:visibility="gone" />
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:minHeight="120dp">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/recyclerView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:scrollbars="vertical"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
tools:listitem="@layout/item_manga_list" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView_holder"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textAppearance="?android:textAppearanceMedium"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
|
||||||
tools:text="@tools:sample/lorem[3]" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progressBar"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:indeterminate="true"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="blue_primary">#1565C0</color>
|
<color name="blue_primary">#1976D2</color>
|
||||||
<color name="blue_primary_dark">#283593</color>
|
<color name="blue_primary_dark">#0D47A1</color>
|
||||||
<color name="blue_primary_darker">#1A237E</color>
|
<color name="blue_primary_darker">#1A237E</color>
|
||||||
<color name="red_accent">#FF8A65</color>
|
<color name="red_accent">#FF8A65</color>
|
||||||
<color name="dim">#99000000</color>
|
<color name="dim">#99000000</color>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<style name="AppTheme.Amoled">
|
<style name="AppTheme.Amoled">
|
||||||
<item name="colorPrimary">@color/blue_primary_dark</item>
|
<item name="colorPrimary">@color/blue_primary</item>
|
||||||
<item name="colorPrimaryDark">@color/blue_primary_darker</item>
|
<item name="colorPrimaryDark">@color/blue_primary_darker</item>
|
||||||
<item name="android:windowBackground">@android:color/black</item>
|
<item name="android:windowBackground">@android:color/black</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -179,12 +179,13 @@
|
|||||||
<string name="file_not_found">Файл не найден</string>
|
<string name="file_not_found">Файл не найден</string>
|
||||||
<string name="data_restored_success">Все данные успешно восстановлены</string>
|
<string name="data_restored_success">Все данные успешно восстановлены</string>
|
||||||
<string name="data_restored_with_errors">Данные восстановлены, но возникли некоторые ошибки</string>
|
<string name="data_restored_with_errors">Данные восстановлены, но возникли некоторые ошибки</string>
|
||||||
<string name="backup_information">You can create backup of your history and favourites and restore it</string>
|
<string name="backup_information">Вы можете создать резервную копию избранного и истории и потом восстановить их</string>
|
||||||
<string name="just_now">Только что</string>
|
<string name="just_now">Только что</string>
|
||||||
<string name="yesterday">Вчера</string>
|
<string name="yesterday">Вчера</string>
|
||||||
<string name="long_ago">Давно</string>
|
<string name="long_ago">Давно</string>
|
||||||
<string name="group">Группировать</string>
|
<string name="group">Группировать</string>
|
||||||
<string name="today">Сегодня</string>
|
<string name="today">Сегодня</string>
|
||||||
<string name="tap_to_try_again">Tap to try again</string>
|
<string name="tap_to_try_again">Попробовать ещё раз</string>
|
||||||
<string name="reader_mode_hint">Chosen configuration will be remembered for this manga</string>
|
<string name="reader_mode_hint">Выбранный режим будет сохранён для текущей манги</string>
|
||||||
|
<string name="silent">Без звука</string>
|
||||||
</resources>
|
</resources>
|
||||||
5
app/src/main/res/values-w600dp/dimens.xml
Normal file
5
app/src/main/res/values-w600dp/dimens.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<dimen name="grid_spacing">8dp</dimen>
|
||||||
|
<dimen name="preferred_grid_width">140dp</dimen>
|
||||||
|
</resources>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<dimen name="grid_spacing">5dp</dimen>
|
<dimen name="grid_spacing">6dp</dimen>
|
||||||
<dimen name="manga_list_item_height">84dp</dimen>
|
<dimen name="manga_list_item_height">84dp</dimen>
|
||||||
<dimen name="manga_list_details_item_height">120dp</dimen>
|
<dimen name="manga_list_details_item_height">120dp</dimen>
|
||||||
<dimen name="chapter_list_item_height">46dp</dimen>
|
<dimen name="chapter_list_item_height">46dp</dimen>
|
||||||
|
|||||||
@@ -189,4 +189,5 @@
|
|||||||
<string name="today">Today</string>
|
<string name="today">Today</string>
|
||||||
<string name="tap_to_try_again">Tap to try again</string>
|
<string name="tap_to_try_again">Tap to try again</string>
|
||||||
<string name="reader_mode_hint">Chosen configuration will be remembered for this manga</string>
|
<string name="reader_mode_hint">Chosen configuration will be remembered for this manga</string>
|
||||||
|
<string name="silent">Silent</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user