From 6a3640bb928e9073b1f4ec5d4acbc532b0be32d9 Mon Sep 17 00:00:00 2001 From: Kenneth Soh Date: Mon, 25 Aug 2025 18:34:51 +0800 Subject: [PATCH 1/2] feat!: Switched to using Kotlin extensions for EdgeToEdge and pref helpers Legacy Java will call EdgeToEdgeHelperKt and PrefHelperKt respectively. This is a breaking change as it is moved to the context of the primary objects (context, views etc) --- .../helperlib/helpers/EdgeToEdgeHelper.kt | 198 ++++++++---------- .../helperlib/helpers/PrefHelper.kt | 82 ++++---- 2 files changed, 121 insertions(+), 159 deletions(-) diff --git a/helperlib/src/main/java/com/itachi1706/helperlib/helpers/EdgeToEdgeHelper.kt b/helperlib/src/main/java/com/itachi1706/helperlib/helpers/EdgeToEdgeHelper.kt index 6bcaaca..7897fa8 100644 --- a/helperlib/src/main/java/com/itachi1706/helperlib/helpers/EdgeToEdgeHelper.kt +++ b/helperlib/src/main/java/com/itachi1706/helperlib/helpers/EdgeToEdgeHelper.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package com.itachi1706.helperlib.helpers import android.view.View @@ -9,128 +11,94 @@ import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat -@Suppress("unused") -object EdgeToEdgeHelper { +/** + * Disable the window system windows to allow edge to edge layout + * @receiver The Application Window + */ +fun Window.disableWindowSystemWindows() { + WindowCompat.setDecorFitsSystemWindows(this, false) +} - /** - * Disable the window system windows to allow edge to edge layout - * @param window The window to disable system windows on - */ - @JvmStatic - fun disableWindowSystemWindows(window: Window) { - WindowCompat.setDecorFitsSystemWindows(window, false) - } +/** + * Set the view to be edge to edge with system bars + * @receiver The Application View + */ +fun View.setViewEdgeToEdge() { + this.setViewEdgeToEdge(WindowInsetsCompat.Type.systemBars()) +} - /** - * Set the view to be edge to edge with system bars - * @param view The view to set the insets on - */ - @JvmStatic - fun setViewEdgeToEdge(view: View) { - setViewEdgeToEdge(view, WindowInsetsCompat.Type.systemBars()) - } +/** + * Set the view to be edge to edge with a specific inset type + * @receiver The Application View + * @param insetType The type of insets to apply, e.g. [WindowInsetsCompat.Type.systemBars] + */ +fun View.setViewEdgeToEdge(@WindowInsetsCompat.Type.InsetsType insetType: Int) { + ViewCompat.setOnApplyWindowInsetsListener(this) { v, windowInsets -> + // Get the insets for the system bars (status bar, navigation bar) and apply padding + val insets = windowInsets.getInsets(insetType) + v.setPadding(insets.left, insets.top, insets.right, insets.bottom) - /** - * Set the view to be edge to edge with a specific inset type - * @param view The view to set the insets on - * @param insetType The type of insets to apply, e.g. [WindowInsetsCompat.Type.systemBars] - */ - @JvmStatic - fun setViewEdgeToEdge( - view: View, - @WindowInsetsCompat.Type.InsetsType insetType: Int - ) { - ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets -> - // Get the insets for the system bars (status bar, navigation bar) and apply padding - val insets = windowInsets.getInsets(insetType) - v.setPadding(insets.left, insets.top, insets.right, insets.bottom) - - WindowInsetsCompat.CONSUMED // Indicate that we have consumed the insets - } + WindowInsetsCompat.CONSUMED // Indicate that we have consumed the insets } +} - /** - * Set the activity to be edge to edge with system bars and set the content view - * @param view The view to set the insets on - * @param activity The activity to set the content view on - * @param layoutId The layout resource ID to set as content view - */ - @JvmStatic - fun setEdgeToEdgeWithContentView( - view: View, - activity: AppCompatActivity, - @LayoutRes layoutId: Int - ) { - disableWindowSystemWindows(activity.window) - activity.setContentView(layoutId) - setViewEdgeToEdge(view) - } +/** + * Set the activity to be edge to edge with system bars and set the content view + * @receiver AppCompat Activity + * @param view The view to set the insets on + * @param layoutId The layout resource ID to set as content view + */ +fun AppCompatActivity.setEdgeToEdgeWithContentView(view: View, @LayoutRes layoutId: Int) { + this.window.disableWindowSystemWindows() + this.setContentView(layoutId) + view.setViewEdgeToEdge() +} - /** - * Set the activity to be edge to edge with system bars and set the content view - * @param view The view to set the insets on - * @param activity The activity to set the content view on - * @param layoutView The view to set as content view - */ - @JvmStatic - fun setEdgeToEdgeWithContentView( - view: View, - activity: AppCompatActivity, - layoutView: View - ) { - disableWindowSystemWindows(activity.window) - activity.setContentView(layoutView) - setViewEdgeToEdge(view) - } +/** + * Set the activity to be edge to edge with system bars and set the content view + * @receiver AppCompat Activity + * @param view The view to set the insets on + * @param layoutView The view to set as content view + */ +fun AppCompatActivity.setEdgeToEdgeWithContentView(view: View, layoutView: View) { + this.window.disableWindowSystemWindows() + this.setContentView(layoutView) + view.setViewEdgeToEdge() +} - /** - * Set the activity to be edge to edge with system bars and set the content view - * @param viewId The ID of the view to set the insets on - * @param activity The activity to set the content view on - * @param layoutView The view to set as content view - */ - @JvmStatic - fun setEdgeToEdgeWithContentView( - @IdRes viewId: Int, - activity: AppCompatActivity, - layoutView: View - ) { - disableWindowSystemWindows(activity.window) - activity.setContentView(layoutView) - val view = activity.findViewById(viewId) - setViewEdgeToEdge(view) - } +/** + * Set the activity to be edge to edge with system bars and set the content view + * @receiver AppCompat Activity + * @param viewId The ID of the view to set the insets on + * @param layoutView The view to set as content view + */ +fun AppCompatActivity.setEdgeToEdgeWithContentView(@IdRes viewId: Int, layoutView: View) { + this.window.disableWindowSystemWindows() + this.setContentView(layoutView) + val view = this.findViewById(viewId) + view.setViewEdgeToEdge() +} - /** - * Set the activity to be edge to edge with system bars and set the content view - * @param viewId The ID of the view to set the insets on - * @param activity The activity to set the content view on - * @param layoutId The layout resource ID to set as content view - */ - @JvmStatic - fun setEdgeToEdgeWithContentView( - @IdRes viewId: Int, - activity: AppCompatActivity, - @LayoutRes layoutId: Int - ) { - disableWindowSystemWindows(activity.window) - activity.setContentView(layoutId) - val view = activity.findViewById(viewId) - setViewEdgeToEdge(view) - } +/** + * Set the activity to be edge to edge with system bars and set the content view + * @receiver AppCompat Activity + * @param viewId The ID of the view to set the insets on + * @param layoutId The layout resource ID to set as content view + */ +fun AppCompatActivity.setEdgeToEdgeWithContentView(@IdRes viewId: Int, @LayoutRes layoutId: Int) { + this.window.disableWindowSystemWindows() + this.setContentView(layoutId) + val view = this.findViewById(viewId) + view.setViewEdgeToEdge() +} - /** - * Set the activity to be edge to edge with system bars and set the content view - * @param layoutView The view to set the insets on - * @param activity The activity to set the content view on - */ - @JvmStatic - fun setEdgeToEdgeWithContentView( - layoutView: View, - activity: AppCompatActivity - ) { - disableWindowSystemWindows(activity.window) - activity.setContentView(layoutView) - setViewEdgeToEdge(layoutView) - } +/** + * Set the activity to be edge to edge with system bars and set the content view + * @receiver AppCompat Activity + * @param layoutView The view to set the insets on + */ +fun AppCompatActivity.setEdgeToEdgeWithContentView(layoutView: View) { + this.window.disableWindowSystemWindows() + this.setContentView(layoutView) + layoutView.setViewEdgeToEdge() } \ No newline at end of file diff --git a/helperlib/src/main/java/com/itachi1706/helperlib/helpers/PrefHelper.kt b/helperlib/src/main/java/com/itachi1706/helperlib/helpers/PrefHelper.kt index b3dbeb3..c06858d 100644 --- a/helperlib/src/main/java/com/itachi1706/helperlib/helpers/PrefHelper.kt +++ b/helperlib/src/main/java/com/itachi1706/helperlib/helpers/PrefHelper.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package com.itachi1706.helperlib.helpers import android.content.Context @@ -10,54 +12,46 @@ import androidx.appcompat.app.AppCompatDelegate import androidx.preference.PreferenceManager /** - * Created by Kenneth on 30/12/2019. - * for com.itachi1706.helperlib.helpers in Helper Library + * Wrapper to [PreferenceManager.getDefaultSharedPreferences] without invoking StrictMode Disk Read Policy Violation + * @receiver Application Context + * @return SharedPreference singleton object */ -@Suppress("unused") -object PrefHelper { - /** - * Wrapper to [PreferenceManager.getDefaultSharedPreferences] without invoking StrictMode Disk Read Policy Violation - * @param context Context object - * @return SharedPreference singleton object - */ - @JvmStatic - fun getDefaultSharedPreferences(context: Context): SharedPreferences { - val old = StrictMode.getThreadPolicy() - StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder(old).permitDiskReads().build()) - val sp = PreferenceManager.getDefaultSharedPreferences(context) - StrictMode.setThreadPolicy(old) - return sp - } +fun Context.getDefaultSharedPreferencesThreadSafe(): SharedPreferences { + val old = StrictMode.getThreadPolicy() + StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder(old).permitDiskReads().build()) + val sp = PreferenceManager.getDefaultSharedPreferences(this) + StrictMode.setThreadPolicy(old) + return sp +} - /** - * Wrapper to [Context.getSharedPreferences] without invoking StrictMode Disk Read Policy Violation - * @param context Context object - * @param name Name of Shared Preference File - * @param mode How to open the file in. Either [Context.MODE_PRIVATE], [Context.MODE_WORLD_READABLE], [Context.MODE_WORLD_WRITEABLE] or [Context.MODE_MULTI_PROCESS] - * @return SharedPreference singleton object - */ - @JvmOverloads - @JvmStatic - fun getSharedPreferences(context: Context, name: String, mode: Int = Context.MODE_PRIVATE): SharedPreferences { - val old = StrictMode.getThreadPolicy() - StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder(old).permitDiskReads().build()) - val sp = context.getSharedPreferences(name, mode) - StrictMode.setThreadPolicy(old) - return sp - } +/** + * Wrapper to [Context.getSharedPreferences] without invoking StrictMode Disk Read Policy Violation + * @receiver Application Context + * @param name Name of Shared Preference File + * @param mode How to open the file in. Either [Context.MODE_PRIVATE], [Context.MODE_WORLD_READABLE], [Context.MODE_WORLD_WRITEABLE] or [Context.MODE_MULTI_PROCESS] + * @return SharedPreference singleton object + */ +@JvmOverloads +fun Context.getSharedPreferencesThreadSafe(name: String, mode: Int = Context.MODE_PRIVATE): SharedPreferences { + val old = StrictMode.getThreadPolicy() + StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder(old).permitDiskReads().build()) + val sp = this.getSharedPreferences(name, mode) + StrictMode.setThreadPolicy(old) + return sp +} - /** - * Check if night mode is enabled - * @param context Activity Context - * @return false if Night mode is disabled, true otherwise - */ - @JvmStatic - fun isNightModeEnabled(context: Context): Boolean { - val currentNightMode = - context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - return currentNightMode != Configuration.UI_MODE_NIGHT_NO - } +/** + * Check if night mode is enabled + * @receiver Application Context + * @return false if Night mode is disabled, true otherwise + */ +fun Context.isNightModeEnabled(): Boolean { + val currentNightMode = + this.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK + return currentNightMode != Configuration.UI_MODE_NIGHT_NO +} +object PrefHelper { /** * Set Night Mode Theme. Options include: * [AppCompatDelegate.MODE_NIGHT_NO] From 4211733079850aacddd4b46e4e3f398c7fc6e259 Mon Sep 17 00:00:00 2001 From: Kenneth Soh Date: Mon, 25 Aug 2025 18:40:36 +0800 Subject: [PATCH 2/2] feat!: Migrated PendingIntentDep to Context extensions Fallback Java to PendingIntentDepKt --- .../helperlib/deprecation/PendingIntentDep.kt | 158 ++++++++---------- 1 file changed, 73 insertions(+), 85 deletions(-) diff --git a/helperlib/src/main/java/com/itachi1706/helperlib/deprecation/PendingIntentDep.kt b/helperlib/src/main/java/com/itachi1706/helperlib/deprecation/PendingIntentDep.kt index f41d6b3..90633d6 100644 --- a/helperlib/src/main/java/com/itachi1706/helperlib/deprecation/PendingIntentDep.kt +++ b/helperlib/src/main/java/com/itachi1706/helperlib/deprecation/PendingIntentDep.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package com.itachi1706.helperlib.deprecation import android.app.PendingIntent @@ -7,108 +9,94 @@ import android.os.Build import android.os.Bundle import androidx.annotation.RequiresApi -@Suppress("UnspecifiedImmutableFlag", "Unused") -object PendingIntentDep { - - @JvmStatic - @JvmOverloads - fun getImmutableActivity(activity: Context, code: Int, intent: Intent, flags: Int = 0, options: Bundle? = null): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getActivity(activity, code, intent, flags or PendingIntent.FLAG_IMMUTABLE, options) - } else { - PendingIntent.getActivity(activity, code, intent, flags, options) - } +@JvmOverloads +fun Context.getImmutableActivity(code: Int, intent: Intent, flags: Int = 0, options: Bundle? = null): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getActivity(this, code, intent, flags or PendingIntent.FLAG_IMMUTABLE, options) + } else { + PendingIntent.getActivity(this, code, intent, flags, options) } +} - @JvmStatic - @JvmOverloads - fun getMutableActivity(activity: Context, code: Int, intent: Intent, flags: Int = 0, options: Bundle? = null): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getActivity(activity, code, intent, flags or PendingIntent.FLAG_MUTABLE, options) - } else { - PendingIntent.getActivity(activity, code, intent, flags, options) - } +@JvmOverloads +fun Context.getMutableActivity(code: Int, intent: Intent, flags: Int = 0, options: Bundle? = null): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getActivity(this, code, intent, flags or PendingIntent.FLAG_MUTABLE, options) + } else { + PendingIntent.getActivity(this, code, intent, flags, options) } +} - @JvmStatic - @JvmOverloads - fun getImmutableActivities(activity: Context, code: Int, intents: Array, flags: Int = 0, options: Bundle? = null): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getActivities(activity, code, intents, flags or PendingIntent.FLAG_IMMUTABLE, options) - } else { - PendingIntent.getActivities(activity, code, intents, flags, options) - } +@JvmOverloads +fun Context.getImmutableActivities(code: Int, intents: Array, flags: Int = 0, options: Bundle? = null): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getActivities(this, code, intents, flags or PendingIntent.FLAG_IMMUTABLE, options) + } else { + PendingIntent.getActivities(this, code, intents, flags, options) } +} - @JvmStatic - @JvmOverloads - fun getMutableActivities(activity: Context, code: Int, intents: Array, flags: Int = 0, options: Bundle? = null): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getActivities(activity, code, intents, flags or PendingIntent.FLAG_MUTABLE, options) - } else { - PendingIntent.getActivities(activity, code, intents, flags, options) - } +@JvmOverloads +fun Context.getMutableActivities(code: Int, intents: Array, flags: Int = 0, options: Bundle? = null): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getActivities(this, code, intents, flags or PendingIntent.FLAG_MUTABLE, options) + } else { + PendingIntent.getActivities(this, code, intents, flags, options) } +} - @JvmStatic - @JvmOverloads - fun getImmutableBroadcast(activity: Context, code: Int, intent: Intent, flags: Int = 0): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getBroadcast(activity, code, intent, flags or PendingIntent.FLAG_IMMUTABLE) - } else { - PendingIntent.getBroadcast(activity, code, intent, flags) - } +@JvmOverloads +fun Context.getImmutableBroadcast(code: Int, intent: Intent, flags: Int = 0): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getBroadcast(this, code, intent, flags or PendingIntent.FLAG_IMMUTABLE) + } else { + PendingIntent.getBroadcast(this, code, intent, flags) } +} - @JvmStatic - @JvmOverloads - fun getMutableBroadcast(activity: Context, code: Int, intent: Intent, flags: Int = 0): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getBroadcast(activity, code, intent, flags or PendingIntent.FLAG_MUTABLE) - } else { - PendingIntent.getBroadcast(activity, code, intent, flags) - } +@JvmOverloads +fun Context.getMutableBroadcast(code: Int, intent: Intent, flags: Int = 0): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getBroadcast(this, code, intent, flags or PendingIntent.FLAG_MUTABLE) + } else { + PendingIntent.getBroadcast(this, code, intent, flags) } +} - @RequiresApi(Build.VERSION_CODES.O) - @JvmStatic - @JvmOverloads - fun getImmutableForegroundService(activity: Context, code: Int, intent: Intent, flags: Int = 0): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getForegroundService(activity, code, intent, flags or PendingIntent.FLAG_IMMUTABLE) - } else { - PendingIntent.getForegroundService(activity, code, intent, flags) - } +@RequiresApi(Build.VERSION_CODES.O) +@JvmOverloads +fun Context.getImmutableForegroundService(code: Int, intent: Intent, flags: Int = 0): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getForegroundService(this, code, intent, flags or PendingIntent.FLAG_IMMUTABLE) + } else { + PendingIntent.getForegroundService(this, code, intent, flags) } +} - @RequiresApi(Build.VERSION_CODES.O) - @JvmStatic - @JvmOverloads - fun getMutableForegroundService(activity: Context, code: Int, intent: Intent, flags: Int = 0): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getForegroundService(activity, code, intent, flags or PendingIntent.FLAG_MUTABLE) - } else { - PendingIntent.getForegroundService(activity, code, intent, flags) - } +@RequiresApi(Build.VERSION_CODES.O) +@JvmOverloads +fun Context.getMutableForegroundService(code: Int, intent: Intent, flags: Int = 0): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getForegroundService(this, code, intent, flags or PendingIntent.FLAG_MUTABLE) + } else { + PendingIntent.getForegroundService(this, code, intent, flags) } +} - @JvmStatic - @JvmOverloads - fun getImmutableService(activity: Context, code: Int, intent: Intent, flags: Int = 0): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getService(activity, code, intent, flags or PendingIntent.FLAG_IMMUTABLE) - } else { - PendingIntent.getService(activity, code, intent, flags) - } +@JvmOverloads +fun Context.getImmutableService(code: Int, intent: Intent, flags: Int = 0): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getService(this, code, intent, flags or PendingIntent.FLAG_IMMUTABLE) + } else { + PendingIntent.getService(this, code, intent, flags) } +} - @JvmStatic - @JvmOverloads - fun getMutableService(activity: Context, code: Int, intent: Intent, flags: Int = 0): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.getService(activity, code, intent, flags or PendingIntent.FLAG_MUTABLE) - } else { - PendingIntent.getService(activity, code, intent, flags) - } +@JvmOverloads +fun Context.getMutableService(code: Int, intent: Intent, flags: Int = 0): PendingIntent { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.getService(this, code, intent, flags or PendingIntent.FLAG_MUTABLE) + } else { + PendingIntent.getService(this, code, intent, flags) } } \ No newline at end of file