@@ -50,6 +50,7 @@ data class AppWidgetGroup(
5050class WidgetFragment : BaseFragment () {
5151
5252 private lateinit var widgetGrid: FrameLayout
53+ private lateinit var emptyPlaceholder: TextView
5354 lateinit var appWidgetManager: AppWidgetManager
5455 lateinit var appWidgetHost: AppWidgetHost
5556 private val widgetWrappers = mutableListOf<ResizableWidgetWrapper >()
@@ -81,26 +82,44 @@ class WidgetFragment : BaseFragment() {
8182 super .onViewCreated(view, savedInstanceState)
8283
8384 requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
84- // Check if any widget is in resize mode
8585 val resizeWidget = widgetWrappers.firstOrNull { it.isResizeMode }
86-
8786 if (resizeWidget != null ) {
88- // Disable resize mode instead of going back
87+ AppLogger .i( TAG , " 🔄 Exiting resize mode for widgetId= ${resizeWidget.hostView.appWidgetId} " )
8988 resizeWidget.isResizeMode = false
9089 resizeWidget.setHandlesVisible(false )
9190 resizeWidget.reloadParentFragment()
9291 } else {
93- // No widget in resize mode, proceed with normal back
9492 isEnabled = false
9593 requireActivity().onBackPressed()
9694 }
9795 }
9896
9997 widgetGrid = view.findViewById(R .id.widget_grid)
98+ AppLogger .i(TAG , " 🟢 Widget grid initialized" )
99+ // Create placeholder programmatically
100+ AppLogger .i(TAG , " 🟢 Creating empty placeholder for widgets" )
101+ emptyPlaceholder = TextView (requireContext()).apply {
102+ text = context.getString(R .string.widgets_not_added)
103+ textSize = 16f
104+ setTextColor(resources.getColor(android.R .color.darker_gray, null ))
105+ gravity = Gravity .CENTER
106+ visibility = View .GONE
107+ }
108+ AppLogger .i(TAG , " 🟢 Empty placeholder TextView created" )
109+
110+ widgetGrid.addView(
111+ emptyPlaceholder, FrameLayout .LayoutParams (
112+ FrameLayout .LayoutParams .WRAP_CONTENT ,
113+ FrameLayout .LayoutParams .WRAP_CONTENT ,
114+ Gravity .CENTER
115+ )
116+ )
117+ AppLogger .i(TAG , " 🟢 Empty placeholder added to widgetGrid" )
100118
101119 appWidgetManager = AppWidgetManager .getInstance(requireContext())
102120 appWidgetHost = AppWidgetHost (requireContext(), APP_WIDGET_HOST_ID )
103121 appWidgetHost.startListening()
122+ AppLogger .i(TAG , " 🟢 AppWidgetHost started listening" )
104123
105124 widgetGrid.setOnLongClickListener {
106125 showGridMenu()
@@ -110,21 +129,21 @@ class WidgetFragment : BaseFragment() {
110129 restoreWidgets()
111130
112131 AppLogger .i(TAG , " 🟢 WidgetFragment onViewCreated, view is ready" )
113-
114- // Notify MainActivity to flush pending widgets
115132 (activity as ? MainActivity )?.flushPendingWidgets()
116133 }
117134
118135 override fun onResume () {
119136 super .onResume()
120137 restoreWidgets()
138+ AppLogger .i(TAG , " 🔄 WidgetFragment onResume, widgets restored" )
121139 }
122140
123141 /* * Grid menu for adding/resetting widgets */
124142 private fun showGridMenu () {
125143 activeGridDialog?.dismiss()
126144 val bottomSheetDialog = LockedBottomSheetDialog (requireContext())
127145 activeGridDialog = bottomSheetDialog
146+ AppLogger .d(TAG , " 🎛️ Showing widget grid menu" )
128147
129148 val container = LinearLayout (requireContext()).apply {
130149 orientation = LinearLayout .VERTICAL
@@ -149,16 +168,19 @@ class WidgetFragment : BaseFragment() {
149168 }
150169
151170 private fun resetAllWidgets () {
171+ AppLogger .w(TAG , " 🧹 Resetting all widgets" )
152172 widgetWrappers.forEach { wrapper ->
173+ AppLogger .d(TAG , " ❌ Deleting widgetId=${wrapper.hostView.appWidgetId} " )
153174 appWidgetHost.deleteAppWidgetId(wrapper.hostView.appWidgetId)
154175 }
155176 widgetWrappers.clear()
156177 widgetGrid.removeAllViews()
178+ widgetGrid.addView(emptyPlaceholder)
157179 saveWidgets()
158- AppLogger .i(TAG , " 🧹 Reset all widgets, cleared grid" )
180+ updateEmptyPlaceholder(widgetWrappers)
181+ AppLogger .i(TAG , " 🧹 All widgets cleared and placeholder shown" )
159182 }
160183
161- /* * Shows the system widget picker */
162184 private fun showCustomWidgetPicker () {
163185 val widgets = appWidgetManager.installedProviders
164186 val pm = requireContext().packageManager
@@ -174,6 +196,8 @@ class WidgetFragment : BaseFragment() {
174196 AppWidgetGroup (appName, appIcon, widgetList.toMutableList())
175197 }.sortedBy { it.appName.lowercase() }
176198
199+ AppLogger .d(TAG , " 🧩 Showing custom widget picker with ${grouped.size} apps" )
200+
177201 val container = LinearLayout (requireContext()).apply { orientation = LinearLayout .VERTICAL ; setPadding(16 , 16 , 16 , 16 ) }
178202 val scrollView = ScrollView (requireContext()).apply { addView(container) }
179203
@@ -212,6 +236,7 @@ class WidgetFragment : BaseFragment() {
212236 textSize = 14f
213237 setPadding(32 , 12 , 12 , 12 )
214238 setOnClickListener {
239+ AppLogger .i(TAG , " ➕ Selected widget ${widgetInfo.label} to add" )
215240 addWidget(widgetInfo)
216241 bottomSheetDialog.dismiss()
217242 }
@@ -234,7 +259,6 @@ class WidgetFragment : BaseFragment() {
234259 }
235260 }
236261
237- /* * Add a widget and handle permissions/configure activities */
238262 private fun addWidget (widgetInfo : AppWidgetProviderInfo ) {
239263 lastWidgetInfo = widgetInfo
240264 val widgetId = appWidgetHost.allocateAppWidgetId()
@@ -266,8 +290,7 @@ class WidgetFragment : BaseFragment() {
266290
267291 if (! bound) return
268292
269- // 🔽 Map widget’s min size to grid span
270- val parentFrame = requireActivity().findViewById<ViewGroup >(R .id.widget_grid) // adjust ID
293+ val parentFrame = requireActivity().findViewById<ViewGroup >(R .id.widget_grid)
271294 val gridWidth = parentFrame.width
272295 val cellSize = (gridWidth - (CELL_MARGIN * (GRID_COLUMNS - 1 ))) / GRID_COLUMNS
273296
@@ -276,25 +299,20 @@ class WidgetFragment : BaseFragment() {
276299
277300 AppLogger .d(TAG , " 📐 Widget ${widgetInfo.provider} requires ${spanX} x$spanY cells" )
278301
279- // 🔍 Get current occupancy
280302 val occupied = getOccupiedGrid()
281303 val maxRows = occupied.size.coerceAtLeast(1 )
282304
283- // 🔍 Find first free block that fits
284305 var foundRow = - 1
285306 var foundCol = - 1
286307
287- outer@ for (row in 0 until maxRows + 10 ) { // allow new rows
308+ outer@ for (row in 0 until maxRows + 10 ) {
288309 for (col in 0 until GRID_COLUMNS ) {
289310 var fits = true
290311 for (dy in 0 until spanY) {
291312 for (dx in 0 until spanX) {
292313 val r = row + dy
293314 val c = col + dx
294- if (c >= GRID_COLUMNS ) {
295- fits = false ; break
296- }
297- if (r < occupied.size && occupied[r][c]) {
315+ if (c >= GRID_COLUMNS || (r < occupied.size && occupied[r][c])) {
298316 fits = false ; break
299317 }
300318 }
@@ -314,11 +332,7 @@ class WidgetFragment : BaseFragment() {
314332 }
315333
316334 AppLogger .i(TAG , " 📦 Placing widget ${widgetInfo.provider} at row=$foundRow col=$foundCol span=${spanX} x$spanY " )
317-
318- // Save placement (so it’s included in JSON next time)
319335 saveWidgetPlacement(widgetId, foundRow, foundCol, spanX, spanY, parentFrame)
320-
321- // Create widget instance
322336 maybeConfigureOrCreate(widgetInfo, widgetId)
323337 }
324338
@@ -486,6 +500,7 @@ class WidgetFragment : BaseFragment() {
486500
487501 addWrapperToGrid(wrapper)
488502 AppLogger .i(TAG , " ✅ Wrapper created for widgetId=$appWidgetId " )
503+ updateEmptyPlaceholder(widgetWrappers)
489504 saveWidgets()
490505 }
491506
@@ -698,6 +713,22 @@ class WidgetFragment : BaseFragment() {
698713 AppLogger .i(TAG , " 📐 Grid Snapshot:\n $snapshot " )
699714 }
700715
716+ private fun updateEmptyPlaceholder (wrappers : List <ResizableWidgetWrapper >) {
717+ val wasVisible = emptyPlaceholder.isVisible
718+ val shouldBeVisible = wrappers.isEmpty()
719+
720+ emptyPlaceholder.isVisible = shouldBeVisible
721+
722+ if (shouldBeVisible && ! wasVisible) {
723+ AppLogger .i(TAG , " 🟨 No widgets present, showing placeholder" )
724+ } else if (! shouldBeVisible && wasVisible) {
725+ AppLogger .i(TAG , " 🟩 Widgets present, hiding placeholder" )
726+ } else {
727+ AppLogger .v(TAG , " 🔄 Placeholder visibility unchanged: ${emptyPlaceholder.isVisible} " )
728+ }
729+ }
730+
731+
701732 override fun onAttach (context : Context ) {
702733 super .onAttach(context)
703734 AppLogger .i(TAG , " 🔗 WidgetFragment onAttach called, context=$context " )
0 commit comments