Merge pull request #1550 from Naveen3Singh/bottom_sheet

Bottom sheet related improvements
This commit is contained in:
Tibor Kaputa 2022-11-11 23:21:32 +01:00 committed by GitHub
commit 01b9cf1d70
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 187 additions and 170 deletions

View file

@ -7,9 +7,7 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.getProperTextColor
import com.simplemobiletools.commons.extensions.setImageResourceOrBeGone
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.models.SimpleListItem
import kotlinx.android.synthetic.main.item_simple_list.view.*
@ -29,30 +27,38 @@ open class SimpleListItemAdapter(val activity: Activity, val onItemClicked: (Sim
open inner class SimpleItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindView(item: SimpleListItem) {
itemView.apply {
val textColor = context.getProperTextColor()
bottom_sheet_item_title.setText(item.textRes)
bottom_sheet_item_title.setTextColor(textColor)
setupSimpleListItem(itemView, item, onItemClicked)
}
}
bottom_sheet_item_icon.setImageResourceOrBeGone(item.imageRes)
bottom_sheet_item_icon.applyColorFilter(textColor)
private class SimpleListItemDiffCallback : DiffUtil.ItemCallback<SimpleListItem>() {
override fun areItemsTheSame(oldItem: SimpleListItem, newItem: SimpleListItem): Boolean {
return SimpleListItem.areItemsTheSame(oldItem, newItem)
}
setOnClickListener {
onItemClicked(item)
}
}
override fun areContentsTheSame(oldItem: SimpleListItem, newItem: SimpleListItem): Boolean {
return SimpleListItem.areContentsTheSame(oldItem, newItem)
}
}
}
private class SimpleListItemDiffCallback : DiffUtil.ItemCallback<SimpleListItem>() {
fun setupSimpleListItem(view: View, item: SimpleListItem, onItemClicked: (SimpleListItem) -> Unit) {
view.apply {
val color = if (item.selected) {
context.getProperPrimaryColor()
} else {
context.getProperTextColor()
}
override fun areItemsTheSame(oldItem: SimpleListItem, newItem: SimpleListItem): Boolean {
return SimpleListItem.areItemsTheSame(oldItem, newItem)
bottom_sheet_item_title.setText(item.textRes)
bottom_sheet_item_title.setTextColor(color)
bottom_sheet_item_icon.setImageResourceOrBeGone(item.imageRes)
bottom_sheet_item_icon.applyColorFilter(color)
bottom_sheet_selected_icon.beVisibleIf(item.selected)
bottom_sheet_selected_icon.applyColorFilter(color)
setOnClickListener {
onItemClicked(item)
}
}
override fun areContentsTheSame(oldItem: SimpleListItem, newItem: SimpleListItem): Boolean {
return SimpleListItem.areContentsTheSame(oldItem, newItem)
}
}

View file

@ -0,0 +1,54 @@
package com.simplemobiletools.commons.dialogs
import android.os.Bundle
import android.view.ViewGroup
import androidx.fragment.app.FragmentManager
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.adapters.setupSimpleListItem
import com.simplemobiletools.commons.fragments.BaseBottomSheetDialogFragment
import com.simplemobiletools.commons.models.SimpleListItem
open class BottomSheetChooserDialog : BaseBottomSheetDialogFragment() {
var onItemClick: ((SimpleListItem) -> Unit)? = null
override fun setupContentView(parent: ViewGroup) {
val listItems = arguments?.getParcelableArray(ITEMS) as Array<SimpleListItem>
listItems.forEach { item ->
val view = layoutInflater.inflate(R.layout.item_simple_list, parent, false)
setupSimpleListItem(view, item) {
onItemClick?.invoke(it)
}
parent.addView(view)
}
}
override fun onDestroy() {
super.onDestroy()
onItemClick = null
}
companion object {
private const val TAG = "BottomSheetChooserDialog"
private const val ITEMS = "data"
fun createChooser(
fragmentManager: FragmentManager,
title: Int?,
items: Array<SimpleListItem>,
callback: (SimpleListItem) -> Unit
): BottomSheetChooserDialog {
val extras = Bundle().apply {
if (title != null) {
putInt(BOTTOM_SHEET_TITLE, title)
}
putParcelableArray(ITEMS, items)
}
return BottomSheetChooserDialog().apply {
arguments = extras
onItemClick = callback
show(fragmentManager, TAG)
}
}
}
}

View file

@ -1,110 +0,0 @@
package com.simplemobiletools.commons.dialogs
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.FragmentManager
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.adapters.SimpleListItemAdapter
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.models.SimpleListItem
import kotlinx.android.synthetic.main.dialog_bottom_sheet_chooser.*
class SimpleBottomSheetChooserDialog : BottomSheetDialogFragment() {
var onItemClick: ((SimpleListItem) -> Unit)? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.dialog_bottom_sheet_chooser, container, false)
val context = requireContext()
val config = context.baseConfig
if (!config.isUsingSystemTheme) {
val background = ResourcesCompat.getDrawable(context.resources, R.drawable.bottom_sheet_bg, context.theme)
val backgroundColor = context.getProperBackgroundColor()
(background as LayerDrawable).findDrawableByLayerId(R.id.bottom_sheet_background).applyColorFilter(backgroundColor)
view.background = background
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val title = arguments?.getInt(TITLE).takeIf { it != 0 }
val subtitle = arguments?.getInt(SUBTITLE).takeIf { it != 0 }
view.apply {
bottom_sheet_title.setTextColor(context.getProperTextColor())
bottom_sheet_title.setTextOrBeGone(title)
bottom_sheet_subtitle.setTextColor(context.getProperTextColor())
bottom_sheet_subtitle.setTextOrBeGone(subtitle)
setupRecyclerView()
}
}
@Suppress("UNCHECKED_CAST")
private fun setupRecyclerView() {
val listItems = arguments?.getParcelableArray(DATA) as Array<SimpleListItem>
getAudioRouteAdapter().submitList(listItems.toList())
}
private fun getAudioRouteAdapter(): SimpleListItemAdapter {
var adapter = bottom_sheet_recycler_view.adapter as? SimpleListItemAdapter
if (adapter == null) {
adapter = SimpleListItemAdapter(requireActivity()) {
onItemClick?.invoke(it)
dismissAllowingStateLoss()
}
bottom_sheet_recycler_view.adapter = adapter
}
return adapter
}
fun updateChooserItems(newItems: Array<SimpleListItem>) {
if (isAdded) {
getAudioRouteAdapter().submitList(newItems.toList())
}
}
override fun onDestroy() {
super.onDestroy()
onItemClick = null
}
companion object {
private const val TAG = "BottomSheetChooser"
private const val TITLE = "title_string"
private const val SUBTITLE = "subtitle_string"
private const val DATA = "data"
fun createChooser(
fragmentManager: FragmentManager,
title: Int?,
subtitle: Int?,
data: Array<SimpleListItem>,
callback: (SimpleListItem) -> Unit
): SimpleBottomSheetChooserDialog {
val extras = Bundle().apply {
if (title != null) {
putInt(TITLE, title)
}
if (subtitle != null) {
putInt(SUBTITLE, subtitle)
}
putParcelableArray(DATA, data)
}
return SimpleBottomSheetChooserDialog().apply {
arguments = extras
onItemClick = callback
show(fragmentManager, TAG)
}
}
}
}

View file

@ -0,0 +1,50 @@
package com.simplemobiletools.commons.fragments
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.extensions.*
import kotlinx.android.synthetic.main.dialog_bottom_sheet.view.*
abstract class BaseBottomSheetDialogFragment : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.dialog_bottom_sheet, container, false)
val context = requireContext()
val config = context.baseConfig
if (requireContext().isBlackAndWhiteTheme()) {
view.background = ResourcesCompat.getDrawable(context.resources, R.drawable.bottom_sheet_bg_black, context.theme)
} else if (!config.isUsingSystemTheme) {
view.background = ResourcesCompat.getDrawable(context.resources, R.drawable.bottom_sheet_bg, context.theme).apply {
(this as LayerDrawable).findDrawableByLayerId(R.id.bottom_sheet_background).applyColorFilter(context.getProperBackgroundColor())
}
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val title = arguments?.getInt(BOTTOM_SHEET_TITLE).takeIf { it != 0 }
view.apply {
bottom_sheet_title.setTextColor(context.getProperTextColor())
bottom_sheet_title.setTextOrBeGone(title)
setupContentView(bottom_sheet_content_holder)
}
}
abstract fun setupContentView(parent: ViewGroup)
companion object {
const val BOTTOM_SHEET_TITLE = "title_string"
}
}

