diff --git a/app/build.gradle b/app/build.gradle index f6e035042..90302a0cb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,7 @@ android { minSdkVersion 21 targetSdkVersion 30 versionCode gitCommits - versionName '1.0-a1' + versionName '1.0-b1' kapt { arguments { diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseFullscreenActivity.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseFullscreenActivity.kt index 3288851e7..8f513dd02 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseFullscreenActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseFullscreenActivity.kt @@ -31,7 +31,6 @@ abstract class BaseFullscreenActivity : BaseActivity() { protected fun hideSystemUI() { insetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars()) - } protected fun showSystemUI() { diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 9896c8464..57ffd22ec 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -27,6 +27,8 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.domain.MangaIntent import org.koitharu.kotatsu.base.ui.BaseActivity 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.MangaSource import org.koitharu.kotatsu.databinding.ActivityDetailsBinding @@ -71,12 +73,19 @@ class DetailsActivity : BaseActivity(), } private fun onError(e: Throwable) { - if (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() + when { + e is CloudFlareProtectedException -> { + CloudFlareDialog.newInstance(e.url) + .show(supportFragmentManager, CloudFlareDialog.TAG) + } + 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() + } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt index 7a39111b8..45f637c1b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt @@ -51,9 +51,9 @@ class FavouritesContainerFragment : BaseFragment(), override fun onViewStateRestored(savedInstanceState: Bundle?) { super.onViewStateRestored(savedInstanceState) - (savedInstanceState?.getParcelable(KEY_ADAPTER_STATE) ?: adapterState)?.let { - (binding.pager.adapter as FavouritesPagerAdapter).restoreState(it) - } + // (savedInstanceState?.getParcelable(KEY_ADAPTER_STATE) ?: adapterState)?.let { + // (binding.pager.adapter as FavouritesPagerAdapter).restoreState(it) + // } } override fun onDestroyView() { diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt index e10ec58ee..a9a80ce59 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt @@ -30,7 +30,7 @@ class CategoriesEditDelegate( .setHint(R.string.enter_category_name) .setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) .setNegativeButton(android.R.string.cancel) - .setMaxLength(12, false) + .setMaxLength(MAX_TITLE_LENGTH, false) .setPositiveButton(R.string.rename) { _, name -> callback.onRenameCategory(category, name) }.create() @@ -43,7 +43,7 @@ class CategoriesEditDelegate( .setHint(R.string.enter_category_name) .setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) .setNegativeButton(android.R.string.cancel) - .setMaxLength(12, false) + .setMaxLength(MAX_TITLE_LENGTH, false) .setPositiveButton(R.string.add) { _, name -> callback.onCreateCategory(name) }.create() @@ -58,4 +58,9 @@ class CategoriesEditDelegate( fun onCreateCategory(name: String) } + + private companion object { + + const val MAX_TITLE_LENGTH = 24 + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListSheet.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListSheet.kt deleted file mode 100644 index 5417d6069..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListSheet.kt +++ /dev/null @@ -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(), - PaginationScrollListener.Callback, OnListItemClickListener, - 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) { - 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() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt index 89bff0d5f..a0e90f9dc 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -52,6 +52,10 @@ class MainActivity : BaseActivity(), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + if (protectHelper.check(this)) { + finish() + return + } setContentView(ActivityMainBinding.inflate(layoutInflater)) drawerToggle = ActionBarDrawerToggle( @@ -76,10 +80,6 @@ class MainActivity : BaseActivity(), } ?: run { openDefaultSection() } - if (protectHelper.check(this)) { - finish() - return - } TrackWorker.setup(applicationContext) AppUpdateChecker(this).launchIfNeeded() diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/PageLoader.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/PageLoader.kt index 08d20518f..728e32169 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/PageLoader.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/PageLoader.kt @@ -60,7 +60,7 @@ class PageLoader( "Null response" } cache.put(url) { out -> - body.byteStream().copyTo(out) + body.byteStream().use { it.copyTo(out) } } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 8955303f0..d89c22c19 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -34,7 +34,6 @@ import org.koitharu.kotatsu.core.model.MangaChapter import org.koitharu.kotatsu.core.model.MangaPage import org.koitharu.kotatsu.core.prefs.ReaderMode 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.ReaderUiState import org.koitharu.kotatsu.reader.ui.pager.reversed.ReversedReaderFragment @@ -63,6 +62,10 @@ class ReaderActivity : BaseFullscreenActivity(), private lateinit var touchHelper: GridTouchHelper private lateinit var orientationHelper: ScreenOrientationHelper private lateinit var controlDelegate: ReaderControlDelegate + private val permissionsRequest = registerForActivityResult( + ActivityResultContracts.RequestPermission(), + this + ) private var gestureInsets: Insets = Insets.NONE private val reader @@ -184,10 +187,7 @@ class ReaderActivity : BaseFullscreenActivity(), ) { onActivityResult(true) } else { - registerForActivityResult( - ActivityResultContracts.RequestPermission(), - this - ).launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + permissionsRequest.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) } } else { showWaitWhileLoading() @@ -273,6 +273,7 @@ class ReaderActivity : BaseFullscreenActivity(), } override fun onReaderModeChanged(mode: ReaderMode) { + viewModel.saveCurrentState(reader?.getCurrentState()) viewModel.switchMode(mode) } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ReaderControlDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt similarity index 98% rename from app/src/main/java/org/koitharu/kotatsu/reader/ReaderControlDelegate.kt rename to app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt index c0306258a..eb408f5f7 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ReaderControlDelegate.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.reader +package org.koitharu.kotatsu.reader.ui import android.view.KeyEvent import androidx.lifecycle.LifecycleCoroutineScope diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index 0e537dffc..dd21b6789 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -39,7 +39,7 @@ class ReaderViewModel( ) : BaseViewModel() { private var loadingJob: Job? = null - private val currentState = MutableStateFlow(state) + private val currentState = MutableStateFlow(null) private val mangaData = MutableStateFlow(intent.manga) private val chapters = LongSparseArray() @@ -98,14 +98,12 @@ class ReaderViewModel( newMode } ?: error("There are no chapters in this manga") // obtain state - if (state == null) { - currentState.value = historyRepository.getOne(manga)?.let { - ReaderState.from(it) - } ?: ReaderState.initial(manga) - } + currentState.value = state ?: historyRepository.getOne(manga)?.let { + ReaderState.from(it) + } ?: ReaderState.initial(manga) readerMode.postValue(mode) - val pages = loadChapter(checkNotNull(manga.chapters?.firstOrNull()).id) + val pages = loadChapter(requireNotNull(currentState.value).chapterId) content.postValue(ReaderContent(pages, currentState.value)) } } @@ -118,10 +116,18 @@ class ReaderViewModel( mode = newMode ) readerMode.value = newMode + content.value?.run { + content.value = copy( + state = getCurrentState() + ) + } } } fun saveCurrentState(state: ReaderState? = null) { + if (state != null) { + currentState.value = state + } saveState( mangaData.value ?: return, state ?: currentState.value ?: return @@ -184,17 +190,14 @@ class ReaderViewModel( currentState.value = currentValue.copy(chapterId = it.chapterId) } } - when { - loadingJob?.isActive == true -> return - pages.isEmpty() -> return - position <= BOUNDS_PAGE_OFFSET -> { - val chapterId = pages.first().chapterId - loadPrevNextChapter(chapterId, -1) - } - position >= pages.size - BOUNDS_PAGE_OFFSET -> { - val chapterId = pages.last().chapterId - loadPrevNextChapter(chapterId, 1) - } + if (pages.isEmpty() || loadingJob?.isActive == true) { + return + } + if (position <= BOUNDS_PAGE_OFFSET) { + loadPrevNextChapter(pages.first().chapterId, -1) + } + if (position >= pages.size - BOUNDS_PAGE_OFFSET) { + loadPrevNextChapter(pages.last().chapterId, 1) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt index 4932c4a22..2c834736e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt @@ -4,13 +4,17 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import kotlinx.coroutines.async import org.koin.android.ext.android.get import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.pager.BaseReader import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter 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.swapAdapter +import org.koitharu.kotatsu.utils.ext.viewLifecycleScope class ReversedReaderFragment : BaseReader() { @@ -29,6 +33,15 @@ class ReversedReaderFragment : BaseReader() { offscreenPageLimit = 2 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() { @@ -47,13 +60,24 @@ class ReversedReaderFragment : BaseReader() { } override fun onPagesChanged(pages: List, pendingState: ReaderState?) { - pagerAdapter?.setItems(pages.asReversed()) { + val reversedPages = pages.asReversed() + viewLifecycleScope.launchWhenCreated { + val items = async { + pagerAdapter?.setItems(reversedPages) + } if (pendingState != null) { - val position = pages.indexOfFirst { + val position = reversedPages.indexOfLast { it.chapterId == pendingState.chapterId && it.index == pendingState.page } - if (position == -1) return@setItems - binding.pager.setCurrentItem(position, false) + items.await() ?: return@launchWhenCreated + if (position != -1) { + binding.pager.setCurrentItem(position, false) + } + } else { + items.await() + } + binding.pager.post { + bindingOrNull()?.pager?.callOnPageChaneListeners() } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt index 460ebdef8..685e44898 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt @@ -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.BaseReaderAdapter 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.swapAdapter import org.koitharu.kotatsu.utils.ext.viewLifecycleScope @@ -64,6 +65,9 @@ class PagerReaderFragment : BaseReader() { } else { items.await() } + binding.pager.post { + bindingOrNull()?.pager?.callOnPageChaneListeners() + } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/wetoon/WebtoonReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/wetoon/WebtoonReaderFragment.kt index c68b0bdc6..663de33ee 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/wetoon/WebtoonReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/wetoon/WebtoonReaderFragment.kt @@ -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.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.ReaderPage -import org.koitharu.kotatsu.utils.ext.doOnCurrentItemChanged -import org.koitharu.kotatsu.utils.ext.findCenterViewPosition -import org.koitharu.kotatsu.utils.ext.firstItem -import org.koitharu.kotatsu.utils.ext.viewLifecycleScope +import org.koitharu.kotatsu.utils.ext.* class WebtoonReaderFragment : BaseReader() { @@ -51,14 +48,20 @@ class WebtoonReaderFragment : BaseReader() { } setItems.await() ?: return@launchWhenCreated if (position != -1) { - binding.recyclerView.firstItem = position - // TODO check - (binding.recyclerView.findViewHolderForAdapterPosition(position) as? WebtoonHolder) - ?.restoreScroll(pendingState.scroll) + with(binding.recyclerView) { + firstItem = position + post { + (findViewHolderForAdapterPosition(position) as? WebtoonHolder) + ?.restoreScroll(pendingState.scroll) + } + } } } else { setItems.await() } + binding.recyclerView.post { + binding.recyclerView.callOnScrollListeners() + } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt index a8226c83d..93aa14f8e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/remotelist/ui/RemoteListViewModel.kt @@ -96,9 +96,12 @@ class RemoteListViewModel( fun applyFilter(newFilter: MangaFilter) { appliedFilter = newFilter - mangaList.value = emptyList() + mangaList.value = null hasNextPage.value = false loadList(false) + filter.value?.run { + filter.value = copy(currentFilter = newFilter) + } } private fun loadFilter() { diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaSearchSheet.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaSearchSheet.kt deleted file mode 100644 index a894fd650..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaSearchSheet.kt +++ /dev/null @@ -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 { - parametersOf(source, query) - } - - private val query by stringArgument(ARG_QUERY) - private val source by parcelableArgument(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) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt index 574004a70..8f1e75c63 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/MainSettingsFragment.kt @@ -52,8 +52,6 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings), MultiSummaryProvider(R.string.gestures_only) findPreference(AppSettings.KEY_TRACK_SOURCES)?.summaryProvider = MultiSummaryProvider(R.string.dont_check) - findPreference(AppSettings.KEY_GRID_SIZE)?.isEnabled = - settings.listMode == ListMode.GRID } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -93,10 +91,6 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings), ?: getString(R.string.not_available) } } - AppSettings.KEY_LIST_MODE -> { - findPreference(AppSettings.KEY_GRID_SIZE)?.isEnabled = - settings.listMode == ListMode.GRID - } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/NotificationSettingsLegacyFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/NotificationSettingsLegacyFragment.kt index 1d560c2d0..923a7e8bf 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/NotificationSettingsLegacyFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/NotificationSettingsLegacyFragment.kt @@ -17,9 +17,10 @@ class NotificationSettingsLegacyFragment : BasePreferenceFragment(R.string.notif private val ringtonePickContract = registerForActivityResult( RingtonePickContract(get().getString(R.string.notification_sound)) ) { uri -> - settings.notificationSound = uri?.toString().orEmpty() + settings.notificationSound = uri?.toString() ?: return@registerForActivityResult findPreference(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) findPreference(AppSettings.KEY_NOTIFICATIONS_SOUND)?.run { val uri = settings.notificationSound.toUriOrNull() - summary = RingtoneManager.getRingtone(context, uri).getTitle(context) + summary = RingtoneManager.getRingtone(context, uri)?.getTitle(context) + ?: getString(R.string.silent) } } diff --git a/app/src/main/res/layout/activity_browser.xml b/app/src/main/res/layout/activity_browser.xml index b4976b58b..0c2add382 100644 --- a/app/src/main/res/layout/activity_browser.xml +++ b/app/src/main/res/layout/activity_browser.xml @@ -19,7 +19,7 @@ diff --git a/app/src/main/res/layout/activity_categories.xml b/app/src/main/res/layout/activity_categories.xml index 693a0268e..57166010a 100644 --- a/app/src/main/res/layout/activity_categories.xml +++ b/app/src/main/res/layout/activity_categories.xml @@ -16,7 +16,7 @@ diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index ae3bddf4e..a12c6daf6 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -15,7 +15,7 @@ diff --git a/app/src/main/res/layout/activity_search_global.xml b/app/src/main/res/layout/activity_search_global.xml index f60b1fbdf..4f6c56541 100644 --- a/app/src/main/res/layout/activity_search_global.xml +++ b/app/src/main/res/layout/activity_search_global.xml @@ -15,7 +15,7 @@ diff --git a/app/src/main/res/layout/activity_settings_simple.xml b/app/src/main/res/layout/activity_settings_simple.xml index f60b1fbdf..4f6c56541 100644 --- a/app/src/main/res/layout/activity_settings_simple.xml +++ b/app/src/main/res/layout/activity_settings_simple.xml @@ -15,7 +15,7 @@ diff --git a/app/src/main/res/layout/sheet_list.xml b/app/src/main/res/layout/sheet_list.xml deleted file mode 100644 index a9fd25a89..000000000 --- a/app/src/main/res/layout/sheet_list.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 7c668f4b4..cd02d0e75 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -1,7 +1,7 @@ - #1565C0 - #283593 + #1976D2 + #0D47A1 #1A237E #FF8A65 #99000000 diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 56a92601d..d839f3aac 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a24742986..2c440bc02 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -179,12 +179,13 @@ Файл не найден Все данные успешно восстановлены Данные восстановлены, но возникли некоторые ошибки - You can create backup of your history and favourites and restore it + Вы можете создать резервную копию избранного и истории и потом восстановить их Только что Вчера Давно Группировать Сегодня - Tap to try again - Chosen configuration will be remembered for this manga + Попробовать ещё раз + Выбранный режим будет сохранён для текущей манги + Без звука \ No newline at end of file diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml new file mode 100644 index 000000000..b871f1600 --- /dev/null +++ b/app/src/main/res/values-w600dp/dimens.xml @@ -0,0 +1,5 @@ + + + 8dp + 140dp + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index f47905595..a23105582 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,6 +1,6 @@ - 5dp + 6dp 84dp 120dp 46dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4d6f71087..0fd1c86c4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -189,4 +189,5 @@ Today Tap to try again Chosen configuration will be remembered for this manga + Silent \ No newline at end of file