Skip to content

Commit e17d754

Browse files
committed
feat: Enhance BaseAdapter and BaseBottomSheetDialogFragment
- BaseAdapter: Improved click listener handling and added protected getters. - BaseBottomSheetDialogFragment: Added functions for expand, collapse, set height, dismiss, enable/disable interaction, and state observation.
1 parent c759573 commit e17d754

File tree

4 files changed

+120
-60
lines changed

4 files changed

+120
-60
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# CHANGELOG
22

3+
## [1.1.2] - 2024-07-26
4+
### Changed
5+
- **BaseAdapter**:
6+
- Refactored click listener handling to retain original click and long click listeners for views.
7+
- Added protected getter functions for `onItemViewClickListener`, `onItemClickListener`, `onItemViewLongClickListener`, `onItemLongClickListener`, `onItemViewDoubleClickListener`, and `onItemDoubleClickListener`.
8+
- Improved `setClickListenerForView` method to correctly manage existing click listeners on views.
9+
10+
### Fixed
11+
- **BaseAdapter**:
12+
- Fixed an issue where original click and long click listeners were overridden, leading to unexpected behavior.
13+
14+
### Added
15+
- **BaseBottomSheetDialogFragment**:
16+
- Added `setExpanded()` to expand the bottom sheet.
17+
- Added `setCollapsed()` to collapse the bottom sheet.
18+
- Added `setBottomSheetHeight(height: Int)` to set the height of the bottom sheet.
19+
- Added `dismissBottomSheet()` to hide and dismiss the bottom sheet.
20+
- Added `setHalfExpanded()` to half-expand the bottom sheet.
21+
- Added `setInteractionEnabled(enabled: Boolean)` to enable or disable user interaction with the bottom sheet.
22+
- Added `observeBottomSheetState(onStateChanged: (newState: Int) -> Unit)` to observe state changes of the bottom sheet.
23+
324
## [1.1.0] - 2024-07-19
425
### Added
526
- **BaseAdapter**