View file

@ -4,7 +4,7 @@ import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
data class SimpleListItem(val id: Int, val imageRes: Int?, val textRes: Int) : Parcelable {
data class SimpleListItem(val id: Int, val textRes: Int, val imageRes: Int? = null, val selected: Boolean = false) : Parcelable {
companion object {
fun areItemsTheSame(old: SimpleListItem, new: SimpleListItem): Boolean {
@ -12,7 +12,7 @@ data class SimpleListItem(val id: Int, val imageRes: Int?, val textRes: Int) : P
}
fun areContentsTheSame(old: SimpleListItem, new: SimpleListItem): Boolean {
return old.imageRes == new.imageRes && old.textRes == new.textRes
return old.imageRes == new.imageRes && old.textRes == new.textRes && old.selected == new.selected
}
}
}

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/bottom_sheet_background"
android:bottom="-2dp">
<shape android:shape="rectangle">
<solid android:color="@color/md_grey_black" />
<stroke
android:width="1dp"
android:color="@color/light_grey_stroke" />
<corners
android:topLeftRadius="@dimen/bottom_sheet_corner_radius"
android:topRightRadius="@dimen/bottom_sheet_corner_radius" />
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="@android:color/white" android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
</vector>

View file

@ -1,5 +1,4 @@
<vector android:height="24dp" android:viewportHeight="500"
android:viewportWidth="500" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#34aadf" android:pathData="M250,500c138.071,0 250,-111.929 250,-250S388.071,0 250,0 0,111.929 0,250s111.929,250 250,250z"/>
<path android:fillColor="#fff" android:pathData="M104.047,247.832s125,-51.3 168.352,-69.364c16.619,-7.225 72.977,-30.347 72.977,-30.347s26.012,-10.115 23.844,14.451c-0.723,10.116 -6.503,45.52 -12.283,83.815 -8.671,54.191 -18.064,113.439 -18.064,113.439s-1.445,16.619 -13.728,19.509 -32.515,-10.115 -36.127,-13.006c-2.891,-2.167 -54.191,-34.682 -72.977,-50.578 -5.058,-4.335 -10.838,-13.005 0.722,-23.121 26.012,-23.844 57.081,-53.468 75.867,-72.254 8.671,-8.671 17.341,-28.902 -18.786,-4.336 -51.3,35.405 -101.878,68.642 -101.878,68.642s-11.561,7.225 -33.237,0.722c-21.677,-6.502 -46.966,-15.173 -46.966,-15.173s-17.34,-10.838 12.284,-22.399z"/>
<vector android:height="24dp" android:viewportHeight="500" android:viewportWidth="500" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF34AADF" android:pathData="M250 500c138.071 0 250-111.929 250-250S388.071 0 250 0 0 111.929 0 250s111.929 250 250 250z"/>
<path android:fillColor="@android:color/white" android:pathData="M104.047 247.832s125-51.3 168.352-69.364c16.619-7.225 72.977-30.347 72.977-30.347s26.012-10.115 23.844 14.451c-0.723 10.116-6.503 45.52-12.283 83.815-8.671 54.191-18.064 113.439-18.064 113.439s-1.445 16.619-13.728 19.509-32.515-10.115-36.127-13.006c-2.891-2.167-54.191-34.682-72.977-50.578-5.058-4.335-10.838-13.005 0.722-23.121 26.012-23.844 57.081-53.468 75.867-72.254 8.671-8.671 17.341-28.902-18.786-4.336-51.3 35.405-101.878 68.642-101.878 68.642s-11.561 7.225-33.237 0.722c-21.677-6.502-46.966-15.173-46.966-15.173s-17.34-10.838 12.284-22.399z"/>
</vector>

View file

@ -21,32 +21,17 @@
tools:text="Title"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/bottom_sheet_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/big_margin"
android:layout_marginTop="@dimen/medium_margin"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bottom_sheet_title"
tools:text="This is subtitle"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/bottom_sheet_recycler_view"
<LinearLayout
android:id="@+id/bottom_sheet_content_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="@dimen/activity_margin"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_marginTop="@dimen/activity_margin"
android:layout_marginBottom="@dimen/big_margin"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bottom_sheet_subtitle"
app:layout_constraintVertical_bias="0"
tools:itemCount="3"
tools:listitem="@layout/item_simple_list" />
app:layout_constraintTop_toBottomOf="@id/bottom_sheet_title"
app:layout_constraintVertical_bias="0" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -23,11 +23,25 @@
android:id="@+id/bottom_sheet_item_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/small_margin"
android:layout_marginHorizontal="@dimen/small_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@id/bottom_sheet_selected_icon"
app:layout_constraintStart_toEndOf="@id/bottom_sheet_item_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="ReadMe.md" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/bottom_sheet_selected_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/activity_margin"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_check_circle_vector"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/bottom_sheet_item_title"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,4 +1,4 @@
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme.Base" parent="Theme.Material3.Dark.NoActionBar">
<item name="colorPrimary">@color/color_primary</item>
@ -352,6 +352,8 @@
<item name="android:backgroundDimAmount">0.32</item>
<item name="bottomSheetStyle">@style/AppTheme.Material3.BottomSheetModalStyle</item>
<item name="elevationOverlayEnabled">true</item>
<item name="android:navigationBarColor">@color/you_status_bar_color</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@color/you_status_bar_color</item>
</style>
<style name="AppTheme.Material3.BottomSheetModalStyle" parent="Widget.Material3.BottomSheet.Modal">

View file

@ -11,7 +11,6 @@
# The setting is particularly useful for tweaking memory settings.
android.enableJetifier=true
android.useAndroidX=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects

View file

@ -2,7 +2,7 @@ package com.simplemobiletools.commons.samples.activities
import android.os.Bundle
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.dialogs.SimpleBottomSheetChooserDialog
import com.simplemobiletools.commons.dialogs.BottomSheetChooserDialog
import com.simplemobiletools.commons.extensions.appLaunched
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.models.SimpleListItem
@ -49,14 +49,13 @@ class MainActivity : BaseSimpleActivity() {
}
private fun launchBottomSheetDemo() {
SimpleBottomSheetChooserDialog.createChooser(
BottomSheetChooserDialog.createChooser(
fragmentManager = supportFragmentManager,
title = R.string.please_select_destination,
subtitle = null,
data = arrayOf(
SimpleListItem(1, R.drawable.ic_settings_cog_vector, R.string.choose_video),
SimpleListItem(2, R.drawable.ic_settings_cog_vector, R.string.choose_photo),
SimpleListItem(4, R.drawable.ic_settings_cog_vector, R.string.choose_contact)
items = arrayOf(
SimpleListItem(1, R.string.record_video, R.drawable.ic_camera_vector),
SimpleListItem(2, R.string.record_audio, R.drawable.ic_microphone_vector, selected = true),
SimpleListItem(4, R.string.choose_contact, R.drawable.ic_add_person_vector)
)
) {
toast("Clicked ${it.id}")