Skip to content

Commit 6a81010

Browse files
feat(UI): Add grab line to bottom and top sheet dialogs
This commit introduces a visual grab line to both the `FontBottomSheetDialogLocked` and `FontTopSheetDialogLocked` components to improve their appearance and affordance. Key changes: - A `View` with a rounded `GradientDrawable` is added to serve as a grab line. - In `FontBottomSheetDialogLocked`, the grab line is positioned at the top of the sheet. - In `FontTopSheetDialogLocked`, it is positioned at the bottom. - The layout logic is updated to wrap the content in a `FrameLayout` alongside the grab line, ensuring content is positioned correctly relative to the new grab line. - The previous `CardView` has been replaced by `MaterialCardView`. - Removed `setContentPadding` from `FontTopSheetDialogLocked` as margins now handle the required spacing.
1 parent 0ef40fd commit 6a81010

File tree

2 files changed

+111
-38
lines changed

2 files changed

+111
-38
lines changed

app/src/main/java/com/github/creativecodecat/components/views/FontBottomSheetDialogLocked.kt

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ package com.github.creativecodecat.components.views
22

33
import android.content.Context
44
import android.graphics.Typeface
5+
import android.graphics.drawable.GradientDrawable
56
import android.view.Gravity
67
import android.view.View
78
import android.view.ViewGroup
89
import android.view.WindowManager
910
import android.widget.FrameLayout
1011
import android.widget.TextView
1112
import androidx.appcompat.app.AppCompatDialog
12-
import androidx.cardview.widget.CardView
1313
import androidx.coordinatorlayout.widget.CoordinatorLayout
1414
import androidx.core.content.ContextCompat
1515
import com.github.droidworksstudio.common.isGestureNavigationEnabled
@@ -19,12 +19,13 @@ import com.github.droidworksstudio.mlauncher.helper.FontManager
1919
import com.google.android.material.card.MaterialCardView
2020

