Skip to content

Commit 0fcfddb

Browse files
Feat: Added next alarm clock to home screen.
1 parent d6dc543 commit 0fcfddb

File tree

18 files changed

+307
-106
lines changed

18 files changed

+307
-106
lines changed

app/src/main/java/com/github/droidworksstudio/mlauncher/MainViewModel.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
3232
private val launcherDefault = MutableLiveData<Boolean>()
3333
val launcherResetFailed = MutableLiveData<Boolean>()
3434

35-
val showClock = MutableLiveData(prefs.showClock)
3635
val showDate = MutableLiveData(prefs.showDate)
36+
val showClock = MutableLiveData(prefs.showClock)
37+
val showAlarm = MutableLiveData(prefs.showAlarm)
3738
val clockAlignment = MutableLiveData(prefs.clockAlignment)
3839
val dateAlignment = MutableLiveData(prefs.dateAlignment)
40+
val alarmAlignment = MutableLiveData(prefs.alarmAlignment)
3941
val homeAppsAlignment = MutableLiveData(Pair(prefs.homeAlignment, prefs.homeAlignmentBottom))
4042
val homeAppsNum = MutableLiveData(prefs.homeAppsNum)
4143
val homePagesNum = MutableLiveData(prefs.homePagesNum)
@@ -80,6 +82,10 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
8082
showClock.value = visibility
8183
}
8284

85+
fun setShowAlarm(visibility: Boolean) {
86+
showAlarm.value = visibility
87+
}
88+
8389
private fun launchApp(appListItem: AppListItem) {
8490
val packageName = appListItem.activityPackage
8591
val appActivityName = appListItem.activityClass
@@ -146,12 +152,16 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
146152
prefs.drawerAlignment = gravity
147153
}
148154

155+
fun updateDateAlignment(gravity: Constants.Gravity) {
156+
dateAlignment.value = gravity
157+
}
158+
149159
fun updateClockAlignment(gravity: Constants.Gravity) {
150160
clockAlignment.value = gravity
151161
}
152162

