Support for multiple manga branches (translations, etc)
This commit is contained in:
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -4,8 +4,12 @@
|
|||||||
<option name="filePathToZoomLevelMap">
|
<option name="filePathToZoomLevelMap">
|
||||||
<map>
|
<map>
|
||||||
<entry key="../../../../../../layout/custom_preview.xml" value="0.1" />
|
<entry key="../../../../../../layout/custom_preview.xml" value="0.1" />
|
||||||
|
<entry key="../../../../../../opt/usr/android-sdk/platforms/android-30/data/res/layout/simple_dropdown_item_1line.xml" value="0.24739583333333334" />
|
||||||
<entry key="app/src/main/res/layout-w600dp/fragment_details.xml" value="0.14583333333333334" />
|
<entry key="app/src/main/res/layout-w600dp/fragment_details.xml" value="0.14583333333333334" />
|
||||||
|
<entry key="app/src/main/res/layout/fragment_chapters.xml" value="0.24739583333333334" />
|
||||||
<entry key="app/src/main/res/layout/fragment_details.xml" value="0.26145833333333335" />
|
<entry key="app/src/main/res/layout/fragment_details.xml" value="0.26145833333333335" />
|
||||||
|
<entry key="app/src/main/res/layout/item_branch.xml" value="0.24739583333333334" />
|
||||||
|
<entry key="app/src/main/res/layout/item_branch_dropdown.xml" value="0.25743589743589745" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ dependencies {
|
|||||||
|
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.1'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
testImplementation 'org.json:json:20201115'
|
testImplementation 'org.json:json:20201115'
|
||||||
testImplementation 'org.koin:koin-test:2.2.2'
|
testImplementation 'org.koin:koin-test:2.2.2'
|
||||||
}
|
}
|
||||||
@@ -9,5 +9,6 @@ data class MangaChapter(
|
|||||||
val name: String,
|
val name: String,
|
||||||
val number: Int,
|
val number: Int,
|
||||||
val url: String,
|
val url: String,
|
||||||
|
val branch: String? = null,
|
||||||
val source: MangaSource
|
val source: MangaSource
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
@@ -90,6 +90,8 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
|||||||
chapters = ArrayList(total)
|
chapters = ArrayList(total)
|
||||||
for (i in 0 until total) {
|
for (i in 0 until total) {
|
||||||
val item = list.getJSONObject(i)
|
val item = list.getJSONObject(i)
|
||||||
|
val chapterId = item.getLong("chapter_id")
|
||||||
|
val branchName = item.getStringOrNull("username")
|
||||||
val url = buildString {
|
val url = buildString {
|
||||||
append(manga.url)
|
append(manga.url)
|
||||||
append("/v")
|
append("/v")
|
||||||
@@ -106,9 +108,10 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
|
|||||||
}
|
}
|
||||||
chapters.add(
|
chapters.add(
|
||||||
MangaChapter(
|
MangaChapter(
|
||||||
id = generateUid(url),
|
id = generateUid(chapterId),
|
||||||
url = url,
|
url = url,
|
||||||
source = source,
|
source = source,
|
||||||
|
branch = branchName,
|
||||||
number = total - i,
|
number = total - i,
|
||||||
name = name
|
name = name
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,13 +3,10 @@ package org.koitharu.kotatsu.details.ui
|
|||||||
import android.app.ActivityOptions
|
import android.app.ActivityOptions
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
import android.widget.AdapterView
|
||||||
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
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.view.updatePadding
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.ui.BaseFragment
|
import org.koitharu.kotatsu.base.ui.BaseFragment
|
||||||
@@ -17,6 +14,7 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
|||||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||||
import org.koitharu.kotatsu.core.model.MangaSource
|
import org.koitharu.kotatsu.core.model.MangaSource
|
||||||
import org.koitharu.kotatsu.databinding.FragmentChaptersBinding
|
import org.koitharu.kotatsu.databinding.FragmentChaptersBinding
|
||||||
|
import org.koitharu.kotatsu.details.ui.adapter.BranchesAdapter
|
||||||
import org.koitharu.kotatsu.details.ui.adapter.ChaptersAdapter
|
import org.koitharu.kotatsu.details.ui.adapter.ChaptersAdapter
|
||||||
import org.koitharu.kotatsu.details.ui.adapter.ChaptersSelectionDecoration
|
import org.koitharu.kotatsu.details.ui.adapter.ChaptersSelectionDecoration
|
||||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||||
@@ -25,7 +23,7 @@ import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
|||||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||||
|
|
||||||
class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||||
OnListItemClickListener<MangaChapter>, ActionMode.Callback {
|
OnListItemClickListener<MangaChapter>, ActionMode.Callback, AdapterView.OnItemSelectedListener {
|
||||||
|
|
||||||
private val viewModel by sharedViewModel<DetailsViewModel>()
|
private val viewModel by sharedViewModel<DetailsViewModel>()
|
||||||
|
|
||||||
@@ -53,9 +51,21 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
|||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
adapter = chaptersAdapter
|
adapter = chaptersAdapter
|
||||||
}
|
}
|
||||||
|
val branchesAdapter = BranchesAdapter()
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
@@ -64,6 +74,7 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
|||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
chaptersAdapter = null
|
chaptersAdapter = null
|
||||||
selectionDecoration = null
|
selectionDecoration = null
|
||||||
|
binding.spinnerBranches.adapter = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +156,12 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||||
|
viewModel.setSelectedBranch(binding.spinnerBranches.selectedItem as String?)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
|
||||||
|
|
||||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||||
val manga = viewModel.manga.value
|
val manga = viewModel.manga.value
|
||||||
mode.menuInflater.inflate(R.menu.mode_chapters, menu)
|
mode.menuInflater.inflate(R.menu.mode_chapters, menu)
|
||||||
@@ -174,7 +191,7 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
|||||||
binding.recyclerViewChapters.updatePadding(
|
binding.recyclerViewChapters.updatePadding(
|
||||||
left = insets.left,
|
left = insets.left,
|
||||||
right = insets.right,
|
right = insets.right,
|
||||||
bottom = insets.bottom
|
bottom = insets.bottom + binding.spinnerBranches.height
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.koitharu.kotatsu.details.ui
|
package org.koitharu.kotatsu.details.ui
|
||||||
|
|
||||||
|
import androidx.lifecycle.asFlow
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -18,6 +19,7 @@ import org.koitharu.kotatsu.history.domain.HistoryRepository
|
|||||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||||
|
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
class DetailsViewModel(
|
class DetailsViewModel(
|
||||||
@@ -31,6 +33,7 @@ class DetailsViewModel(
|
|||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
||||||
|
private val selectedBranch = MutableStateFlow<String?>(null)
|
||||||
|
|
||||||
private val history = mangaData.mapNotNull { it?.id }
|
private val history = mangaData.mapNotNull { it?.id }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
@@ -69,12 +72,24 @@ class DetailsViewModel(
|
|||||||
|
|
||||||
val onMangaRemoved = SingleLiveEvent<Manga>()
|
val onMangaRemoved = SingleLiveEvent<Manga>()
|
||||||
|
|
||||||
|
val branches = mangaData.map {
|
||||||
|
it?.chapters?.mapToSet { x -> x.branch }?.sortedBy { x -> x }.orEmpty()
|
||||||
|
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||||
|
|
||||||
|
val selectedBranchIndex = combine(
|
||||||
|
branches.asFlow(),
|
||||||
|
selectedBranch
|
||||||
|
) { branches, selected ->
|
||||||
|
branches.indexOf(selected)
|
||||||
|
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||||
|
|
||||||
val chapters = combine(
|
val chapters = combine(
|
||||||
mangaData.map { it?.chapters.orEmpty() },
|
mangaData.map { it?.chapters.orEmpty() },
|
||||||
history.map { it?.chapterId },
|
history.map { it?.chapterId },
|
||||||
newChapters,
|
newChapters,
|
||||||
chaptersReversed
|
chaptersReversed,
|
||||||
) { chapters, currentId, newCount, reversed ->
|
selectedBranch
|
||||||
|
) { chapters, currentId, newCount, reversed, branch ->
|
||||||
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
||||||
val firstNewIndex = chapters.size - newCount
|
val firstNewIndex = chapters.size - newCount
|
||||||
val res = chapters.mapIndexed { index, chapter ->
|
val res = chapters.mapIndexed { index, chapter ->
|
||||||
@@ -86,7 +101,7 @@ class DetailsViewModel(
|
|||||||
else -> ChapterExtra.UNREAD
|
else -> ChapterExtra.UNREAD
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}.filter { it.chapter.branch == branch }
|
||||||
if (reversed) res.asReversed() else res
|
if (reversed) res.asReversed() else res
|
||||||
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||||
|
|
||||||
@@ -96,6 +111,15 @@ class DetailsViewModel(
|
|||||||
?: throw MangaNotFoundException("Cannot find manga")
|
?: throw MangaNotFoundException("Cannot find manga")
|
||||||
mangaData.value = manga
|
mangaData.value = manga
|
||||||
manga = manga.source.repository.getDetails(manga)
|
manga = manga.source.repository.getDetails(manga)
|
||||||
|
// find default branch
|
||||||
|
val hist = historyRepository.getOne(manga)
|
||||||
|
selectedBranch.value = if (hist != null) {
|
||||||
|
manga.chapters?.find { it.id == hist.chapterId }?.branch
|
||||||
|
} else {
|
||||||
|
manga.chapters
|
||||||
|
?.groupBy { it.branch }
|
||||||
|
?.maxByOrNull { it.value.size }?.key
|
||||||
|
}
|
||||||
mangaData.value = manga
|
mangaData.value = manga
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,4 +138,8 @@ class DetailsViewModel(
|
|||||||
fun setChaptersReversed(newValue: Boolean) {
|
fun setChaptersReversed(newValue: Boolean) {
|
||||||
settings.chaptersReverse = newValue
|
settings.chaptersReverse = newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setSelectedBranch(branch: String?) {
|
||||||
|
selectedBranch.value = branch
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.koitharu.kotatsu.details.ui.adapter
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.BaseAdapter
|
||||||
|
import android.widget.TextView
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.utils.ext.replaceWith
|
||||||
|
|
||||||
|
class BranchesAdapter : BaseAdapter() {
|
||||||
|
|
||||||
|
private val dataSet = ArrayList<String?>()
|
||||||
|
|
||||||
|
override fun getCount(): Int {
|
||||||
|
return dataSet.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItem(position: Int): Any? {
|
||||||
|
return dataSet[position]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemId(position: Int): Long {
|
||||||
|
return dataSet[position].hashCode().toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
val view = convertView ?: LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_branch, parent, false)
|
||||||
|
(view as TextView).text = dataSet[position]
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
val view = convertView ?: LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_branch_dropdown, parent, false)
|
||||||
|
(view as TextView).text = dataSet[position]
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setItems(items: Collection<String?>) {
|
||||||
|
dataSet.replaceWith(items)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ class ReaderViewModel(
|
|||||||
|
|
||||||
private var loadingJob: Job? = null
|
private var loadingJob: Job? = null
|
||||||
private val currentState = MutableStateFlow<ReaderState?>(null)
|
private val currentState = MutableStateFlow<ReaderState?>(null)
|
||||||
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
private val mangaData = MutableStateFlow(intent.manga)
|
||||||
private val chapters = LongSparseArray<MangaChapter>()
|
private val chapters = LongSparseArray<MangaChapter>()
|
||||||
|
|
||||||
val readerMode = MutableLiveData<ReaderMode>()
|
val readerMode = MutableLiveData<ReaderMode>()
|
||||||
@@ -58,7 +58,7 @@ class ReaderViewModel(
|
|||||||
)
|
)
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||||
|
|
||||||
val content = MutableLiveData<ReaderContent>(ReaderContent(emptyList(), null))
|
val content = MutableLiveData(ReaderContent(emptyList(), null))
|
||||||
val manga: Manga?
|
val manga: Manga?
|
||||||
get() = mangaData.value
|
get() = mangaData.value
|
||||||
|
|
||||||
@@ -80,7 +80,6 @@ class ReaderViewModel(
|
|||||||
manga.chapters?.forEach {
|
manga.chapters?.forEach {
|
||||||
chapters.put(it.id, it)
|
chapters.put(it.id, it)
|
||||||
}
|
}
|
||||||
mangaData.value = manga
|
|
||||||
// determine mode
|
// determine mode
|
||||||
val mode =
|
val mode =
|
||||||
dataRepository.getReaderMode(manga.id) ?: manga.chapters?.randomOrNull()?.let {
|
dataRepository.getReaderMode(manga.id) ?: manga.chapters?.randomOrNull()?.let {
|
||||||
@@ -96,6 +95,9 @@ class ReaderViewModel(
|
|||||||
currentState.value = state ?: historyRepository.getOne(manga)?.let {
|
currentState.value = state ?: historyRepository.getOne(manga)?.let {
|
||||||
ReaderState.from(it)
|
ReaderState.from(it)
|
||||||
} ?: ReaderState.initial(manga)
|
} ?: ReaderState.initial(manga)
|
||||||
|
|
||||||
|
val branch = chapters[currentState.value?.chapterId ?: 0L].branch
|
||||||
|
mangaData.value = manga.copy(chapters = manga.chapters?.filter { it.branch == branch })
|
||||||
readerMode.postValue(mode)
|
readerMode.postValue(mode)
|
||||||
|
|
||||||
val pages = loadChapter(requireNotNull(currentState.value).chapterId)
|
val pages = loadChapter(requireNotNull(currentState.value).chapterId)
|
||||||
|
|||||||
@@ -1,11 +1,29 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
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:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/app_bar"
|
||||||
|
style="@style/Widget.MaterialComponents.AppBarLayout.Surface"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$Behavior">
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinner_branches"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_scrollFlags="scroll|enterAlways"
|
||||||
|
tools:listitem="@layout/item_branch"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recyclerView_chapters"
|
android:id="@+id/recyclerView_chapters"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -18,6 +36,7 @@
|
|||||||
app:fastScrollVerticalThumbDrawable="@drawable/list_thumb"
|
app:fastScrollVerticalThumbDrawable="@drawable/list_thumb"
|
||||||
app:fastScrollVerticalTrackDrawable="@drawable/list_track"
|
app:fastScrollVerticalTrackDrawable="@drawable/list_track"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
tools:listitem="@layout/item_chapter" />
|
tools:listitem="@layout/item_chapter" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
@@ -29,4 +48,4 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
</FrameLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
9
app/src/main/res/layout/item_branch.xml
Normal file
9
app/src/main/res/layout/item_branch.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<CheckedTextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
style="?android:attr/spinnerItemStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?android:attr/listPreferredItemHeightSmall"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLargePopupMenu" />
|
||||||
9
app/src/main/res/layout/item_branch_dropdown.xml
Normal file
9
app/src/main/res/layout/item_branch_dropdown.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<CheckedTextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
style="?android:attr/spinnerDropDownItemStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?android:attr/listPreferredItemHeightSmall"
|
||||||
|
android:drawableEnd="?android:listChoiceIndicatorSingle"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLargePopupMenu" />
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.4.30'
|
ext.kotlin_version = '1.4.31'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
|||||||
Reference in New Issue
Block a user