2121
/**
22-
* BottomSheetDialog using CardView for reliable rounded bottom corners.
22+
* BottomSheetDialog using CardView with a grab line at the top.
2323
*/
2424
class FontBottomSheetDialogLocked(context: Context) : AppCompatDialog(context), CustomFontView {
2525

2626
private val coordinator: CoordinatorLayout
27-
private val sheet: CardView
27+
private val sheet: MaterialCardView
28+
private val contentWrapper: FrameLayout
2829
private var cancelableFlag = true
2930

3031
override fun setCancelable(flag: Boolean) {
@@ -33,6 +34,8 @@ class FontBottomSheetDialogLocked(context: Context) : AppCompatDialog(context),
3334
}
3435

3536
init {
37+
val density = context.resources.displayMetrics.density
38+
3639
// Coordinator layout
3740
coordinator = CoordinatorLayout(context).apply {
3841
layoutParams = ViewGroup.LayoutParams(
@@ -42,18 +45,46 @@ class FontBottomSheetDialogLocked(context: Context) : AppCompatDialog(context),
4245
setOnClickListener { if (cancelableFlag) dismiss() }
4346
}
4447

45-
// Sheet wrapped in CardView
48+
// Sheet wrapped in MaterialCardView
4649
sheet = MaterialCardView(context).apply {
4750
layoutParams = CoordinatorLayout.LayoutParams(
4851
ViewGroup.LayoutParams.MATCH_PARENT,
4952
ViewGroup.LayoutParams.WRAP_CONTENT
5053
).apply { gravity = Gravity.BOTTOM }
5154

52-
cardElevation = 16 * context.resources.displayMetrics.density
55+
cardElevation = 16 * density
5356
setCardBackgroundColor(ContextCompat.getColor(context, R.color.colorPrimaryBackground))
5457
}
5558

59+
// Grab line at top
60+
val grabLine = View(context).apply {
61+
val widthPx = (40 * density).toInt()
62+
val heightPx = (4 * density).toInt()
63+
val topMarginPx = (10 * density).toInt()
64+
val bottomMarginPx = (8 * density).toInt()
65+
66+
layoutParams = FrameLayout.LayoutParams(widthPx, heightPx).apply {
67+
gravity = Gravity.CENTER_HORIZONTAL
68+
topMargin = topMarginPx
69+
bottomMargin = bottomMarginPx
70+
}
71+
background = GradientDrawable().apply {
72+
shape = GradientDrawable.RECTANGLE
73+
cornerRadius = 2 * density
74+
setColor(ContextCompat.getColor(context, R.color.colorAccent))
75+
}
76+
}
77+
78+
// Content wrapper inside sheet
79+
contentWrapper = FrameLayout(context).apply {
80+
layoutParams = FrameLayout.LayoutParams(
81+
ViewGroup.LayoutParams.MATCH_PARENT,
82+
ViewGroup.LayoutParams.WRAP_CONTENT
83+
)
84+
addView(grabLine) // always at index 0
85+
}
5686

87+
sheet.addView(contentWrapper)
5788
coordinator.addView(sheet)
5889
super.setContentView(coordinator)
5990

@@ -73,38 +104,44 @@ class FontBottomSheetDialogLocked(context: Context) : AppCompatDialog(context),
73104
}
74105

75106
override fun setContentView(view: View) {
76-
sheet.removeAllViews()
77-
sheet.addView(
107+
// Remove old content except the grab line (index 0)
108+
for (i in contentWrapper.childCount - 1 downTo 1) {
109+
contentWrapper.removeViewAt(i)
110+
}
111+
112+
// Remove parent if the view already has one
113+
(view.parent as? ViewGroup)?.removeView(view)
114+
115+
val density = context.resources.displayMetrics.density
116+
contentWrapper.addView(
78117
view, FrameLayout.LayoutParams(
79118
ViewGroup.LayoutParams.MATCH_PARENT,
80119
ViewGroup.LayoutParams.WRAP_CONTENT
81-
)
82-
)
120+
).apply {
121+
topMargin = (22 * density).toInt() // push below grab line
122+
})
83123
}
84124

85125
override fun onStart() {
86126
super.onStart()
87127

88128
// Apply font recursively
89129
window?.decorView?.let { rootView ->
90-
FontManager.getTypeface(context)?.let { typeface ->
91-
applyFontRecursively(rootView, typeface)
92-
}
130+
FontManager.getTypeface(context)?.let { applyFontRecursively(rootView, it) }
93131
}
94132

95-
// Add padding for gesture/status bar
133+
// Add padding for gesture navigation
96134
val bottomMargin = when (isGestureNavigationEnabled(context)) {
97135
true -> context.resources.getDimensionPixelSize(R.dimen.bottom_margin_gesture_nav)
98136
false -> context.resources.getDimensionPixelSize(R.dimen.bottom_margin_3_button_nav)
99137
}
100138

101-
// Apply side margins
102139
val sideMargin = context.resources.getDimensionPixelSize(R.dimen.bottom_sheet_side_margin)
103140
val lp = sheet.layoutParams as CoordinatorLayout.LayoutParams
104141
lp.setMargins(sideMargin, lp.topMargin, sideMargin, bottomMargin)
105142
sheet.layoutParams = lp
106143

107-
// Slide down from top
144+
// Slide up animation from bottom
108145
sheet.translationY = -sheet.height.toFloat()
109146
sheet.animate().translationY(0f).setDuration(250).start()
110147
}

app/src/main/java/com/github/creativecodecat/components/views/FontTopSheetDialogLocked.kt

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,30 @@ package com.github.creativecodecat.components.views
22

33
import android.content.Context
44
import android.graphics.Typeface
5+
import android.graphics.drawable.GradientDrawable
56
import android.view.Gravity
67
import android.view.View
78
import android.view.ViewGroup
89
import android.view.WindowManager
910
import android.widget.FrameLayout
1011
import android.widget.TextView
1112
import androidx.appcompat.app.AppCompatDialog
12-
import androidx.cardview.widget.CardView
1313
import androidx.coordinatorlayout.widget.CoordinatorLayout
1414
import androidx.core.content.ContextCompat
15+
import com.github.droidworksstudio.common.isGestureNavigationEnabled
1516
import com.github.droidworksstudio.mlauncher.R
1617
import com.github.droidworksstudio.mlauncher.helper.CustomFontView
1718
import com.github.droidworksstudio.mlauncher.helper.FontManager
1819
import com.google.android.material.card.MaterialCardView
1920

2021
/**
21-
* TopSheetDialog using CardView for reliable rounded bottom corners.
22+
* TopSheetDialog using CardView with a grab line at the bottom.
2223
*/
2324
class FontTopSheetDialogLocked(context: Context) : AppCompatDialog(context), CustomFontView {
2425

2526
private val coordinator: CoordinatorLayout
26-
private val sheet: CardView
27+
private val sheet: MaterialCardView
28+
private val contentWrapper: FrameLayout
2729
private var cancelableFlag = true
2830

2931
override fun setCancelable(flag: Boolean) {
@@ -32,6 +34,8 @@ class FontTopSheetDialogLocked(context: Context) : AppCompatDialog(context), Cus
3234
}
3335

3436
init {
37+
val density = context.resources.displayMetrics.density
38+
3539
// Coordinator layout
3640
coordinator = CoordinatorLayout(context).apply {
3741
layoutParams = ViewGroup.LayoutParams(
@@ -41,18 +45,46 @@ class FontTopSheetDialogLocked(context: Context) : AppCompatDialog(context), Cus
4145
setOnClickListener { if (cancelableFlag) dismiss() }
4246
}
4347

44-
// Sheet wrapped in CardView
48+
// Sheet wrapped in MaterialCardView
4549
sheet = MaterialCardView(context).apply {
4650
layoutParams = CoordinatorLayout.LayoutParams(
4751
ViewGroup.LayoutParams.MATCH_PARENT,
4852
ViewGroup.LayoutParams.WRAP_CONTENT
4953
).apply { gravity = Gravity.TOP }
5054

51-
cardElevation = 16 * context.resources.displayMetrics.density
55+
cardElevation = 16 * density
5256
setCardBackgroundColor(ContextCompat.getColor(context, R.color.colorPrimaryBackground))
5357
}
5458

59+
// Bottom grab line
60+
val grabLine = View(context).apply {
61+
val widthPx = (40 * density).toInt()
62+
val heightPx = (4 * density).toInt()
63+
val topMarginPx = (8 * density).toInt()
64+
val bottomMarginPx = (10 * density).toInt()
65+
66+
layoutParams = FrameLayout.LayoutParams(widthPx, heightPx).apply {
67+
gravity = Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM
68+
topMargin = topMarginPx
69+
bottomMargin = bottomMarginPx
70+
}
71+
background = GradientDrawable().apply {
72+
shape = GradientDrawable.RECTANGLE
73+
cornerRadius = 2 * density
74+
setColor(ContextCompat.getColor(context, R.color.colorAccent))
75+
}
76+
}
77+
78+
// Content wrapper inside sheet
79+
contentWrapper = FrameLayout(context).apply {
80+
layoutParams = FrameLayout.LayoutParams(
81+
ViewGroup.LayoutParams.MATCH_PARENT,
82+
ViewGroup.LayoutParams.WRAP_CONTENT
83+
)
84+
addView(grabLine) // always at index 0, bottom-aligned
85+
}
5586

87+
sheet.addView(contentWrapper)
5688
coordinator.addView(sheet)
5789
super.setContentView(coordinator)
5890

@@ -72,42 +104,46 @@ class FontTopSheetDialogLocked(context: Context) : AppCompatDialog(context), Cus
72104
}
73105

74106
override fun setContentView(view: View) {
75-
sheet.removeAllViews()
76-
sheet.addView(
107+
// Remove old content except grab line
108+
for (i in contentWrapper.childCount - 1 downTo 0) {
109+
val child = contentWrapper.getChildAt(i)
110+
if (child != contentWrapper.getChildAt(0)) contentWrapper.removeViewAt(i)
111+
}
112+
113+
// Remove from parent if needed
114+
(view.parent as? ViewGroup)?.removeView(view)
115+
116+
val density = context.resources.displayMetrics.density
117+
contentWrapper.addView(
77118
view, FrameLayout.LayoutParams(
78119
ViewGroup.LayoutParams.MATCH_PARENT,
79120
ViewGroup.LayoutParams.WRAP_CONTENT
80-
)
81-
)
121+
).apply {
122+
topMargin = 0 // adjust if you want padding above content
123+
bottomMargin = (22 * density).toInt() // leave space for grab line
124+
})
82125
}
83126

84127
override fun onStart() {
85128
super.onStart()
86129

87130
// Apply font recursively
88131
window?.decorView?.let { rootView ->
89-
FontManager.getTypeface(context)?.let { typeface ->
90-
applyFontRecursively(rootView, typeface)
91-
}
132+
FontManager.getTypeface(context)?.let { applyFontRecursively(rootView, it) }
92133
}
93134

94135
// Add padding for gesture/status bar
95-
val paddingBottom = context.resources.getDimensionPixelSize(R.dimen.bottom_sheet_side_margin)
96-
97-
sheet.setContentPadding(
98-
sheet.paddingLeft,
99-
sheet.paddingTop,
100-
sheet.paddingRight,
101-
paddingBottom
102-
)
136+
val bottomMargin = when (isGestureNavigationEnabled(context)) {
137+
true -> context.resources.getDimensionPixelSize(R.dimen.bottom_margin_gesture_nav)
138+
false -> context.resources.getDimensionPixelSize(R.dimen.bottom_margin_3_button_nav)
139+
}
103140

104-
// Apply side margins
105141
val sideMargin = context.resources.getDimensionPixelSize(R.dimen.bottom_sheet_side_margin)
106142
val lp = sheet.layoutParams as CoordinatorLayout.LayoutParams
107-
lp.setMargins(sideMargin, lp.topMargin, sideMargin, lp.bottomMargin)
143+
lp.setMargins(sideMargin, lp.topMargin, sideMargin, bottomMargin)
108144
sheet.layoutParams = lp
109145

110-
// Slide down from top
146+
// Slide down animation from top
111147
sheet.translationY = -sheet.height.toFloat()
112148
sheet.animate().translationY(0f).setDuration(250).start()
113149
}

0 commit comments

Comments
 (0)