Merge branch 'feature/desktop-ui' into devel

pull/128/head
Koitharu 4 years ago
commit de176ec040
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -31,7 +31,7 @@ abstract class BaseActivity<B : ViewBinding> : AppCompatActivity(), OnApplyWindo
@Suppress("LeakingThis") @Suppress("LeakingThis")
protected val exceptionResolver = ExceptionResolver(this) protected val exceptionResolver = ExceptionResolver(this)
private var lastInsets: Insets = Insets.NONE private var lastInsets: Insets? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val settings = get<AppSettings>() val settings = get<AppSettings>()

@ -42,7 +42,7 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return if (resources.getBoolean(R.bool.is_tablet)) { return if (resources.getBoolean(R.bool.is_tablet)) {
AppCompatDialog(context, theme) AppCompatDialog(context, R.style.Theme_Kotatsu_Dialog)
} else super.onCreateDialog(savedInstanceState) } else super.onCreateDialog(savedInstanceState)
} }

@ -8,6 +8,7 @@ import androidx.core.graphics.Insets
import androidx.core.view.OnApplyWindowInsetsListener import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.doOnNextLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
@ -22,7 +23,7 @@ abstract class BaseFragment<B : ViewBinding> : Fragment(), OnApplyWindowInsetsLi
@Suppress("LeakingThis") @Suppress("LeakingThis")
protected val exceptionResolver = ExceptionResolver(this) protected val exceptionResolver = ExceptionResolver(this)
private var lastInsets: Insets = Insets.NONE private var lastInsets: Insets? = null
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -36,12 +37,18 @@ abstract class BaseFragment<B : ViewBinding> : Fragment(), OnApplyWindowInsetsLi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
lastInsets = Insets.NONE
ViewCompat.setOnApplyWindowInsetsListener(view, this) ViewCompat.setOnApplyWindowInsetsListener(view, this)
view.doOnNextLayout {
// Listener may not be called
if (lastInsets == null) {
onWindowInsetsChanged(Insets.NONE)
}
}
} }
override fun onDestroyView() { override fun onDestroyView() {
viewBinding = null viewBinding = null
lastInsets = null
super.onDestroyView() super.onDestroyView()
} }

