Initial adding Explore screen
parent
6a8a6a08db
commit
b9428e3898
@ -0,0 +1,10 @@
|
|||||||
|
package org.koitharu.kotatsu.explore
|
||||||
|
|
||||||
|
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||||
|
import org.koin.dsl.module
|
||||||
|
import org.koitharu.kotatsu.explore.ui.ExploreViewModel
|
||||||
|
|
||||||
|
val exploreModule
|
||||||
|
get() = module {
|
||||||
|
viewModel { ExploreViewModel(get()) }
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
package org.koitharu.kotatsu.explore.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.graphics.Insets
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.BaseFragment
|
||||||
|
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
|
||||||
|
import org.koitharu.kotatsu.databinding.FragmentExploreBinding
|
||||||
|
import org.koitharu.kotatsu.explore.ui.adapter.ExploreAdapter
|
||||||
|
import org.koitharu.kotatsu.explore.ui.adapter.SourcesHeaderEventListener
|
||||||
|
import org.koitharu.kotatsu.library.ui.adapter.LibraryAdapter
|
||||||
|
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||||
|
|
||||||
|
class ExploreFragment : BaseFragment<FragmentExploreBinding>(),
|
||||||
|
RecyclerViewOwner,
|
||||||
|
SourcesHeaderEventListener {
|
||||||
|
|
||||||
|
private val viewModel by viewModel<ExploreViewModel>()
|
||||||
|
private var exploreAdapter: ExploreAdapter? = null
|
||||||
|
private var paddingHorizontal = 0
|
||||||
|
|
||||||
|
override val recyclerView: RecyclerView
|
||||||
|
get() = binding.recyclerView
|
||||||
|
|
||||||
|
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): FragmentExploreBinding {
|
||||||
|
return FragmentExploreBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
exploreAdapter = ExploreAdapter(get(), viewLifecycleOwner, this)
|
||||||
|
with(binding.recyclerView) {
|
||||||
|
adapter = exploreAdapter
|
||||||
|
setHasFixedSize(true)
|
||||||
|
val spacing = resources.getDimensionPixelOffset(R.dimen.list_spacing)
|
||||||
|
paddingHorizontal = spacing
|
||||||
|
}
|
||||||
|
viewModel.items.observe(viewLifecycleOwner) {
|
||||||
|
exploreAdapter!!.items = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
exploreAdapter = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onWindowInsetsChanged(insets: Insets) {
|
||||||
|
binding.root.updatePadding(
|
||||||
|
left = insets.left,
|
||||||
|
right = insets.right,
|
||||||
|
)
|
||||||
|
binding.recyclerView.updatePadding(
|
||||||
|
left = insets.left + paddingHorizontal,
|
||||||
|
right = insets.right + paddingHorizontal,
|
||||||
|
bottom = insets.bottom,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onManageClick(view: View) {
|
||||||
|
startActivity(SettingsActivity.newManageSourcesIntent(view.context))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRetryClick(error: Throwable) = Unit
|
||||||
|
|
||||||
|
override fun onEmptyActionClick() = Unit
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance() = ExploreFragment()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package org.koitharu.kotatsu.explore.ui
|
||||||
|
|
||||||
|
import androidx.core.os.LocaleListCompat
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.core.model.getLocaleTitle
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.explore.ui.model.ExploreItem
|
||||||
|
import org.koitharu.kotatsu.utils.ext.map
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
private const val KEY_ENABLED = "!"
|
||||||
|
|
||||||
|
class ExploreViewModel(
|
||||||
|
private val settings: AppSettings,
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
val items = MutableLiveData<List<ExploreItem>>(emptyList())
|
||||||
|
|
||||||
|
init {
|
||||||
|
buildList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildList() {
|
||||||
|
val sources = settings.getMangaSources(includeHidden = true)
|
||||||
|
val hiddenSources = settings.hiddenSources
|
||||||
|
val map = sources.groupByTo(TreeMap(LocaleKeyComparator())) {
|
||||||
|
if (it.name !in hiddenSources) {
|
||||||
|
KEY_ENABLED
|
||||||
|
} else {
|
||||||
|
it.locale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val result = ArrayList<ExploreItem>(sources.size + map.size + 1)
|
||||||
|
result += ExploreItem.Buttons
|
||||||
|
val enabledSources = map.remove(KEY_ENABLED)
|
||||||
|
if (!enabledSources.isNullOrEmpty()) {
|
||||||
|
result += ExploreItem.Header(R.string.enabled_sources)
|
||||||
|
enabledSources.mapTo(result) {
|
||||||
|
ExploreItem.Source(
|
||||||
|
source = it,
|
||||||
|
summary = it.getLocaleTitle(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.value = result
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LocaleKeyComparator : Comparator<String?> {
|
||||||
|
|
||||||
|
private val deviceLocales = LocaleListCompat.getAdjustedDefault()
|
||||||
|
.map { it.language }
|
||||||
|
|
||||||
|
override fun compare(a: String?, b: String?): Int {
|
||||||
|
when {
|
||||||
|
a == b -> return 0
|
||||||
|
a == null -> return 1
|
||||||
|
b == null -> return -1
|
||||||
|
}
|
||||||
|
val ai = deviceLocales.indexOf(a!!)
|
||||||
|
val bi = deviceLocales.indexOf(b!!)
|
||||||
|
return when {
|
||||||
|
ai < 0 && bi < 0 -> a.compareTo(b)
|
||||||
|
ai < 0 -> 1
|
||||||
|
bi < 0 -> -1
|
||||||
|
else -> ai.compareTo(bi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package org.koitharu.kotatsu.explore.ui.adapter
|
||||||
|
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import coil.ImageLoader
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||||
|
import org.koitharu.kotatsu.explore.ui.model.ExploreItem
|
||||||
|
|
||||||
|
class ExploreAdapter(
|
||||||
|
coil: ImageLoader,
|
||||||
|
lifecycleOwner: LifecycleOwner,
|
||||||
|
listener: SourcesHeaderEventListener,
|
||||||
|
) : AsyncListDifferDelegationAdapter<ExploreItem>(
|
||||||
|
ExploreDiffCallback(),
|
||||||
|
exploreButtonsDelegate(),
|
||||||
|
sourceHeaderDelegate(listener),
|
||||||
|
sourceItemDelegate(coil, lifecycleOwner),
|
||||||
|
) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
delegatesManager
|
||||||
|
.addDelegate(exploreButtonsDelegate())
|
||||||
|
.addDelegate(sourceHeaderDelegate(listener = listener))
|
||||||
|
.addDelegate(sourceItemDelegate(coil, lifecycleOwner))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
package org.koitharu.kotatsu.explore.ui.adapter
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import coil.ImageLoader
|
||||||
|
import coil.request.Disposable
|
||||||
|
import coil.request.ImageRequest
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.databinding.ItemExploreButtonsBinding
|
||||||
|
import org.koitharu.kotatsu.databinding.ItemExploreHeaderBinding
|
||||||
|
import org.koitharu.kotatsu.databinding.ItemExploreSourceBinding
|
||||||
|
import org.koitharu.kotatsu.explore.ui.model.ExploreItem
|
||||||
|
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||||
|
|
||||||
|
fun exploreButtonsDelegate() = adapterDelegateViewBinding<ExploreItem.Buttons, ExploreItem, ItemExploreButtonsBinding>(
|
||||||
|
{ layoutInflater, parent -> ItemExploreButtonsBinding.inflate(layoutInflater, parent, false) }
|
||||||
|
) {
|
||||||
|
|
||||||
|
binding.localStorage.requestFocus() // stub
|
||||||
|
|
||||||
|
} // TODO
|
||||||
|
|
||||||
|
fun sourceHeaderDelegate(
|
||||||
|
listener: SourcesHeaderEventListener,
|
||||||
|
) = adapterDelegateViewBinding<ExploreItem.Header, ExploreItem, ItemExploreHeaderBinding>(
|
||||||
|
{ layoutInflater, parent -> ItemExploreHeaderBinding.inflate(layoutInflater, parent, false) }
|
||||||
|
) {
|
||||||
|
|
||||||
|
val listenerAdapter = View.OnClickListener {
|
||||||
|
listener.onManageClick(itemView)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.buttonMore.setOnClickListener(listenerAdapter)
|
||||||
|
|
||||||
|
bind {
|
||||||
|
binding.textViewTitle.setText(R.string.remote_sources)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sourceItemDelegate(
|
||||||
|
coil: ImageLoader,
|
||||||
|
lifecycleOwner: LifecycleOwner,
|
||||||
|
) = adapterDelegateViewBinding<ExploreItem.Source, ExploreItem, ItemExploreSourceBinding>(
|
||||||
|
{ layoutInflater, parent -> ItemExploreSourceBinding.inflate(layoutInflater, parent, false) },
|
||||||
|
on = { item, _, _ -> item is ExploreItem.Source }
|
||||||
|
) {
|
||||||
|
|
||||||
|
var imageRequest: Disposable? = null
|
||||||
|
|
||||||
|
bind {
|
||||||
|
binding.textViewTitle.text = item.source.title
|
||||||
|
imageRequest = ImageRequest.Builder(context)
|
||||||
|
.data(item.faviconUrl)
|
||||||
|
.error(R.drawable.ic_favicon_fallback)
|
||||||
|
.target(binding.imageViewCover)
|
||||||
|
.lifecycle(lifecycleOwner)
|
||||||
|
.enqueueWith(coil)
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewRecycled {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
imageRequest = null
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package org.koitharu.kotatsu.explore.ui.adapter
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import org.koitharu.kotatsu.explore.ui.model.ExploreItem
|
||||||
|
|
||||||
|
class ExploreDiffCallback : DiffUtil.ItemCallback<ExploreItem>() {
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItem: ExploreItem, newItem: ExploreItem): Boolean {
|
||||||
|
return when {
|
||||||
|
oldItem.javaClass != newItem.javaClass -> false
|
||||||
|
oldItem is ExploreItem.Buttons && newItem is ExploreItem.Buttons -> {
|
||||||
|
oldItem == newItem
|
||||||
|
}
|
||||||
|
oldItem is ExploreItem.Source && newItem is ExploreItem.Source -> {
|
||||||
|
oldItem.source == newItem.source
|
||||||
|
}
|
||||||
|
oldItem is ExploreItem.Header && newItem is ExploreItem.Header -> {
|
||||||
|
oldItem.titleResId == newItem.titleResId
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: ExploreItem, newItem: ExploreItem): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package org.koitharu.kotatsu.explore.ui.adapter
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
|
||||||
|
|
||||||
|
interface SourcesHeaderEventListener : ListStateHolderListener {
|
||||||
|
|
||||||
|
fun onManageClick(view: View)
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package org.koitharu.kotatsu.explore.ui.model
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
|
sealed interface ExploreItem {
|
||||||
|
|
||||||
|
object Buttons : ExploreItem
|
||||||
|
|
||||||
|
class Header(
|
||||||
|
@StringRes val titleResId: Int,
|
||||||
|
) : ExploreItem {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as Header
|
||||||
|
return titleResId == other.titleResId
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int = titleResId
|
||||||
|
}
|
||||||
|
|
||||||
|
class Source(
|
||||||
|
val source: MangaSource,
|
||||||
|
val summary: String?,
|
||||||
|
) : ExploreItem {
|
||||||
|
|
||||||
|
val faviconUrl: Uri
|
||||||
|
get() = Uri.fromParts("favicon", source.name, null)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as Source
|
||||||
|
|
||||||
|
if (source != other.source) return false
|
||||||
|
if (summary != other.summary) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = source.hashCode()
|
||||||
|
result = 31 * result + summary.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
<?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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:paddingVertical="4dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/favourites"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/history"
|
||||||
|
app:icon="@drawable/ic_history" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/local_storage"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/local_storage"
|
||||||
|
app:icon="@drawable/ic_storage" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/suggestions"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/suggestions"
|
||||||
|
app:icon="@drawable/ic_suggestion" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/downloads"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/bookmarks"
|
||||||
|
app:icon="@drawable/ic_bookmark" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -1,7 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
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:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="@dimen/list_spacing"
|
||||||
|
android:paddingRight="@dimen/list_spacing"
|
||||||
|
android:paddingTop="@dimen/grid_spacing_outer"
|
||||||
|
android:paddingBottom="@dimen/grid_spacing_outer"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_explore_source" />
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
<?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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:paddingVertical="4dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/favourites"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/history"
|
||||||
|
app:icon="@drawable/ic_history"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/local_storage"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/local_storage"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/local_storage"
|
||||||
|
app:icon="@drawable/ic_storage"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/favourites"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/favourites" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/suggestions"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/suggestions"
|
||||||
|
app:icon="@drawable/ic_suggestion"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/downloads"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/favourites"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/favourites" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/downloads"
|
||||||
|
style="@style/Widget.Kotatsu.ExploreButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/bookmarks"
|
||||||
|
app:icon="@drawable/ic_bookmark"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/local_storage"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/suggestions"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/local_storage" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
style="@style/Widget.Kotatsu.ExploreButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
tools:icon="@drawable/ic_history"
|
|
||||||
tools:text="@string/history" />
|
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical|start"
|
||||||
|
android:padding="@dimen/grid_spacing"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.Kotatsu.SectionHeader"
|
||||||
|
tools:text="@tools:sample/lorem[2]" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_more"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/manage" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<?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="?attr/listPreferredItemHeightSmall"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:padding="@dimen/list_spacing">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/imageView_cover"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="h,1:1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover.Small"
|
||||||
|
tools:src="@tools:sample/backgrounds/scenic" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageView_cover"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/imageView_cover"
|
||||||
|
tools:text="Title" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
Loading…
Reference in New Issue