153-
fun updateDateAlignment(gravity: Constants.Gravity) {
154-
dateAlignment.value = gravity
163+
fun updateAlarmAlignment(gravity: Constants.Gravity) {
164+
alarmAlignment.value = gravity
155165
}
156166

157167
fun updateHomeAppsAlignment(gravity: Constants.Gravity, onBottom: Boolean) {

app/src/main/java/com/github/droidworksstudio/mlauncher/data/Constants.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ object Constants {
3939
const val MIN_CLOCK_DATE_SIZE = 10
4040
const val MAX_CLOCK_DATE_SIZE = 120
4141

42+
const val MIN_ALARM_SIZE = 10
43+
const val MAX_ALARM_SIZE = 120
44+
4245
const val MIN_BATTERY_SIZE = 10
4346
const val MAX_BATTERY_SIZE = 75
4447

app/src/main/java/com/github/droidworksstudio/mlauncher/data/Prefs.kt

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ private const val HOME_CLICK_AREA = "HOME_CLICK_AREA"
3232
private const val DRAWER_ALIGNMENT = "DRAWER_ALIGNMENT"
3333
private const val CLOCK_ALIGNMENT = "CLOCK_ALIGNMENT"
3434
private const val DATE_ALIGNMENT = "DATE_ALIGNMENT"
35+
private const val ALARM_ALIGNMENT = "ALARM_ALIGNMENT"
3536
private const val STATUS_BAR = "STATUS_BAR"
3637
private const val SHOW_BATTERY = "SHOW_BATTERY"
3738
private const val SHOW_BATTERY_ICON = "SHOW_BATTERY_ICON"
@@ -40,6 +41,7 @@ private const val HOME_LOCKED = "HOME_LOCKED"
4041
private const val SETTINGS_LOCKED = "SETTINGS_LOCKED"
4142
private const val SHOW_CLOCK = "SHOW_CLOCK"
4243
private const val SHOW_CLOCK_FORMAT = "SHOW_CLOCK_FORMAT"
44+
private const val SHOW_ALARM = "SHOW_ALARM"
4345
private const val SEARCH_START = "SEARCH_START"
4446
private const val SWIPE_UP_ACTION = "SWIPE_UP_ACTION"
4547
private const val SWIPE_DOWN_ACTION = "SWIPE_DOWN_ACTION"
@@ -78,8 +80,9 @@ private const val CLICK_USAGE = "CLICK_USAGE"
7880
private const val CLICK_DATE = "CLICK_DATE"
7981
private const val DOUBLE_TAP = "DOUBLE_TAP"
8082
private const val APP_SIZE_TEXT = "APP_SIZE_TEXT"
81-
private const val CLOCK_SIZE_TEXT = "CLOCK_SIZE_TEXT"
8283
private const val DATE_SIZE_TEXT = "DATE_SIZE_TEXT"
84+
private const val CLOCK_SIZE_TEXT = "CLOCK_SIZE_TEXT"
85+
private const val ALARM_SIZE_TEXT = "ALARM_SIZE_TEXT"
8386
private const val BATTERY_SIZE_TEXT = "BATTERY_SIZE_TEXT"
8487
private const val TEXT_SIZE_SETTINGS = "TEXT_SIZE_SETTINGS"
8588
private const val TEXT_PADDING_SIZE = "TEXT_PADDING_SIZE"
@@ -256,6 +259,16 @@ class Prefs(val context: Context) {
256259
}
257260
set(value) = prefs.edit().putString(DATE_ALIGNMENT, value.toString()).apply()
258261

262+
var alarmAlignment: Gravity
263+
get() {
264+
val string = prefs.getString(
265+
ALARM_ALIGNMENT,
266+
Gravity.Left.name
267+
).toString()
268+
return Gravity.valueOf(string)
269+
}
270+
set(value) = prefs.edit().putString(ALARM_ALIGNMENT, value.toString()).apply()
271+
259272
var drawerAlignment: Gravity
260273
get() {
261274
val string = prefs.getString(
@@ -270,6 +283,10 @@ class Prefs(val context: Context) {
270283
get() = prefs.getBoolean(STATUS_BAR, false)
271284
set(value) = prefs.edit().putBoolean(STATUS_BAR, value).apply()
272285

286+
var showDate: Boolean
287+
get() = prefs.getBoolean(SHOW_DATE, true)
288+
set(value) = prefs.edit().putBoolean(SHOW_DATE, value).apply()
289+
273290
var showClock: Boolean
274291
get() = prefs.getBoolean(SHOW_CLOCK, true)
275292
set(value) = prefs.edit().putBoolean(SHOW_CLOCK, value).apply()
@@ -278,9 +295,9 @@ class Prefs(val context: Context) {
278295
get() = prefs.getBoolean(SHOW_CLOCK_FORMAT, true)
279296
set(value) = prefs.edit().putBoolean(SHOW_CLOCK_FORMAT, value).apply()
280297

281-
var showDate: Boolean
282-
get() = prefs.getBoolean(SHOW_DATE, true)
283-
set(value) = prefs.edit().putBoolean(SHOW_DATE, value).apply()
298+
var showAlarm: Boolean
299+
get() = prefs.getBoolean(SHOW_ALARM, true)
300+
set(value) = prefs.edit().putBoolean(SHOW_ALARM, value).apply()
284301

285302
var showBattery: Boolean
286303
get() = prefs.getBoolean(SHOW_BATTERY, true)
@@ -529,6 +546,16 @@ class Prefs(val context: Context) {
529546
}
530547
set(value) = prefs.edit().putInt(APP_SIZE_TEXT, value).apply()
531548

549+
var dateSize: Int
550+
get() {
551+
return try {
552+
prefs.getInt(DATE_SIZE_TEXT, 22)
553+
} catch (_: Exception) {
554+
22
555+
}
556+
}
557+
set(value) = prefs.edit().putInt(DATE_SIZE_TEXT, value).apply()
558+
532559
var clockSize: Int
533560
get() {
534561
return try {
@@ -539,15 +566,16 @@ class Prefs(val context: Context) {
539566
}
540567
set(value) = prefs.edit().putInt(CLOCK_SIZE_TEXT, value).apply()
541568

542-
var dateSize: Int
569+
var alarmSize: Int
543570
get() {
544571
return try {
545-
prefs.getInt(DATE_SIZE_TEXT, 22)
572+
prefs.getInt(ALARM_SIZE_TEXT, 20)
546573
} catch (_: Exception) {
547-
22
574+
20
548575
}
549576
}
550-
set(value) = prefs.edit().putInt(DATE_SIZE_TEXT, value).apply()
577+
set(value) = prefs.edit().putInt(ALARM_SIZE_TEXT, value).apply()
578+
551579

552580
var batterySize: Int
553581
get() {

app/src/main/java/com/github/droidworksstudio/mlauncher/helper/AppReloader.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,27 @@ package com.github.droidworksstudio.mlauncher.helper
22

33
import android.content.Context
44
import android.content.Intent
5-
import android.os.Handler
6-
import android.os.Looper
5+
import kotlinx.coroutines.DelicateCoroutinesApi
6+
import kotlinx.coroutines.Dispatchers
7+
import kotlinx.coroutines.GlobalScope
8+
import kotlinx.coroutines.delay
9+
import kotlinx.coroutines.launch
710

811
object AppReloader {
12+
// GlobalScope: "fire and forget", no lifecycle management
13+
@OptIn(DelicateCoroutinesApi::class)
914
fun restartApp(context: Context) {
1015
val packageManager = context.packageManager
1116
val intent = packageManager.getLaunchIntentForPackage(context.packageName)
1217
val componentName = intent?.component
1318
val mainIntent = Intent.makeRestartActivityTask(componentName)
1419

1520
// Delay the restart slightly to ensure all current activities are finished
16-
Handler(Looper.getMainLooper()).postDelayed({
21+
GlobalScope.launch(Dispatchers.Main) {
22+
delay(500) // Suspend function, avoids `Handler`
1723
context.startActivity(mainIntent)
1824
Runtime.getRuntime().exit(0)
19-
}, 500) // Delay of 500ms
25+
}
2026
}
21-
}
27+
}
28+

app/src/main/java/com/github/droidworksstudio/mlauncher/helper/DialogBuilder.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ class DialogBuilder(val context: Context, val activity: Activity) {
7272
prefs.clear()
7373

7474
AppReloader.restartApp(context)
75-
7675
}
7776

7877
var sliderDialog: AlertDialog? = null

app/src/main/java/com/github/droidworksstudio/mlauncher/helper/Utils.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.github.droidworksstudio.mlauncher.helper
22

33
//noinspection SuspiciousImport
44
import android.app.Activity
5+
import android.app.AlarmManager
56
import android.app.AlertDialog
67
import android.app.AppOpsManager
78
import android.app.UiModeManager
@@ -17,12 +18,16 @@ import android.os.Process
1718
import android.os.UserHandle
1819
import android.os.UserManager
1920
import android.provider.Settings
21+
import android.text.SpannableStringBuilder
22+
import android.text.style.ImageSpan
2023
import android.util.DisplayMetrics
2124
import android.util.Log.d
2225
import android.util.TypedValue
2326
import android.view.View
2427
import android.view.WindowInsets
2528
import android.view.WindowManager
29+
import androidx.annotation.RequiresApi
30+
import androidx.appcompat.content.res.AppCompatResources
2631
import com.github.droidworksstudio.common.openAccessibilitySettings
2732
import com.github.droidworksstudio.common.showLongToast
2833
import com.github.droidworksstudio.mlauncher.BuildConfig
@@ -193,6 +198,35 @@ fun getUserHandleFromString(context: Context, userHandleString: String): UserHan
193198
return Process.myUserHandle()
194199
}
195200

201+
@RequiresApi(Build.VERSION_CODES.Q)
202+
fun getNextAlarm(context: Context, prefs: Prefs): CharSequence {
203+
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
204+
val nextAlarmClock = alarmManager.nextAlarmClock ?: return "No alarm is set."
205+
206+
val alarmTime = nextAlarmClock.triggerTime
207+
val formattedTime = SimpleDateFormat("EEE, MMM d hh:mm a", Locale.getDefault()).format(alarmTime)
208+
209+
val drawable = AppCompatResources.getDrawable(context, R.drawable.ic_alarm_clock)
210+
val fontSize = TypedValue.applyDimension(
211+
TypedValue.COMPLEX_UNIT_SP,
212+
(prefs.alarmSize / 1.5).toFloat(),
213+
context.resources.displayMetrics
214+
).toInt()
215+
216+
drawable?.setBounds(0, 0, fontSize, fontSize)
217+
218+
return SpannableStringBuilder(" ").apply {
219+
drawable?.let {
220+
setSpan(
221+
ImageSpan(it, ImageSpan.ALIGN_CENTER),
222+
0, 1,
223+
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE
224+
)
225+
}
226+
append(" $formattedTime")
227+
}
228+
}
229+
196230
fun ismlauncherDefault(context: Context): Boolean {
197231
val launcherPackageName = getDefaultLauncherPackage(context)
198232
return BuildConfig.APPLICATION_ID == launcherPackageName

app/src/main/java/com/github/droidworksstudio/mlauncher/ui/HomeFragment.kt

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import android.view.ViewGroup
2424
import android.widget.LinearLayout
2525
import android.widget.Space
2626
import android.widget.TextView
27+
import androidx.annotation.RequiresApi
2728
import androidx.biometric.BiometricManager
2829
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
2930
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
@@ -58,6 +59,7 @@ import com.github.droidworksstudio.mlauncher.helper.AppDetailsHelper.getUsageSta
5859
import com.github.droidworksstudio.mlauncher.helper.AppReloader
5960
import com.github.droidworksstudio.mlauncher.helper.BatteryReceiver
6061
import com.github.droidworksstudio.mlauncher.helper.getHexForOpacity
62+
import com.github.droidworksstudio.mlauncher.helper.getNextAlarm
6163
import com.github.droidworksstudio.mlauncher.helper.hideStatusBar
6264
import com.github.droidworksstudio.mlauncher.helper.initActionService
6365
import com.github.droidworksstudio.mlauncher.helper.ismlauncherDefault
@@ -116,6 +118,7 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
116118
}
117119

118120

121+
@RequiresApi(Build.VERSION_CODES.Q)
119122
override fun onStart() {
120123
super.onStart()
121124
if (prefs.showStatusBar) showStatusBar(requireActivity()) else hideStatusBar(requireActivity())
@@ -148,6 +151,8 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
148151
date.format12Hour = datePattern
149152
date.format24Hour = datePattern
150153

154+
alarm.text = getNextAlarm(requireContext(), prefs)
155+
151156
clock.textSize = prefs.clockSize.toFloat()
152157
date.textSize = prefs.dateSize.toFloat()
153158
battery.textSize = prefs.batterySize.toFloat()
@@ -157,9 +162,9 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
157162
val backgroundColor = getHexForOpacity(prefs)
158163
mainLayout.setBackgroundColor(backgroundColor)
159164

160-
161-
clock.setTextColor(prefs.clockColor)
162165
date.setTextColor(prefs.dateColor)
166+
clock.setTextColor(prefs.clockColor)
167+
alarm.setTextColor(prefs.alarmClockColor)
163168
battery.setTextColor(prefs.batteryColor)
164169
totalScreenTime.setTextColor(prefs.appColor)
165170
setDefaultLauncher.setTextColor(prefs.appColor)
@@ -284,20 +289,39 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
284289

285290
with(viewModel) {
286291

287-
clockAlignment.observe(viewLifecycleOwner) { gravity ->
288-
binding.timeLayout.gravity = gravity.value()
292+
clockAlignment.observe(viewLifecycleOwner) { clockGravity ->
293+
binding.clock.gravity = clockGravity.value()
294+
295+
// Set layout_gravity to align the TextClock (clock) within the parent (LinearLayout)
296+
binding.clock.layoutParams = (binding.clock.layoutParams as LinearLayout.LayoutParams).apply {
297+
gravity = clockGravity.value()
298+
}
289299
}
290300

291-
dateAlignment.observe(viewLifecycleOwner) { gravity ->
292-
binding.dateLayout.gravity = gravity.value()
301+
dateAlignment.observe(viewLifecycleOwner) { dateGravity ->
302+
binding.date.gravity = dateGravity.value()
303+
304+
// Set layout_gravity to align the TextClock (date) within the parent (LinearLayout)
305+
binding.date.layoutParams = (binding.date.layoutParams as LinearLayout.LayoutParams).apply {
306+
gravity = dateGravity.value()
307+
}
308+
}
309+
310+
alarmAlignment.observe(viewLifecycleOwner) { alarmGravity ->
311+
binding.alarm.gravity = alarmGravity.value()
312+
313+
// Set layout_gravity to align the TextView (alarm) within the parent (LinearLayout)
314+
binding.alarm.layoutParams = (binding.alarm.layoutParams as LinearLayout.LayoutParams).apply {
315+
gravity = alarmGravity.value()
316+
}
293317
}
294318

295-
homeAppsAlignment.observe(viewLifecycleOwner) { (gravity, onBottom) ->
319+
homeAppsAlignment.observe(viewLifecycleOwner) { (homeAppsGravity, onBottom) ->
296320
val horizontalAlignment = if (onBottom) Gravity.BOTTOM else Gravity.CENTER_VERTICAL
297-
binding.homeAppsLayout.gravity = gravity.value() or horizontalAlignment
321+
binding.homeAppsLayout.gravity = homeAppsGravity.value() or horizontalAlignment
298322

299323
binding.homeAppsLayout.children.forEach { view ->
300-
(view as TextView).gravity = gravity.value()
324+
(view as TextView).gravity = homeAppsGravity.value()
301325
}
302326
}
303327
homeAppsNum.observe(viewLifecycleOwner) {
@@ -307,11 +331,14 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
307331
updateAppCount(it)
308332
}
309333
}
334+
showDate.observe(viewLifecycleOwner) {
335+
binding.date.visibility = if (it) View.VISIBLE else View.GONE
336+
}
310337
showClock.observe(viewLifecycleOwner) {
311338
binding.clock.visibility = if (it) View.VISIBLE else View.GONE
312339
}
313-
showDate.observe(viewLifecycleOwner) {
314-
binding.date.visibility = if (it) View.VISIBLE else View.GONE
340+
showAlarm.observe(viewLifecycleOwner) {
341+
binding.alarm.visibility = if (it) View.VISIBLE else View.GONE
315342
}
316343

317344
}
@@ -328,19 +355,21 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener
328355

329356
private fun showAppList(flag: AppDrawerFlag, includeHiddenApps: Boolean = false, n: Int = 0) {
330357
viewModel.getAppList(includeHiddenApps)
331-
lifecycleScope.launch(Dispatchers.Main) {
332-
try {
358+
try {
359+
if (findNavController().currentDestination?.id == R.id.mainFragment) {
333360
findNavController().navigate(
334361
R.id.action_mainFragment_to_appListFragment,
335362
bundleOf("flag" to flag.toString(), "n" to n)
336363
)
337-
} catch (e: Exception) {
364+
}
365+
} catch (e: Exception) {
366+
if (findNavController().currentDestination?.id == R.id.mainFragment) {
338367
findNavController().navigate(
339368
R.id.appListFragment,
340369
bundleOf("flag" to flag.toString())
341370
)
342-
e.printStackTrace()
343371
}
372+
e.printStackTrace()
344373
}
345374
}
346375

0 commit comments

Comments
 (0)