@ -4,6 +4,7 @@ import android.app.ActivityOptions
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.*
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.Spinner
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
@ -24,6 +25,7 @@ import org.koitharu.kotatsu.download.ui.service.DownloadService
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.reader.ui.ReaderState import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.utils.RecyclerViewScrollCallback
class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(), class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
OnListItemClickListener<ChapterListItem>, OnListItemClickListener<ChapterListItem>,
@ -56,21 +58,9 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
setHasFixedSize(true) setHasFixedSize(true)
adapter = chaptersAdapter adapter = chaptersAdapter
} }
val branchesAdapter = BranchesAdapter() binding.spinnerBranches?.let(::initSpinner)
binding.spinnerBranches.adapter = branchesAdapter
binding.spinnerBranches.onItemSelectedListener = this
viewModel.isLoading.observe(viewLifecycleOwner, this::onLoadingStateChanged) viewModel.isLoading.observe(viewLifecycleOwner, this::onLoadingStateChanged)
viewModel.chapters.observe(viewLifecycleOwner, this::onChaptersChanged) viewModel.chapters.observe(viewLifecycleOwner, this::onChaptersChanged)
viewModel.branches.observe(viewLifecycleOwner) {
branchesAdapter.setItems(it)
binding.spinnerBranches.isVisible = it.size > 1
}
viewModel.selectedBranchIndex.observe(viewLifecycleOwner) {
if (it != -1 && it != binding.spinnerBranches.selectedItemPosition) {
binding.spinnerBranches.setSelection(it)
}
}
viewModel.isChaptersReversed.observe(viewLifecycleOwner) { viewModel.isChaptersReversed.observe(viewLifecycleOwner) {
activity?.invalidateOptionsMenu() activity?.invalidateOptionsMenu()
} }
@ -79,7 +69,7 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
override fun onDestroyView() { override fun onDestroyView() {
chaptersAdapter = null chaptersAdapter = null
selectionDecoration = null selectionDecoration = null
binding.spinnerBranches.adapter = null binding.spinnerBranches?.adapter = null
super.onDestroyView() super.onDestroyView()
} }
@ -166,7 +156,8 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
} }
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
viewModel.setSelectedBranch(binding.spinnerBranches.selectedItem as String?) val spinner = binding.spinnerBranches ?: return
viewModel.setSelectedBranch(spinner.selectedItem as String?)
} }
override fun onNothingSelected(parent: AdapterView<*>?) = Unit override fun onNothingSelected(parent: AdapterView<*>?) = Unit
@ -201,14 +192,37 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {
binding.recyclerViewChapters.updatePadding( binding.recyclerViewChapters.updatePadding(
left = insets.left, bottom = insets.bottom + (binding.spinnerBranches?.height ?: 0),
right = insets.right,
bottom = insets.bottom + binding.spinnerBranches.height
) )
} }
private fun initSpinner(spinner: Spinner) {
val branchesAdapter = BranchesAdapter()
spinner.adapter = branchesAdapter
spinner.onItemSelectedListener = this
viewModel.branches.observe(viewLifecycleOwner) {
branchesAdapter.setItems(it)
spinner.isVisible = it.size > 1
}
viewModel.selectedBranchIndex.observe(viewLifecycleOwner) {
if (it != -1 && it != spinner.selectedItemPosition) {
spinner.setSelection(it)
}
}
}
private fun onChaptersChanged(list: List<ChapterListItem>) { private fun onChaptersChanged(list: List<ChapterListItem>) {
chaptersAdapter?.items = list val adapter = chaptersAdapter ?: return
if (adapter.itemCount == 0) {
val position = list.indexOfFirst { it.hasFlag(ChapterListItem.FLAG_CURRENT) } - 1
if (position > 0) {
adapter.setItems(list, RecyclerViewScrollCallback(binding.recyclerViewChapters, position))
} else {
adapter.items = list
}
} else {
adapter.items = list
}
} }
private fun onLoadingStateChanged(isLoading: Boolean) { private fun onLoadingStateChanged(isLoading: Boolean) {

@ -6,25 +6,26 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.Spinner
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.Toolbar
import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.net.toFile import androidx.core.net.toFile
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R 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
@ -34,6 +35,7 @@ import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.os.ShortcutsRepository import org.koitharu.kotatsu.core.os.ShortcutsRepository
import org.koitharu.kotatsu.databinding.ActivityDetailsBinding import org.koitharu.kotatsu.databinding.ActivityDetailsBinding
import org.koitharu.kotatsu.details.ui.adapter.BranchesAdapter
import org.koitharu.kotatsu.download.ui.service.DownloadService import org.koitharu.kotatsu.download.ui.service.DownloadService
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
@ -43,8 +45,8 @@ import org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity
import org.koitharu.kotatsu.utils.ShareHelper import org.koitharu.kotatsu.utils.ShareHelper
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class DetailsActivity : BaseActivity<ActivityDetailsBinding>(), class DetailsActivity : BaseActivity<ActivityDetailsBinding>(), TabLayoutMediator.TabConfigurationStrategy,
TabLayoutMediator.TabConfigurationStrategy { AdapterView.OnItemSelectedListener {
private val viewModel by viewModel<DetailsViewModel> { private val viewModel by viewModel<DetailsViewModel> {
parametersOf(MangaIntent(intent)) parametersOf(MangaIntent(intent))
@ -53,9 +55,16 @@ class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(ActivityDetailsBinding.inflate(layoutInflater)) setContentView(ActivityDetailsBinding.inflate(layoutInflater))
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.run {
binding.pager.adapter = MangaDetailsAdapter(this) setDisplayHomeAsUpEnabled(true)
TabLayoutMediator(binding.tabs, binding.pager, this).attach() setDisplayShowTitleEnabled(false)
}
val pager = binding.pager
if (pager != null) {
pager.adapter = MangaDetailsAdapter(this)
TabLayoutMediator(checkNotNull(binding.tabs), pager, this).attach()
}
binding.spinnerBranches?.let(::initSpinner)
viewModel.manga.observe(this, ::onMangaUpdated) viewModel.manga.observe(this, ::onMangaUpdated)
viewModel.newChaptersCount.observe(this, ::onNewChaptersChanged) viewModel.newChaptersCount.observe(this, ::onNewChaptersChanged)
@ -96,25 +105,17 @@ class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
binding.snackbar.updatePadding( binding.snackbar.updatePadding(
bottom = insets.bottom bottom = insets.bottom
) )
with(binding.toolbar) { binding.toolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
updatePadding( topMargin = insets.top
left = insets.left,
right = insets.right
)
updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
}
}
if (binding.tabs.parent !is Toolbar) {
binding.tabs.updatePadding(
left = insets.left,
right = insets.right
)
} }
binding.root.updatePadding(
left = insets.left,
right = insets.right
)
} }
private fun onNewChaptersChanged(newChapters: Int) { private fun onNewChaptersChanged(newChapters: Int) {
val tab = binding.tabs.getTabAt(1) ?: return val tab = binding.tabs?.getTabAt(1) ?: return
if (newChapters == 0) { if (newChapters == 0) {
tab.removeBadge() tab.removeBadge()
} else { } else {
@ -208,11 +209,7 @@ class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
viewModel.manga.value?.let { viewModel.manga.value?.let {
lifecycleScope.launch { lifecycleScope.launch {
if (!get<ShortcutsRepository>().requestPinShortcut(it)) { if (!get<ShortcutsRepository>().requestPinShortcut(it)) {
Snackbar.make( binding.snackbar.show(getString(R.string.operation_not_supported))
binding.pager,
R.string.operation_not_supported,
Snackbar.LENGTH_SHORT
).show()
} }
} }
} }
@ -231,19 +228,25 @@ class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
override fun onSupportActionModeStarted(mode: ActionMode) { override fun onSupportActionModeStarted(mode: ActionMode) {
super.onSupportActionModeStarted(mode) super.onSupportActionModeStarted(mode)
binding.pager.isUserInputEnabled = false binding.pager?.isUserInputEnabled = false
} }
override fun onSupportActionModeFinished(mode: ActionMode) { override fun onSupportActionModeFinished(mode: ActionMode) {
super.onSupportActionModeFinished(mode) super.onSupportActionModeFinished(mode)
binding.pager.isUserInputEnabled = true binding.pager?.isUserInputEnabled = true
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val spinner = binding.spinnerBranches ?: return
viewModel.setSelectedBranch(spinner.selectedItem as String?)
} }
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
fun showChapterMissingDialog(chapterId: Long) { fun showChapterMissingDialog(chapterId: Long) {
val remoteManga = viewModel.getRemoteManga() val remoteManga = viewModel.getRemoteManga()
if (remoteManga == null) { if (remoteManga == null) {
Snackbar.make(binding.pager, R.string.chapter_is_missing, Snackbar.LENGTH_LONG) binding.snackbar.show(getString( R.string.chapter_is_missing))
.show()
return return
} }
MaterialAlertDialogBuilder(this).apply { MaterialAlertDialogBuilder(this).apply {
@ -266,9 +269,22 @@ class DetailsActivity : BaseActivity<ActivityDetailsBinding>(),
}.show() }.show()
} }
companion object { private fun initSpinner(spinner: Spinner) {
val branchesAdapter = BranchesAdapter()
spinner.adapter = branchesAdapter
spinner.onItemSelectedListener = this
viewModel.branches.observe(this) {
branchesAdapter.setItems(it)
spinner.isVisible = it.size > 1
}
viewModel.selectedBranchIndex.observe(this) {
if (it != -1 && it != spinner.selectedItemPosition) {
spinner.setSelection(it)
}
}
}
const val ACTION_MANGA_VIEW = "${BuildConfig.APPLICATION_ID}.action.VIEW_MANGA" companion object {
fun newIntent(context: Context, manga: Manga): Intent { fun newIntent(context: Context, manga: Manga): Intent {
return Intent(context, DetailsActivity::class.java) return Intent(context, DetailsActivity::class.java)

@ -243,9 +243,7 @@ class DetailsFragment : BaseFragment<FragmentDetailsBinding>(), View.OnClickList
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {
binding.root.updatePadding( binding.root.updatePadding(
left = insets.left, bottom = insets.bottom,
right = insets.right,
bottom = insets.bottom
) )
} }

@ -176,17 +176,19 @@ abstract class MangaListFragment : BaseFragment<FragmentListBinding>(),
val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top
binding.root.updatePadding( binding.root.updatePadding(
left = insets.left, left = insets.left,
right = insets.right right = insets.right,
) )
if (activity is MainActivity) { if (activity is MainActivity) {
val topOffsetDiff = binding.recyclerView.paddingTop - headerHeight
binding.recyclerView.updatePadding( binding.recyclerView.updatePadding(
top = headerHeight, top = headerHeight,
bottom = insets.bottom bottom = insets.bottom,
) )
binding.recyclerView.scrollBy(0, topOffsetDiff)
binding.swipeRefreshLayout.setProgressViewOffset( binding.swipeRefreshLayout.setProgressViewOffset(
true, true,
headerHeight + resources.resolveDp(-72), headerHeight + resources.resolveDp(-72),
headerHeight + resources.resolveDp(10) headerHeight + resources.resolveDp(10),
) )
} }
} }

@ -10,13 +10,15 @@ import android.view.ViewGroup.MarginLayoutParams
import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.* import androidx.core.view.GravityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.commit import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.CircularProgressDrawable import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -55,10 +57,7 @@ import org.koitharu.kotatsu.suggestions.ui.SuggestionsFragment
import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker
import org.koitharu.kotatsu.tracker.ui.FeedFragment import org.koitharu.kotatsu.tracker.ui.FeedFragment
import org.koitharu.kotatsu.tracker.work.TrackWorker import org.koitharu.kotatsu.tracker.work.TrackWorker
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.*
import org.koitharu.kotatsu.utils.ext.hideKeyboard
import org.koitharu.kotatsu.utils.ext.measureHeight
import org.koitharu.kotatsu.utils.ext.resolveDp
private const val TAG_PRIMARY = "primary" private const val TAG_PRIMARY = "primary"
private const val TAG_SEARCH = "search" private const val TAG_SEARCH = "search"
@ -71,7 +70,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
private val searchSuggestionViewModel by viewModel<SearchSuggestionViewModel>() private val searchSuggestionViewModel by viewModel<SearchSuggestionViewModel>()
private lateinit var navHeaderBinding: NavigationHeaderBinding private lateinit var navHeaderBinding: NavigationHeaderBinding
private lateinit var drawerToggle: ActionBarDrawerToggle private var drawerToggle: ActionBarDrawerToggle? = null
private var drawer: DrawerLayout? = null
override val appBar: AppBarLayout override val appBar: AppBarLayout
get() = binding.appbar get() = binding.appbar
@ -80,36 +80,35 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(ActivityMainBinding.inflate(layoutInflater)) setContentView(ActivityMainBinding.inflate(layoutInflater))
navHeaderBinding = NavigationHeaderBinding.inflate(layoutInflater) navHeaderBinding = NavigationHeaderBinding.inflate(layoutInflater)
drawerToggle = ActionBarDrawerToggle( drawer = binding.root as? DrawerLayout
this, drawerToggle = drawer?.let {
binding.drawer, ActionBarDrawerToggle(
binding.toolbar, this,
R.string.open_menu, it,
R.string.close_menu binding.toolbar,
) R.string.open_menu,
drawerToggle.setHomeAsUpIndicator(ContextCompat.getDrawable(this, R.drawable.ic_arrow_back)) R.string.close_menu
drawerToggle.setToolbarNavigationClickListener { ).apply {
binding.searchView.hideKeyboard() setHomeAsUpIndicator(ContextCompat.getDrawable(this@MainActivity, R.drawable.ic_arrow_back))
onBackPressed() setToolbarNavigationClickListener {
binding.searchView.hideKeyboard()
onBackPressed()
}
it.addDrawerListener(this)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
} }
binding.drawer.addDrawerListener(drawerToggle)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
with(binding.searchView) { with(binding.searchView) {
onFocusChangeListener = this@MainActivity onFocusChangeListener = this@MainActivity
searchSuggestionListener = this@MainActivity searchSuggestionListener = this@MainActivity
if (drawer == null) {
drawableStart = ContextCompat.getDrawable(context, R.drawable.ic_search)
}
} }
with(binding.navigationView) { with(binding.navigationView) {
val menuView = ViewCompat.setOnApplyWindowInsetsListener(this, NavigationViewInsetsListener())
findViewById<RecyclerView>(com.google.android.material.R.id.design_navigation_view)
ViewCompat.setOnApplyWindowInsetsListener(navHeaderBinding.root) { v, insets ->
val systemWindowInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(top = systemWindowInsets.top)
// NavigationView doesn't dispatch insets to the menu view, so pad the bottom here.
menuView.updatePadding(bottom = systemWindowInsets.bottom)
insets
}
addHeaderView(navHeaderBinding.root) addHeaderView(navHeaderBinding.root)
setNavigationItemSelectedListener(this@MainActivity) setNavigationItemSelectedListener(this@MainActivity)
} }
@ -134,26 +133,27 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
override fun onRestoreInstanceState(savedInstanceState: Bundle) { override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState) super.onRestoreInstanceState(savedInstanceState)
drawerToggle.isDrawerIndicatorEnabled = drawerToggle?.isDrawerIndicatorEnabled =
binding.drawer.getDrawerLockMode(GravityCompat.START) == DrawerLayout.LOCK_MODE_UNLOCKED drawer?.getDrawerLockMode(GravityCompat.START) == DrawerLayout.LOCK_MODE_UNLOCKED
} }
override fun onPostCreate(savedInstanceState: Bundle?) { override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState) super.onPostCreate(savedInstanceState)
drawerToggle.syncState() drawerToggle?.syncState()
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
drawerToggle.onConfigurationChanged(newConfig) drawerToggle?.onConfigurationChanged(newConfig)
} }
override fun onBackPressed() { override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH) val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH)
binding.searchView.clearFocus() binding.searchView.clearFocus()
when { when {
binding.drawer.isDrawerOpen(binding.navigationView) -> binding.drawer.closeDrawer( drawer?.isDrawerOpen(binding.navigationView) == true -> {
binding.navigationView) drawer?.closeDrawer(binding.navigationView)
}
fragment != null -> supportFragmentManager.commit { fragment != null -> supportFragmentManager.commit {
remove(fragment) remove(fragment)
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
@ -164,7 +164,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return drawerToggle.onOptionsItemSelected(item) || when (item.itemId) { return drawerToggle?.onOptionsItemSelected(item) == true || when (item.itemId) {
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }
@ -210,19 +210,22 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
else -> return false else -> return false
} }
} }
binding.drawer.closeDrawers() drawer?.closeDrawers()
appBar.setExpanded(true)
return true return true
} }
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {
binding.toolbarCard.updateLayoutParams<MarginLayoutParams> {
topMargin = insets.top + resources.resolveDp(8)
}
binding.fab.updateLayoutParams<MarginLayoutParams> { binding.fab.updateLayoutParams<MarginLayoutParams> {
bottomMargin = insets.bottom + topMargin bottomMargin = insets.bottom + topMargin
leftMargin = insets.left + topMargin
rightMargin = insets.right + topMargin
} }
binding.toolbarCard.updateLayoutParams<MarginLayoutParams> {
topMargin = insets.top + bottomMargin
}
binding.root.updatePadding(
left = insets.left,
right = insets.right,
)
binding.container.updateLayoutParams<MarginLayoutParams> { binding.container.updateLayoutParams<MarginLayoutParams> {
topMargin = -(binding.appbar.measureHeight()) topMargin = -(binding.appbar.measureHeight())
} }
@ -360,14 +363,14 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
} }
private fun onSearchOpened() { private fun onSearchOpened() {
binding.drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) drawer?.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
drawerToggle.isDrawerIndicatorEnabled = false drawerToggle?.isDrawerIndicatorEnabled = false
adjustFabVisibility(isSearchOpened = true) adjustFabVisibility(isSearchOpened = true)
} }
private fun onSearchClosed() { private fun onSearchClosed() {
binding.drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) drawer?.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
drawerToggle.isDrawerIndicatorEnabled = true drawerToggle?.isDrawerIndicatorEnabled = true
adjustFabVisibility(isSearchOpened = false) adjustFabVisibility(isSearchOpened = false)
} }