isseverCore/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ afterEvaluate {
9696
from(components["release"])
9797
groupId = "com.github.issever22"
9898
artifactId = "iCore"
99-
version = "1.1.1"
99+
version = "1.1.2"
100100

101101
pom {
102102
name.set("iCore")

isseverCore/src/main/java/com/issever/core/base/BaseAdapter.kt

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ import androidx.recyclerview.widget.RecyclerView
1010
import androidx.viewbinding.ViewBinding
1111
import com.issever.core.data.initialization.IsseverCore
1212

13-
abstract class BaseAdapter<T: Any, VB: ViewBinding>(
13+
abstract class BaseAdapter<T : Any, VB : ViewBinding>(
1414
private val bindingInflater: (LayoutInflater, ViewGroup, Boolean) -> VB
1515
) : RecyclerView.Adapter<BaseAdapter<T, VB>.BaseViewHolder>() {
1616

1717
open val coreLocalData: BaseLocalData by lazy { IsseverCore.getBaseLocalData() }
18-
inner class BaseViewHolder(val binding: VB): RecyclerView.ViewHolder(binding.root)
18+
19+
inner class BaseViewHolder(val binding: VB) : RecyclerView.ViewHolder(binding.root)
1920

2021
open val differ by lazy {
2122
AsyncListDiffer(this, object : DiffUtil.ItemCallback<T>() {
@@ -30,7 +31,10 @@ abstract class BaseAdapter<T: Any, VB: ViewBinding>(
3031
}
3132

3233
private var onItemViewClickListener: ((T, View) -> Unit)? = null
34+
protected fun getViewClickListener(): ((T, View) -> Unit)? = onItemViewClickListener
35+
3336
private var onItemClickListener: ((T) -> Unit)? = null
37+
protected fun getClickListener(): ((T) -> Unit)? = onItemClickListener
3438

3539
fun setOnItemViewClickListener(listener: (T, View) -> Unit) {
3640
onItemViewClickListener = listener
@@ -41,7 +45,10 @@ abstract class BaseAdapter<T: Any, VB: ViewBinding>(
4145
}
4246

4347
private var onItemViewLongClickListener: ((T, View) -> Unit)? = null
48+
protected fun getViewLongClickListener(): ((T, View) -> Unit)? = onItemViewLongClickListener
49+
4450
private var onItemLongClickListener: ((T) -> Unit)? = null
51+
protected fun getLongClickListener(): ((T) -> Unit)? = onItemLongClickListener
4552

4653
fun setOnItemViewLongClickListener(listener: (T, View) -> Unit) {
4754
onItemViewLongClickListener = listener
@@ -52,9 +59,13 @@ abstract class BaseAdapter<T: Any, VB: ViewBinding>(
5259
}
5360

5461
private var doubleClickTimeout: Long = 300L
62+
private var lastClickTime: Long = 0L
5563

5664
private var onItemViewDoubleClickListener: ((T, View) -> Unit)? = null
65+
protected fun getViewDoubleClickListener(): ((T, View) -> Unit)? = onItemViewDoubleClickListener
66+
5767
private var onItemDoubleClickListener: ((T) -> Unit)? = null
68+
protected fun getDoubleClickListener(): ((T) -> Unit)? = onItemDoubleClickListener
5869

5970
fun setOnItemViewDoubleClickListener(listener: (T, View) -> Unit) {
6071
onItemViewDoubleClickListener = listener
@@ -80,85 +91,74 @@ abstract class BaseAdapter<T: Any, VB: ViewBinding>(
8091

8192
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
8293
val item = getItem(position)
83-
bind(holder, item,holder.binding.root.context)
94+
bind(holder, item, holder.binding.root.context)
8495

85-
setClickListenerForView(item,holder.binding.root)
96+
setClickListenerForView(item, holder.binding.root)
8697
}
8798

99+
private val originalClickListeners = mutableMapOf<View, View.OnClickListener?>()
100+
101+
private val originalLongClickListeners = mutableMapOf<View, View.OnLongClickListener?>()
102+
88103
private fun setClickListenerForView(item: T, view: View) {
89-
var lastClickTime = 0L
90-
var clickCount = 0
91-
92-
val clickRunnable = Runnable {
93-
if (clickCount == 1) {
94-
onItemViewClickListener?.invoke(item, view)
95-
onItemClickListener?.invoke(item)
96-
} else if (clickCount == 2) {
97-
onItemViewDoubleClickListener?.invoke(item, view)
98-
onItemDoubleClickListener?.invoke(item)
104+
if (view.id != View.NO_ID || view.parent == null) {
105+
if (!originalClickListeners.containsKey(view)) {
106+
originalClickListeners[view] = try {
107+
val field = View::class.java.getDeclaredField("mListenerInfo")
108+
field.isAccessible = true
109+
val listenerInfo = field.get(view)
110+
val listenerField = listenerInfo.javaClass.getDeclaredField("mOnClickListener")
111+
listenerField.isAccessible = true
112+
listenerField.get(listenerInfo) as? View.OnClickListener
113+
} catch (e: Exception) {
114+
null
115+
}
99116
}
100-
clickCount = 0
101-
}
102117

103-
val isDoubleClickEnabled = onItemViewDoubleClickListener != null || onItemDoubleClickListener != null
118+
if (!originalLongClickListeners.containsKey(view)) {
119+
originalLongClickListeners[view] = try {
120+
val field = View::class.java.getDeclaredField("mListenerInfo")
121+
field.isAccessible = true
122+
val listenerInfo = field.get(view)
123+
val listenerField =
124+
listenerInfo.javaClass.getDeclaredField("mOnLongClickListener")
125+
listenerField.isAccessible = true
126+
listenerField.get(listenerInfo) as? View.OnLongClickListener
127+
} catch (e: Exception) {
128+
null
129+
}
130+
}
104131

105-
if (view.parent == null) {
106132
view.setOnClickListener {
107-
if (isDoubleClickEnabled) {
108-
val currentTime = System.currentTimeMillis()
109-
if (currentTime - lastClickTime < doubleClickTimeout) {
110-
clickCount++
111-
view.removeCallbacks(clickRunnable)
112-
} else {
113-
clickCount = 1
114-
}
115-
lastClickTime = currentTime
116-
view.postDelayed(clickRunnable, doubleClickTimeout)
133+
originalClickListeners[view]?.onClick(view)
134+
135+
val currentTime = System.currentTimeMillis()
136+
if (currentTime - lastClickTime < doubleClickTimeout) {
137+
onItemViewDoubleClickListener?.invoke(item, view)
138+
onItemDoubleClickListener?.invoke(item)
117139
} else {
118-
onItemViewClickListener?.invoke(item, it)
140+
onItemViewClickListener?.invoke(item, view)
119141
onItemClickListener?.invoke(item)
120142
}
143+
lastClickTime = currentTime
121144
}
122145

123146
view.setOnLongClickListener {
124-
onItemViewLongClickListener?.invoke(item, it)
147+
originalLongClickListeners[view]?.onLongClick(view)
148+
onItemViewLongClickListener?.invoke(item, view)
125149
onItemLongClickListener?.invoke(item)
126150
true
127151
}
128152
}
129153

130154
if (view is ViewGroup) {
131155
for (i in 0 until view.childCount) {
132-
val child = view.getChildAt(i)
133-
setClickListenerForView(item, child)
134-
}
135-
} else {
136-
view.setOnClickListener {
137-
if (isDoubleClickEnabled) {
138-
val currentTime = System.currentTimeMillis()
139-
if (currentTime - lastClickTime < doubleClickTimeout) {
140-
clickCount++
141-
view.removeCallbacks(clickRunnable)
142-
} else {
143-
clickCount = 1
144-
}
145-
lastClickTime = currentTime
146-
view.postDelayed(clickRunnable, doubleClickTimeout)
147-
} else {
148-
onItemViewClickListener?.invoke(item, it)
149-
onItemClickListener?.invoke(item)
150-
}
151-
}
152-
153-
view.setOnLongClickListener {
154-
onItemViewLongClickListener?.invoke(item, it)
155-
onItemLongClickListener?.invoke(item)
156-
true
156+
setClickListenerForView(item, view.getChildAt(i))
157157
}
158158
}
159159
}
160160

161-
abstract fun bind(holder: BaseViewHolder,item: T, context: Context)
161+
abstract fun bind(holder: BaseViewHolder, item: T, context: Context)
162162

163163
open fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
164164
return oldItem == newItem

isseverCore/src/main/java/com/issever/core/base/BaseBottomSheetDialogFragment.kt

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
1313
import com.issever.core.data.initialization.IsseverCore
1414
import com.issever.core.util.extensions.showSnackbar
1515

16-
abstract class BaseBottomSheetDialogFragment<VB : ViewBinding,VM : BaseViewModel?> : BottomSheetDialogFragment() {
16+
abstract class BaseBottomSheetDialogFragment<VB : ViewBinding, VM : BaseViewModel?> : BottomSheetDialogFragment() {
1717

1818
private var _binding: VB? = null
1919
open val binding get() = _binding!!
@@ -24,8 +24,9 @@ abstract class BaseBottomSheetDialogFragment<VB : ViewBinding,VM : BaseViewModel
2424
protected abstract fun initViewBinding(): VB
2525
protected open fun init() {}
2626
protected open fun initObservers() {}
27-
open var loadingView : View? = null
27+
open var loadingView: View? = null
2828
open lateinit var behavior: BottomSheetBehavior<FrameLayout>
29+
open var bottomSheet: FrameLayout? = null
2930

3031
override fun onCreateView(
3132
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
@@ -38,7 +39,7 @@ abstract class BaseBottomSheetDialogFragment<VB : ViewBinding,VM : BaseViewModel
3839
super.onViewCreated(view, savedInstanceState)
3940

4041
val dialog = dialog as BottomSheetDialog
41-
val bottomSheet = dialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
42+
bottomSheet = dialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
4243
behavior = BottomSheetBehavior.from(bottomSheet!!)
4344

4445
init()
@@ -53,6 +54,44 @@ abstract class BaseBottomSheetDialogFragment<VB : ViewBinding,VM : BaseViewModel
5354
initObservers()
5455
}
5556

57+
open fun setExpanded() {
58+
behavior.state = BottomSheetBehavior.STATE_EXPANDED
59+
}
60+
61+
open fun setCollapsed() {
62+
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
63+
}
64+
65+
open fun setBottomSheetHeight(height: Int) {
66+
val layoutParams = bottomSheet?.layoutParams
67+
layoutParams?.height = height
68+
bottomSheet?.layoutParams = layoutParams
69+
}
70+
71+
open fun dismissBottomSheet() {
72+
behavior.state = BottomSheetBehavior.STATE_HIDDEN
73+
dialog?.dismiss()
74+
}
75+
76+
open fun setHalfExpanded() {
77+
behavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
78+
}
79+
80+
open fun setInteractionEnabled(enabled: Boolean) {
81+
bottomSheet?.isClickable = enabled
82+
bottomSheet?.isFocusable = enabled
83+
}
84+
85+
open fun observeBottomSheetState(onStateChanged: (newState: Int) -> Unit) {
86+
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
87+
override fun onStateChanged(bottomSheet: View, newState: Int) {
88+
onStateChanged(newState)
89+
}
90+
91+
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
92+
})
93+
}
94+
5695
override fun onDestroyView() {
5796
super.onDestroyView()
5897
_binding = null

0 commit comments

Comments
 (0)