@ -0,0 +1,24 @@
package org.koitharu.kotatsu.main.ui
import android.view.View
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import java.lang.ref.WeakReference
import com.google.android.material.R as materialR
class NavigationViewInsetsListener : OnApplyWindowInsetsListener {
private var menuViewRef: WeakReference<View>? = null
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
val menuView = menuViewRef?.get() ?: v.findViewById<View>(materialR.id.design_navigation_view).also {
menuViewRef = WeakReference(it)
}
val systemWindowInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(top = systemWindowInsets.top)
// NavigationView doesn't dispatch insets to the menu view, so pad the bottom here.
menuView.updatePadding(bottom = systemWindowInsets.bottom)
return WindowInsetsCompat.CONSUMED
}
}

@ -5,7 +5,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.divider.MaterialDividerItemDecoration import com.google.android.material.divider.MaterialDividerItemDecoration
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
@ -20,6 +19,7 @@ import org.koitharu.kotatsu.details.ui.model.ChapterListItem
import org.koitharu.kotatsu.details.ui.model.toListItem import org.koitharu.kotatsu.details.ui.model.toListItem
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.utils.BottomSheetToolbarController import org.koitharu.kotatsu.utils.BottomSheetToolbarController
import org.koitharu.kotatsu.utils.RecyclerViewScrollCallback
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
class ChaptersBottomSheet : BaseBottomSheet<SheetChaptersBinding>(), OnListItemClickListener<ChapterListItem> { class ChaptersBottomSheet : BaseBottomSheet<SheetChaptersBinding>(), OnListItemClickListener<ChapterListItem> {
@ -59,7 +59,7 @@ class ChaptersBottomSheet : BaseBottomSheet<SheetChaptersBinding>(), OnListItemC
binding.recyclerView.adapter = ChaptersAdapter(this).also { adapter -> binding.recyclerView.adapter = ChaptersAdapter(this).also { adapter ->
if (currentPosition >= 0) { if (currentPosition >= 0) {
val targetPosition = (currentPosition - 1).coerceAtLeast(0) val targetPosition = (currentPosition - 1).coerceAtLeast(0)
adapter.setItems(items, Scroller(binding.recyclerView, targetPosition)) adapter.setItems(items, RecyclerViewScrollCallback(binding.recyclerView, targetPosition))
} else { } else {
adapter.items = items adapter.items = items
} }
@ -78,13 +78,6 @@ class ChaptersBottomSheet : BaseBottomSheet<SheetChaptersBinding>(), OnListItemC
fun onChapterChanged(chapter: MangaChapter) fun onChapterChanged(chapter: MangaChapter)
} }
private class Scroller(private val recyclerView: RecyclerView, private val position: Int) : Runnable {
override fun run() {
val offset = recyclerView.resources.getDimensionPixelSize(R.dimen.chapter_list_item_height) / 2
(recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, offset)
}
}
companion object { companion object {
private const val ARG_CHAPTERS = "chapters" private const val ARG_CHAPTERS = "chapters"

@ -243,7 +243,7 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
rawX >= binding.root.width - gestureInsets.right || rawX >= binding.root.width - gestureInsets.right ||
rawY >= binding.root.height - gestureInsets.bottom || rawY >= binding.root.height - gestureInsets.bottom ||
binding.appbarTop.hasGlobalPoint(rawX, rawY) || binding.appbarTop.hasGlobalPoint(rawX, rawY) ||
binding.appbarBottom.hasGlobalPoint(rawX, rawY) binding.appbarBottom?.hasGlobalPoint(rawX, rawY) == true
) { ) {
false false
} else { } else {
@ -320,11 +320,13 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
if (binding.appbarTop.isVisible != isUiVisible) { if (binding.appbarTop.isVisible != isUiVisible) {
val transition = TransitionSet() val transition = TransitionSet()
.setOrdering(TransitionSet.ORDERING_TOGETHER) .setOrdering(TransitionSet.ORDERING_TOGETHER)
.addTransition(Slide(Gravity.BOTTOM).addTarget(binding.appbarBottom))
.addTransition(Slide(Gravity.TOP).addTarget(binding.appbarTop)) .addTransition(Slide(Gravity.TOP).addTarget(binding.appbarTop))
binding.appbarBottom?.let { botomBar ->
transition.addTransition(Slide(Gravity.BOTTOM).addTarget(botomBar))
}
TransitionManager.beginDelayedTransition(binding.root, transition) TransitionManager.beginDelayedTransition(binding.root, transition)
binding.appbarTop.isVisible = isUiVisible binding.appbarTop.isVisible = isUiVisible
binding.appbarBottom.isVisible = isUiVisible binding.appbarBottom?.isVisible = isUiVisible
if (isUiVisible) { if (isUiVisible) {
showSystemUI() showSystemUI()
} else { } else {
@ -341,7 +343,7 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
right = systemBars.right, right = systemBars.right,
left = systemBars.left left = systemBars.left
) )
binding.appbarBottom.updatePadding( binding.appbarBottom?.updatePadding(
bottom = systemBars.bottom, bottom = systemBars.bottom,
right = systemBars.right, right = systemBars.right,
left = systemBars.left left = systemBars.left

@ -6,7 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@ -29,6 +29,7 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
private lateinit var thumbnails: List<PageThumbnail> private lateinit var thumbnails: List<PageThumbnail>
private val spanResolver = MangaListSpanResolver() private val spanResolver = MangaListSpanResolver()
private var currentPageIndex = -1
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -37,12 +38,12 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
dismissAllowingStateLoss() dismissAllowingStateLoss()
return return
} }
val current = arguments?.getInt(ARG_CURRENT, -1) ?: -1 currentPageIndex = requireArguments().getInt(ARG_CURRENT, currentPageIndex)
val repository = MangaRepository(pages.first().source) val repository = MangaRepository(pages.first().source)
thumbnails = pages.mapIndexed { i, x -> thumbnails = pages.mapIndexed { i, x ->
PageThumbnail( PageThumbnail(
number = i + 1, number = i + 1,
isCurrent = i == current, isCurrent = i == currentPageIndex,
repository = repository, repository = repository,
page = x page = x
) )
@ -69,11 +70,9 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
resources.getQuantityString(R.plurals.pages, thumbnails.size, thumbnails.size) resources.getQuantityString(R.plurals.pages, thumbnails.size, thumbnails.size)
} }
val initialTopPosition = binding.recyclerView.top
with(binding.recyclerView) { with(binding.recyclerView) {
addItemDecoration( addItemDecoration(
SpacingItemDecoration(view.resources.getDimensionPixelOffset(R.dimen.grid_spacing)) SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))
) )
adapter = PageThumbnailAdapter( adapter = PageThumbnailAdapter(
thumbnails, thumbnails,
@ -82,16 +81,12 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
get(), get(),
this@PagesThumbnailsSheet this@PagesThumbnailsSheet
) )
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) = Unit
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
binding.appbar.isLifted = getChildAt(0).top < initialTopPosition
}
})
addOnLayoutChangeListener(spanResolver) addOnLayoutChangeListener(spanResolver)
spanResolver.setGridSize(get<AppSettings>().gridSize / 100f, this) spanResolver.setGridSize(get<AppSettings>().gridSize / 100f, this)
if (currentPageIndex > 0) {
val offset = resources.getDimensionPixelOffset(R.dimen.preferred_grid_width)
(layoutManager as GridLayoutManager).scrollToPositionWithOffset(currentPageIndex, offset)
}
} }
} }

@ -14,6 +14,8 @@ import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail
import org.koitharu.kotatsu.utils.ext.IgnoreErrors import org.koitharu.kotatsu.utils.ext.IgnoreErrors
import org.koitharu.kotatsu.utils.ext.referer import org.koitharu.kotatsu.utils.ext.referer
import org.koitharu.kotatsu.utils.ext.setTextColorAttr
import com.google.android.material.R as materialR
fun pageThumbnailAD( fun pageThumbnailAD(
coil: ImageLoader, coil: ImageLoader,
@ -31,7 +33,7 @@ fun pageThumbnailAD(
height = (gridWidth * 13f / 18f).toInt() height = (gridWidth * 13f / 18f).toInt()
) )
binding.handle.setOnClickListener { binding.root.setOnClickListener {
clickListener.onItemClick(item.page, itemView) clickListener.onItemClick(item.page, itemView)
} }
@ -39,7 +41,8 @@ fun pageThumbnailAD(
job?.cancel() job?.cancel()
binding.imageViewThumb.setImageDrawable(null) binding.imageViewThumb.setImageDrawable(null)
with(binding.textViewNumber) { with(binding.textViewNumber) {
setBackgroundResource(if (item.isCurrent) R.drawable.bg_badge_accent else R.drawable.bg_badge_default) setBackgroundResource(if (item.isCurrent) R.drawable.bg_badge_accent else R.drawable.bg_badge_empty)
setTextColorAttr(if (item.isCurrent) materialR.attr.colorOnTertiary else android.R.attr.textColorPrimary)
text = (item.number).toString() text = (item.number).toString()
} }
job = scope.launch(Dispatchers.Default + IgnoreErrors) { job = scope.launch(Dispatchers.Default + IgnoreErrors) {

@ -15,7 +15,7 @@ import org.koitharu.kotatsu.databinding.ItemSearchSuggestionMangaGridBinding
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
import org.koitharu.kotatsu.utils.ScrollResetCallback import org.koitharu.kotatsu.utils.RecyclerViewScrollCallback
import org.koitharu.kotatsu.utils.ext.enqueueWith import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest import org.koitharu.kotatsu.utils.ext.newImageRequest
@ -37,7 +37,7 @@ fun searchSuggestionMangaListAD(
right = recyclerView.paddingRight - spacing, right = recyclerView.paddingRight - spacing,
) )
recyclerView.addItemDecoration(SpacingItemDecoration(spacing)) recyclerView.addItemDecoration(SpacingItemDecoration(spacing))
val scrollResetCallback = ScrollResetCallback(recyclerView) val scrollResetCallback = RecyclerViewScrollCallback(recyclerView, 0)
bind { bind {
adapter.setItems(item.items, scrollResetCallback) adapter.setItems(item.items, scrollResetCallback)

@ -0,0 +1,21 @@
package org.koitharu.kotatsu.utils
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.lang.ref.WeakReference
class RecyclerViewScrollCallback(recyclerView: RecyclerView, private val position: Int) : Runnable {
private val recyclerViewRef = WeakReference(recyclerView)
override fun run() {
val rv = recyclerViewRef.get() ?: return
val lm = rv.layoutManager ?: return
rv.stopScroll()
if (lm is LinearLayoutManager) {
lm.scrollToPositionWithOffset(position, 0)
} else {
lm.scrollToPosition(position)
}
}
}

@ -1,13 +0,0 @@
package org.koitharu.kotatsu.utils
import androidx.recyclerview.widget.RecyclerView
import java.lang.ref.WeakReference
class ScrollResetCallback(recyclerView: RecyclerView) : Runnable {
private val recyclerViewRef = WeakReference(recyclerView)
override fun run() {
recyclerViewRef.get()?.scrollToPosition(0)
}
}

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.utils.ext
import android.view.View
import androidx.core.graphics.Insets
fun Insets.getStart(view: View): Int {
return if (view.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
right
} else {
left
}
}
fun Insets.getEnd(view: View): Int {
return if (view.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
left
} else {
right
}
}

@ -3,7 +3,9 @@ package org.koitharu.kotatsu.utils.ext
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.annotation.AttrRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.res.use
import androidx.core.view.isGone import androidx.core.view.isGone
var TextView.textAndVisible: CharSequence? var TextView.textAndVisible: CharSequence?
@ -35,4 +37,11 @@ fun TextView.setTextAndVisible(@StringRes textResId: Int) {
setText(textResId) setText(textResId)
isGone = text.isNullOrEmpty() isGone = text.isNullOrEmpty()
} }
}
fun TextView.setTextColorAttr(@AttrRes attrResId: Int) {
val colors = context.obtainStyledAttributes(intArrayOf(attrResId)).use {
it.getColorStateList(0)
}
setTextColor(colors)
} }

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<solid android:color="?colorBackgroundFloating" />
<stroke
android:width="1dp"
android:color="?colorOutline" />
<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />
</shape>

@ -0,0 +1,81 @@
<?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:animateLayoutChanges="true"
android:orientation="vertical">
<org.koitharu.kotatsu.base.ui.widgets.CheckableButtonGroup
android:id="@+id/checkableGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:orientation="horizontal"
android:weightSum="3">
<com.google.android.material.button.MaterialButton
android:id="@+id/button_list"
style="@style/Widget.Kotatsu.ToggleButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/list"
app:icon="@drawable/ic_list" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_list_detailed"
style="@style/Widget.Kotatsu.ToggleButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/detailed_list"
app:icon="@drawable/ic_list_detailed" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_grid"
style="@style/Widget.Kotatsu.ToggleButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/grid"
app:icon="@drawable/ic_grid" />
</org.koitharu.kotatsu.base.ui.widgets.CheckableButtonGroup>
<TextView
android:id="@+id/textView_grid_title"
style="?materialAlertDialogTitleTextStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="?attr/dialogPreferredPadding"
android:paddingRight="?attr/dialogPreferredPadding"
android:singleLine="true"
android:text="@string/grid_size"
android:visibility="gone"
tools:visibility="visible" />
<com.google.android.material.slider.Slider
android:id="@+id/slider_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:stepSize="5"
android:valueFrom="50"
android:valueTo="150"
android:visibility="gone"
app:labelBehavior="floating"
app:tickVisible="false"
tools:value="100"
tools:visibility="visible" />
</LinearLayout>

@ -1,198 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
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="match_parent"
android:clipToPadding="false"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.koitharu.kotatsu.base.ui.widgets.CoverImageView
android:id="@+id/imageView_cover"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:foreground="?selectableItemBackground"
android:scaleType="centerCrop"
android:transitionName="cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.3"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover"
tools:background="@tools:sample/backgrounds/scenic"
tools:ignore="ContentDescription,UnusedAttribute" />
<TextView
android:id="@+id/textView_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="4"
android:textAppearance="?attr/textAppearanceHeadlineSmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem[15]" />
<TextView
android:id="@+id/textView_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="4"
android:textAppearance="?attr/textAppearanceBodyMedium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_title"
tools:text="@tools:sample/lorem[12]" />
<TextView
android:id="@+id/textView_author"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="12dp"
android:background="@drawable/list_selector"
android:padding="4dp"
android:singleLine="true"
android:textColor="?attr/colorTertiary"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_subtitle"
app:layout_constraintWidth_default="wrap"
tools:text="@tools:sample/full_names" />
<TextView
android:id="@+id/textView_state"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:drawablePadding="4dp"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodySmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_author"
tools:drawableStart="@drawable/ic_state_finished"
tools:text="Finished" />
<include
android:id="@+id/info_layout"
layout="@layout/layout_details_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_state" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_favorite"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:paddingStart="0dp"
android:paddingEnd="0dp"
app:icon="@drawable/ic_heart_outline"
app:iconGravity="textTop"
app:iconPadding="0dp"
app:layout_constraintBottom_toBottomOf="@id/button_read"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toTopOf="@id/button_read" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_read"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:enabled="false"
android:text="@string/read"
android:textAllCaps="false"
app:iconGravity="textStart"
app:iconPadding="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/button_favorite"
app:layout_constraintTop_toBottomOf="@id/info_layout"
tools:text="@string/_continue" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="imageView_cover,button_read" />
<org.koitharu.kotatsu.base.ui.widgets.ChipsView
android:id="@+id/chips_tags"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:chipSpacingHorizontal="6dp"
app:chipSpacingVertical="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/barrier_header" />
<TextView
android:id="@+id/textView_description"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:lineSpacingMultiplier="1.2"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textIsSelectable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chips_tags"
tools:ignore="UnusedAttribute"
tools:text="@tools:sample/lorem/random[250]" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progressBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone"
app:hideAnimationBehavior="outward"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:showAnimationBehavior="inward"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".details.ui.DetailsActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
style="@style/Widget.Kotatsu.Tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:background="@android:color/transparent"
app:tabGravity="center"
app:tabMode="fixed" />
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
<org.koitharu.kotatsu.base.ui.widgets.FadingSnackbar
android:id="@+id/snackbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:visibility="gone" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -0,0 +1,83 @@
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<org.koitharu.kotatsu.reader.ui.ReaderToastView
android:id="@+id/toastView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="20dp"
android:background="@drawable/bg_reader_indicator"
android:drawablePadding="6dp"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodySmall"
android:theme="@style/ThemeOverlay.Material3.Dark"
tools:text="@string/loading_" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/dim"
android:elevation="0dp"
android:theme="@style/ThemeOverlay.Material3.Dark"
app:elevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:popupTheme="@style/ThemeOverlay.Kotatsu" />
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:popupTheme="@style/ThemeOverlay.Kotatsu" />
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:id="@+id/layout_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:orientation="vertical">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
<TextView
android:id="@+id/textView_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/loading_"
android:textAppearance="?attr/textAppearanceBody2" />
</LinearLayout>
</FrameLayout>

@ -17,8 +17,8 @@
android:id="@+id/imageView_cover" android:id="@+id/imageView_cover"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="8dp"
android:layout_marginTop="16dp" android:layout_marginTop="8dp"
android:foreground="?selectableItemBackground" android:foreground="?selectableItemBackground"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:transitionName="cover" android:transitionName="cover"
@ -35,9 +35,9 @@
android:id="@+id/textView_title" android:id="@+id/textView_title"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="8dp"
android:layout_marginTop="16dp" android:layout_marginTop="8dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="8dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="3" android:maxLines="3"
android:textAppearance="?attr/textAppearanceHeadlineSmall" android:textAppearance="?attr/textAppearanceHeadlineSmall"
@ -50,9 +50,9 @@
android:id="@+id/textView_subtitle" android:id="@+id/textView_subtitle"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="8dp"
android:layout_marginTop="6dp" android:layout_marginTop="4dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="8dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="3" android:maxLines="3"
android:textAppearance="?attr/textAppearanceBodyMedium" android:textAppearance="?attr/textAppearanceBodyMedium"
@ -65,11 +65,11 @@
android:id="@+id/textView_author" android:id="@+id/textView_author"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp" android:layout_marginStart="6dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:layout_marginEnd="12dp" android:layout_marginEnd="6dp"
android:background="@drawable/list_selector" android:background="@drawable/list_selector"
android:padding="4dp" android:padding="2dp"
android:singleLine="true" android:singleLine="true"
android:textColor="?attr/colorTertiary" android:textColor="?attr/colorTertiary"
android:textStyle="bold" android:textStyle="bold"
@ -84,9 +84,9 @@
android:id="@+id/textView_state" android:id="@+id/textView_state"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="8dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="8dp"
android:drawablePadding="4dp" android:drawablePadding="4dp"
android:singleLine="true" android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodySmall" android:textAppearance="?attr/textAppearanceBodySmall"
@ -96,12 +96,19 @@
tools:drawableStart="@drawable/ic_state_finished" tools:drawableStart="@drawable/ic_state_finished"
tools:text="Finished" /> tools:text="Finished" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="imageView_cover,button_read" />
<include <include
android:id="@+id/info_layout" android:id="@+id/info_layout"
layout="@layout/layout_details_info" layout="@layout/layout_details_info"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover" app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_state" /> app:layout_constraintTop_toBottomOf="@id/textView_state" />
@ -128,7 +135,6 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:enabled="false" android:enabled="false"
android:text="@string/read" android:text="@string/read"
@ -140,14 +146,6 @@
app:layout_constraintTop_toBottomOf="@id/info_layout" app:layout_constraintTop_toBottomOf="@id/info_layout"
tools:text="@string/_continue" /> tools:text="@string/_continue" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="imageView_cover,button_read" />
<org.koitharu.kotatsu.base.ui.widgets.ChipsView <org.koitharu.kotatsu.base.ui.widgets.ChipsView
android:id="@+id/chips_tags" android:id="@+id/chips_tags"
android:layout_width="0dp" android:layout_width="0dp"

@ -0,0 +1,90 @@
<?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="match_parent"
android:orientation="horizontal">
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="260dp"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
app:drawerLayoutCornerSize="0dp"
app:elevation="0dp"
app:menu="@menu/nav_drawer" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
tools:layout="@layout/fragment_list" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
app:liftOnScroll="false">
<FrameLayout
android:id="@+id/toolbar_card"
android:layout_width="match_parent"
android:layout_height="54dp"
android:layout_marginVertical="8dp"
android:background="@drawable/toolbar_background">
<com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:focusable="true"
android:focusableInTouchMode="true">
<org.koitharu.kotatsu.search.ui.widget.SearchEditText
android:id="@+id/searchView"
style="@style/Widget.Kotatsu.SearchView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
android:drawablePadding="16dp"
android:gravity="center_vertical"
android:hint="@string/search_manga"
android:imeOptions="actionSearch"
android:importantForAutofill="no"
android:singleLine="true" />
</com.google.android.material.appbar.MaterialToolbar>
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="@string/_continue"
android:src="@drawable/ic_read_fill"
android:visibility="gone"
app:backgroundTint="?attr/colorContainer"
app:fabSize="normal"
app:layout_anchor="@id/container"
app:layout_anchorGravity="bottom|end"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:layout_dodgeInsetEdges="bottom"
tools:visibility="visible" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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="match_parent"
android:orientation="vertical"
tools:context=".details.ui.DetailsActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:elevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:liftOnScroll="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="?attr/actionBarTheme">
<Spinner
android:id="@+id/spinner_branches"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:visibility="gone"
tools:listitem="@layout/item_branch"
tools:visibility="visible" />
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/container_details"
android:name="org.koitharu.kotatsu.details.ui.DetailsFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appbar"
tools:layout="@layout/fragment_details" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/container_chapters"
android:name="org.koitharu.kotatsu.details.ui.ChaptersFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/guideline"
app:layout_constraintTop_toBottomOf="@id/appbar"
tools:layout="@layout/fragment_chapters" />
<org.koitharu.kotatsu.base.ui.widgets.FadingSnackbar
android:id="@+id/snackbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,28 @@
<?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:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView_chapters"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical"
app:fastScrollEnabled="true"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_chapter" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone"
tools:visibility="visible" />
</FrameLayout>

@ -3,7 +3,6 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".details.ui.DetailsActivity"> tools:context=".details.ui.DetailsActivity">
@ -12,24 +11,28 @@
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:liftOnScroll="false" app:elevation="0dp"
app:elevation="0dp"> app:liftOnScroll="false">
<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="?attr/actionBarSize"
android:background="@drawable/m3_tabs_background"
android:theme="?attr/actionBarTheme" android:theme="?attr/actionBarTheme"
app:layout_scrollFlags="scroll|enterAlways"/> app:layout_scrollFlags="scroll|enterAlways"
tools:ignore="PrivateResource">
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/tabs" android:id="@+id/tabs"
style="@style/Widget.Kotatsu.Tabs" android:layout_width="wrap_content"
android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_height="wrap_content" android:layout_gravity="center_horizontal"
app:tabGravity="fill" android:background="@null"
app:tabMaxWidth="0dp" app:tabGravity="center"
app:tabMode="fixed" /> app:tabMode="scrollable" />
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

@ -3,7 +3,6 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".main.ui.MainActivity"> tools:context=".main.ui.MainActivity">
@ -16,12 +15,15 @@
android:id="@id/container" android:id="@id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:layout="@layout/fragment_list"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:background="@null" android:background="@null"
android:stateListAnimator="@null"> android:stateListAnimator="@null">
@ -29,10 +31,7 @@
android:id="@+id/toolbar_card" android:id="@+id/toolbar_card"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginStart="16dp" android:layout_marginVertical="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:background="@drawable/toolbar_background"> android:background="@drawable/toolbar_background">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
@ -42,11 +41,7 @@
android:background="@null" android:background="@null"
android:focusable="true" android:focusable="true"
android:focusableInTouchMode="true" android:focusableInTouchMode="true"
android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar" app:contentInsetStartWithNavigation="0dp">
app:contentInsetStartWithNavigation="0dp"
app:titleTextAppearance="@style/TextAppearance.Kotatsu.PersistentToolbarTitle"
app:titleTextColor="?android:colorControlNormal"
tools:title="@string/app_name">
<org.koitharu.kotatsu.search.ui.widget.SearchEditText <org.koitharu.kotatsu.search.ui.widget.SearchEditText
android:id="@+id/searchView" android:id="@+id/searchView"

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/scrimBackground"> xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/Widget.Material3.CardView.Outlined"
app:cardBackgroundColor="?scrimBackground">
<org.koitharu.kotatsu.base.ui.widgets.CoverImageView <org.koitharu.kotatsu.base.ui.widgets.CoverImageView
android:id="@+id/imageView_thumb" android:id="@+id/imageView_thumb"
@ -13,18 +15,12 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@drawable/ic_placeholder" /> tools:src="@drawable/ic_placeholder" />
<View
android:id="@+id/handle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?selectableItemBackground" />
<TextView <TextView
android:id="@+id/textView_number" android:id="@+id/textView_number"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_margin="8dp" android:layout_margin="4dp"
android:ellipsize="none" android:ellipsize="none"
android:gravity="center" android:gravity="center"
android:minWidth="26dp" android:minWidth="26dp"
@ -34,4 +30,4 @@
tools:background="@drawable/bg_badge_default" tools:background="@drawable/bg_badge_default"
tools:text="2" /> tools:text="2" />
</FrameLayout> </com.google.android.material.card.MaterialCardView>

@ -21,6 +21,4 @@
<dimen name="search_suggestions_manga_height">124dp</dimen> <dimen name="search_suggestions_manga_height">124dp</dimen>
<dimen name="search_suggestions_manga_spacing">4dp</dimen> <dimen name="search_suggestions_manga_spacing">4dp</dimen>
<!--Text dimens-->
</resources> </resources>

@ -85,4 +85,12 @@
<style name="ThemeOverlay.Kotatsu.AMOLED" parent="" /> <style name="ThemeOverlay.Kotatsu.AMOLED" parent="" />
<style name="Theme.Kotatsu.Dialog" parent="">
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
<item name="toolbarNavigationButtonStyle">@style/Theme.Kotatsu.ActionMode.CloseButton</item>
</style>
</resources> </resources>

Loading…
Cancel
Save