From 8173993601b9763673076d19ab6f5d8a25d3c63c Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Mon, 12 May 2025 15:37:18 +0200 Subject: [PATCH 1/7] add debug info widget in debug mode --- .../launcher/preferences/Preferences.kt | 35 ++++++++++++---- .../jrpie/android/launcher/ui/HomeActivity.kt | 7 ++-- .../android/launcher/ui/widgets/ClockView.kt | 4 +- .../launcher/ui/widgets/DebugInfoView.kt | 17 ++++++++ .../launcher/widgets/DebugInfoWidget.kt | 42 +++++++++++++++++++ .../widgets/LauncherWidgetProvider.kt | 10 ++--- .../jrpie/android/launcher/widgets/Widget.kt | 1 - .../jrpie/android/launcher/widgets/Widgets.kt | 4 +- .../layout/{home.xml => activity_home.xml} | 0 .../layout/{clock.xml => widget_clock.xml} | 0 app/src/main/res/layout/widget_debug_info.xml | 16 +++++++ 11 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/de/jrpie/android/launcher/ui/widgets/DebugInfoView.kt create mode 100644 app/src/main/java/de/jrpie/android/launcher/widgets/DebugInfoWidget.kt rename app/src/main/res/layout/{home.xml => activity_home.xml} (100%) rename app/src/main/res/layout/{clock.xml => widget_clock.xml} (100%) create mode 100644 app/src/main/res/layout/widget_debug_info.xml diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/Preferences.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/Preferences.kt index 34cf569..fd86d79 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/Preferences.kt +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/Preferences.kt @@ -16,6 +16,7 @@ import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersio import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersionUnknown import de.jrpie.android.launcher.ui.HomeActivity import de.jrpie.android.launcher.widgets.ClockWidget +import de.jrpie.android.launcher.widgets.DebugInfoWidget import de.jrpie.android.launcher.widgets.WidgetPanel import de.jrpie.android.launcher.widgets.WidgetPosition import de.jrpie.android.launcher.widgets.deleteAllWidgets @@ -95,17 +96,33 @@ fun resetPreferences(context: Context) { ) ) + if (BuildConfig.DEBUG) { + LauncherPreferences.widgets().widgets( + LauncherPreferences.widgets().widgets().also { + it.add( + DebugInfoWidget( + (context.applicationContext as Application).appWidgetHost.allocateAppWidgetId(), + WidgetPosition(1, 1, 10, 4), + WidgetPanel.HOME.id + ) + ) + } + ) + } val hidden: MutableSet = mutableSetOf() - val launcher = DetailedAppInfo.fromAppInfo( - AppInfo( - BuildConfig.APPLICATION_ID, - HomeActivity::class.java.name, - INVALID_USER - ), context - ) - launcher?.getRawInfo()?.let { hidden.add(it) } - Log.i(TAG,"Hiding ${launcher?.getRawInfo()}") + + if (!BuildConfig.DEBUG) { + val launcher = DetailedAppInfo.fromAppInfo( + AppInfo( + BuildConfig.APPLICATION_ID, + HomeActivity::class.java.name, + INVALID_USER + ), context + ) + launcher?.getRawInfo()?.let { hidden.add(it) } + Log.i(TAG, "Hiding ${launcher?.getRawInfo()}") + } LauncherPreferences.apps().hidden(hidden) Action.resetToDefaultActions(context) diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt index 957c902..f501107 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt @@ -12,11 +12,10 @@ import android.view.MotionEvent import android.view.View import android.window.OnBackInvokedDispatcher import de.jrpie.android.launcher.Application -import de.jrpie.android.launcher.R import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.LauncherAction -import de.jrpie.android.launcher.databinding.HomeBinding +import de.jrpie.android.launcher.databinding.ActivityHomeBinding import de.jrpie.android.launcher.openTutorial import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.tutorial.TutorialActivity @@ -35,7 +34,7 @@ import de.jrpie.android.launcher.ui.tutorial.TutorialActivity */ class HomeActivity : UIObject, Activity() { - private lateinit var binding: HomeBinding + private lateinit var binding: ActivityHomeBinding private var touchGestureDetector: TouchGestureDetector? = null private var sharedPreferencesListener = @@ -60,7 +59,7 @@ class HomeActivity : UIObject, Activity() { // Initialise layout - binding = HomeBinding.inflate(layoutInflater) + binding = ActivityHomeBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt index 33c4888..54d3869 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt @@ -6,13 +6,13 @@ import android.view.LayoutInflater import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import de.jrpie.android.launcher.actions.Gesture -import de.jrpie.android.launcher.databinding.ClockBinding +import de.jrpie.android.launcher.databinding.WidgetClockBinding import de.jrpie.android.launcher.preferences.LauncherPreferences import java.util.Locale class ClockView(context: Context, attrs: AttributeSet? = null, val appWidgetId: Int): ConstraintLayout(context, attrs) { - val binding: ClockBinding = ClockBinding.inflate(LayoutInflater.from(context), this, true) + val binding: WidgetClockBinding = WidgetClockBinding.inflate(LayoutInflater.from(context), this, true) init { initClock() setOnClicks() diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/DebugInfoView.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/DebugInfoView.kt new file mode 100644 index 0000000..d0ab70a --- /dev/null +++ b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/DebugInfoView.kt @@ -0,0 +1,17 @@ +package de.jrpie.android.launcher.ui.widgets + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.constraintlayout.widget.ConstraintLayout +import de.jrpie.android.launcher.databinding.WidgetDebugInfoBinding +import de.jrpie.android.launcher.getDeviceInfo + +class DebugInfoView(context: Context, attrs: AttributeSet? = null, val appWidgetId: Int): ConstraintLayout(context, attrs) { + + val binding: WidgetDebugInfoBinding = WidgetDebugInfoBinding.inflate(LayoutInflater.from(context), this, true) + + init { + binding.debugInfoText.text = getDeviceInfo() + } +} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/DebugInfoWidget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/DebugInfoWidget.kt new file mode 100644 index 0000000..01ecddc --- /dev/null +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/DebugInfoWidget.kt @@ -0,0 +1,42 @@ +package de.jrpie.android.launcher.widgets + +import android.app.Activity +import android.content.Context +import android.graphics.drawable.Drawable +import android.view.View +import de.jrpie.android.launcher.ui.widgets.DebugInfoView +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +@SerialName("widget:debuginfo") +class DebugInfoWidget( + override val id: Int, + override var position: WidgetPosition, + override val panelId: Int, + override var allowInteraction: Boolean = true +) : Widget() { + + override fun createView(activity: Activity): View { + return DebugInfoView(activity, null, id) + } + + override fun findView(views: Sequence): DebugInfoView? { + return views.mapNotNull { it as? DebugInfoView }.firstOrNull { it.appWidgetId == id } + } + + override fun getPreview(context: Context): Drawable? { + return null + } + + override fun getIcon(context: Context): Drawable? { + return null + } + + override fun isConfigurable(context: Context): Boolean { + return false + } + + override fun configure(activity: Activity, requestCode: Int) { } +} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/LauncherWidgetProvider.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/LauncherWidgetProvider.kt index 018b29b..92f33a9 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/LauncherWidgetProvider.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/LauncherWidgetProvider.kt @@ -37,13 +37,14 @@ class LauncherAppWidgetProvider(val info: AppWidgetProviderInfo) : LauncherWidge } } -class LauncherClockWidgetProvider : LauncherWidgetProvider() { - override fun loadLabel(context: Context): CharSequence? { +data object LauncherClockWidgetProvider : LauncherWidgetProvider() { + + override fun loadLabel(context: Context): CharSequence { return context.getString(R.string.widget_clock_label) } - override fun loadDescription(context: Context): CharSequence? { + override fun loadDescription(context: Context): CharSequence { return context.getString(R.string.widget_clock_description) } @@ -54,5 +55,4 @@ class LauncherClockWidgetProvider : LauncherWidgetProvider() { override fun loadIcon(context: Context): Drawable? { return AppCompatResources.getDrawable(context, R.drawable.baseline_clock_24) } -} - +} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt index e31250b..28539a2 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.content.Context import android.graphics.drawable.Drawable import android.view.View -import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.preferences.LauncherPreferences import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/Widgets.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/Widgets.kt index b7f140b..cded50c 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/Widgets.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/Widgets.kt @@ -53,7 +53,7 @@ fun bindAppWidgetOrRequestPermission(activity: Activity, providerInfo: AppWidget fun getAppWidgetProviders( context: Context ): List { - val list = mutableListOf(LauncherClockWidgetProvider()) + val list = mutableListOf(LauncherClockWidgetProvider) val appWidgetManager = context.getAppWidgetManager() val profiles = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -68,11 +68,9 @@ fun getAppWidgetProviders( context: Context ): List { }.flatten() ) - return list } - fun updateWidget(widget: Widget) { LauncherPreferences.widgets().widgets( (LauncherPreferences.widgets().widgets() ?: setOf()) diff --git a/app/src/main/res/layout/home.xml b/app/src/main/res/layout/activity_home.xml similarity index 100% rename from app/src/main/res/layout/home.xml rename to app/src/main/res/layout/activity_home.xml diff --git a/app/src/main/res/layout/clock.xml b/app/src/main/res/layout/widget_clock.xml similarity index 100% rename from app/src/main/res/layout/clock.xml rename to app/src/main/res/layout/widget_clock.xml diff --git a/app/src/main/res/layout/widget_debug_info.xml b/app/src/main/res/layout/widget_debug_info.xml new file mode 100644 index 0000000..1de9e43 --- /dev/null +++ b/app/src/main/res/layout/widget_debug_info.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file From 30e9fcd20f47c7e2b2fd69c0346b1d94e4f4c3ec Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Mon, 12 May 2025 16:05:15 +0200 Subject: [PATCH 2/7] show number of widgets for widget panel --- .../manage/ManageWidgetPanelsActivity.kt | 8 +++++--- .../manage/WidgetPanelsRecyclerAdapter.kt | 6 ++++++ .../android/launcher/widgets/WidgetPanel.kt | 6 ++++++ .../res/layout/list_widget_panels_row.xml | 20 ++++++++++++++++--- app/src/main/res/values/strings.xml | 4 ++-- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetPanelsActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetPanelsActivity.kt index cb57fda..163777f 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetPanelsActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetPanelsActivity.kt @@ -18,13 +18,16 @@ import de.jrpie.android.launcher.widgets.updateWidgetPanel class ManageWidgetPanelsActivity : AppCompatActivity(), UIObject { + @SuppressLint("NotifyDataSetChanged") private val sharedPreferencesListener = SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> - if (prefKey == LauncherPreferences.widgets().keys().customPanels()) { + if ( + prefKey == LauncherPreferences.widgets().keys().customPanels() + || prefKey == LauncherPreferences.widgets().keys().widgets() + ) { viewAdapter.widgetPanels = (LauncherPreferences.widgets().customPanels() ?: setOf()).toTypedArray() - @SuppressLint("NotifyDataSetChanged") viewAdapter.notifyDataSetChanged() } } @@ -76,7 +79,6 @@ class ManageWidgetPanelsActivity : AppCompatActivity(), UIObject { ) ) } - true } } diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetPanelsRecyclerAdapter.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetPanelsRecyclerAdapter.kt index 40c2c2f..d27ba9a 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetPanelsRecyclerAdapter.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetPanelsRecyclerAdapter.kt @@ -26,10 +26,16 @@ class WidgetPanelsRecyclerAdapter( class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var labelView: TextView = itemView.findViewById(R.id.list_widget_panels_label) + var infoView: TextView = itemView.findViewById(R.id.list_widget_panels_info) } override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { viewHolder.labelView.text = widgetPanels[i].label + val numWidgets = widgetPanels[i].getWidgets().size + viewHolder.infoView.text = context.resources.getQuantityString( + R.plurals.widget_panel_number_of_widgets, + numWidgets, numWidgets + ) viewHolder.itemView.setOnClickListener { onSelectWidgetPanel(widgetPanels[i]) diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPanel.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPanel.kt index 93e588d..e56983a 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPanel.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPanel.kt @@ -32,6 +32,12 @@ class WidgetPanel(val id: Int, var label: String) { .filter { it.panelId == this.id }.forEach { it.delete(context) } } + fun getWidgets(): List { + return LauncherPreferences.widgets().widgets().filter { + it.panelId == this.id + } + } + companion object { val HOME = WidgetPanel(0, "home") diff --git a/app/src/main/res/layout/list_widget_panels_row.xml b/app/src/main/res/layout/list_widget_panels_row.xml index 53f7449..835050f 100644 --- a/app/src/main/res/layout/list_widget_panels_row.xml +++ b/app/src/main/res/layout/list_widget_panels_row.xml @@ -1,6 +1,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 46fce3d..d399d12 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -406,8 +406,8 @@ Widget Panel #%1$d - Contains %d widget. - Contains %d widgets. + Contains %1$d widget. + Contains %1$d widgets. From 33ccea8cbcad5fc6daead8daf59716017c0c0474 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Mon, 12 May 2025 16:33:59 +0200 Subject: [PATCH 3/7] fix #162 - place new widgets in free area if possible --- .../widgets/manage/ManageWidgetsActivity.kt | 17 +++--- .../launcher/widgets/WidgetPosition.kt | 58 ++++++++++++++++--- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetsActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetsActivity.kt index 6fec855..4b5c0c2 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetsActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetsActivity.kt @@ -17,9 +17,12 @@ import de.jrpie.android.launcher.databinding.ActivityManageWidgetsBinding import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.UIObject import de.jrpie.android.launcher.widgets.AppWidget +import de.jrpie.android.launcher.widgets.GRID_SIZE import de.jrpie.android.launcher.widgets.WidgetPanel import de.jrpie.android.launcher.widgets.WidgetPosition +import kotlin.math.max import kotlin.math.min +import kotlin.math.roundToInt // http://coderender.blogspot.com/2012/01/hosting-android-widgets-my.html @@ -143,14 +146,12 @@ class ManageWidgetsActivity : UIObject, Activity() { val display = windowManager.defaultDisplay - val position = WidgetPosition.fromAbsoluteRect( - Rect( - 0, 0, - min(400, appWidgetManager.getAppWidgetInfo(appWidgetId).minWidth), - min(400, appWidgetManager.getAppWidgetInfo(appWidgetId).minHeight) - ), - display.width, - display.height + val widgetInfo = appWidgetManager.getAppWidgetInfo(appWidgetId) + + val position = WidgetPosition.findFreeSpace( + WidgetPanel.byId(panelId), + max(3, (GRID_SIZE * (widgetInfo.minWidth) / display.width.toFloat()).roundToInt()), + max(3, (GRID_SIZE * (widgetInfo.minHeight) / display.height.toFloat()).roundToInt()) ) val widget = AppWidget(appWidgetId, position, panelId, provider) diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPosition.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPosition.kt index b575665..e51f00c 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPosition.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPosition.kt @@ -11,9 +11,20 @@ const val GRID_SIZE: Short = 12 @Serializable data class WidgetPosition(var x: Short, var y: Short, var width: Short, var height: Short) { + constructor(rect: Rect) : this( + rect.left.toShort(), + rect.top.toShort(), + (rect.right - rect.left).toShort(), + (rect.bottom - rect.top).toShort() + ) + + fun toRect(): Rect { + return Rect(x.toInt(), y.toInt(), x + width, y + height) + } + fun getAbsoluteRect(screenWidth: Int, screenHeight: Int): Rect { val gridWidth = screenWidth / GRID_SIZE.toFloat() - val gridHeight= screenHeight / GRID_SIZE.toFloat() + val gridHeight = screenHeight / GRID_SIZE.toFloat() return Rect( (x * gridWidth).toInt(), @@ -23,25 +34,33 @@ data class WidgetPosition(var x: Short, var y: Short, var width: Short, var heig ) } + companion object { fun fromAbsoluteRect(absolute: Rect, screenWidth: Int, screenHeight: Int): WidgetPosition { val gridWidth = screenWidth / GRID_SIZE.toFloat() - val gridHeight= screenHeight / GRID_SIZE.toFloat() + val gridHeight = screenHeight / GRID_SIZE.toFloat() - val x = (absolute.left / gridWidth).roundToInt().toShort().coerceIn(0, (GRID_SIZE-1).toShort()) - val y = (absolute.top / gridHeight).roundToInt().toShort().coerceIn(0, (GRID_SIZE-1).toShort()) + val x = (absolute.left / gridWidth).roundToInt().toShort() + .coerceIn(0, (GRID_SIZE - 1).toShort()) + val y = (absolute.top / gridHeight).roundToInt().toShort() + .coerceIn(0, (GRID_SIZE - 1).toShort()) val w = max(2, ((absolute.right - absolute.left) / gridWidth).roundToInt()).toShort() val h = max(2, ((absolute.bottom - absolute.top) / gridHeight).roundToInt()).toShort() - return WidgetPosition(x,y,w,h) + return WidgetPosition(x, y, w, h) } - fun center(minWidth: Int, minHeight: Int, screenWidth: Int, screenHeight: Int): WidgetPosition { + fun center( + minWidth: Int, + minHeight: Int, + screenWidth: Int, + screenHeight: Int + ): WidgetPosition { val gridWidth = screenWidth / GRID_SIZE.toFloat() - val gridHeight= screenHeight / GRID_SIZE.toFloat() + val gridHeight = screenHeight / GRID_SIZE.toFloat() val cellsWidth = ceil(minWidth / gridWidth).toInt().toShort() val cellsHeight = ceil(minHeight / gridHeight).toInt().toShort() @@ -52,7 +71,32 @@ data class WidgetPosition(var x: Short, var y: Short, var width: Short, var heig cellsWidth, cellsHeight ) + } + fun findFreeSpace( + widgetPanel: WidgetPanel?, + minWidth: Int, + minHeight: Int + ): WidgetPosition { + val rect = Rect(0, 0, minWidth, minHeight) + if (widgetPanel == null) { + return WidgetPosition(rect) + } + + val widgets = widgetPanel.getWidgets().map { it.position.toRect() } + + for (x in 0.. Date: Mon, 12 May 2025 16:36:17 +0200 Subject: [PATCH 4/7] 0.2.1 --- app/build.gradle | 4 ++-- fastlane/metadata/android/en-US/changelogs/46.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/46.txt diff --git a/app/build.gradle b/app/build.gradle index 7e92f3b..42f0a2b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { minSdkVersion 21 targetSdkVersion 35 compileSdk 35 - versionCode 45 - versionName "0.2.0" + versionCode 46 + versionName "0.2.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/fastlane/metadata/android/en-US/changelogs/46.txt b/fastlane/metadata/android/en-US/changelogs/46.txt new file mode 100644 index 0000000..7d7f599 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/46.txt @@ -0,0 +1,2 @@ +* Fixed several bugs related to widgets +* Copy device info when clicking the version number (thank you, wassupluke!) From 87f3d49305aa0b18c8953edd923e47816b99e90e Mon Sep 17 00:00:00 2001 From: Luke Wass Date: Mon, 12 May 2025 08:49:08 -0500 Subject: [PATCH 5/7] bump Android Gradle Plugin from 8.9.2 to 8.10.0 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 2ef0f7e..e128ac7 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext.kotlin_version = '2.0.0' - ext.android_plugin_version = '8.9.2' + ext.android_plugin_version = '8.10.0' repositories { google() mavenCentral() @@ -10,7 +10,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.9.2' + classpath 'com.android.tools.build:gradle:8.10.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "com.android.tools.build:gradle:$android_plugin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" From 642b6bcbf4786672b6f3a4d6a165dc70e0fba82e Mon Sep 17 00:00:00 2001 From: Luke Wass Date: Mon, 12 May 2025 12:32:14 -0500 Subject: [PATCH 6/7] migrate build files to kotlin --- app/build.gradle | 116 ---------------------------- app/build.gradle.kts | 158 ++++++++++++++++++++++++++++++++++++++ app/proguard-rules.pro | 2 +- build.gradle | 35 --------- build.gradle.kts | 13 ++++ gradle.properties | 2 +- gradle/libs.versions.toml | 71 +++++++++++++++++ settings.gradle | 2 - settings.gradle.kts | 24 ++++++ 9 files changed, 268 insertions(+), 155 deletions(-) delete mode 100644 app/build.gradle create mode 100644 app/build.gradle.kts delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 gradle/libs.versions.toml delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 42f0a2b..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,116 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' -apply plugin: 'kotlinx-serialization' - -android { - dataBinding { - enabled = true - } - - packaging { - resources.excludes.addAll( - [ - "META-INF/LICENSE.md", - "META-INF/NOTICE.md", - "META-INF/LICENSE-notice.md" - ] - ) - } - - defaultConfig { - applicationId "de.jrpie.android.launcher" - minSdkVersion 21 - targetSdkVersion 35 - compileSdk 35 - versionCode 46 - versionName "0.2.1" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = '17' - } - - buildFeatures { - viewBinding true - } - - - buildTypes { - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - debug { - applicationIdSuffix = ".debug" - versionNameSuffix = "-debug" - } - } - - flavorDimensions += "distribution" - - productFlavors { - create("default") { - dimension = "distribution" - getIsDefault().set(true) - buildConfigField "boolean", "USE_ACCESSIBILITY_SERVICE", "true" - } - create("accrescent") { - dimension = "distribution" - applicationIdSuffix = ".accrescent" - versionNameSuffix = "+accrescent" - buildConfigField "boolean", "USE_ACCESSIBILITY_SERVICE", "false" - } - } - - sourceSets { - accrescent { - manifest.srcFile 'src/accrescent/AndroidManifest.xml' - } - } - - namespace 'de.jrpie.android.launcher' - buildFeatures { - buildConfig true - } - - dependenciesInfo { - // Disables dependency metadata when building APKs. - includeInApk = false - // Disables dependency metadata when building Android App Bundles. - includeInBundle = false - } - lint { - abortOnError false - } - - -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.activity:activity-ktx:1.8.0' - implementation 'androidx.appcompat:appcompat:1.7.0' - implementation 'androidx.core:core-ktx:1.15.0' - implementation 'androidx.constraintlayout:constraintlayout:2.2.0' - implementation 'androidx.gridlayout:gridlayout:1.0.0' - implementation 'androidx.palette:palette-ktx:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.4.0' - implementation 'androidx.preference:preference-ktx:1.2.1' - implementation 'com.google.android.material:material:1.12.0' - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") - implementation "eu.jonahbauer:android-preference-annotations:1.1.2" - implementation 'androidx.activity:activity:1.10.1' - annotationProcessor "eu.jonahbauer:android-preference-annotations:1.1.2" - annotationProcessor "com.android.databinding:compiler:$android_plugin_version" - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.2.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' -} - diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..7190581 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,158 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.kapt) + alias(libs.plugins.kotlin.serialization) +} + +android { + namespace = "de.jrpie.android.launcher" + compileSdk = 35 + + defaultConfig { + applicationId = "de.jrpie.android.launcher" + minSdk = 21 + targetSdk = 35 + versionCode = 46 + versionName = "0.2.1" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + debug { + applicationIdSuffix = ".debug" + versionNameSuffix = "-debug" + } + } + + flavorDimensions += "distribution" + + productFlavors { + create("default") { + dimension = "distribution" + isDefault = true + buildConfigField("boolean", "USE_ACCESSIBILITY_SERVICE", "true") + } + create("accrescent") { + dimension = "distribution" + applicationIdSuffix = ".accrescent" + versionNameSuffix = "+accrescent" + buildConfigField("boolean", "USE_ACCESSIBILITY_SERVICE", "false") + } + } + + sourceSets { + this.getByName("accrescent") { + this.java.srcDir("src/accrescent") + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + buildConfig = true + compose = true + dataBinding = true + viewBinding = true + } + + dependenciesInfo { + includeInApk = false + includeInBundle = false + } + + lint { + abortOnError = false + } +} + +dependencies { + // implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) + + // implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation(libs.kotlin.stdlib.jdk7) + + // implementation 'androidx.activity:activity-ktx:1.8.0' + implementation(libs.androidx.activity.ktx) + + // implementation 'androidx.appcompat:appcompat:1.7.0' + implementation(libs.androidx.appcompat) + + // implementation 'androidx.core:core-ktx:1.15.0' + implementation(libs.androidx.core.ktx) + + // implementation 'androidx.constraintlayout:constraintlayout:2.2.0' + implementation(libs.androidx.constraintlayout) + + // implementation 'androidx.gridlayout:gridlayout:1.0.0' + implementation(libs.androidx.gridlayout) + + // implementation 'androidx.palette:palette-ktx:1.0.0' + implementation(libs.androidx.palette.ktx) + + // implementation 'androidx.recyclerview:recyclerview:1.4.0' + implementation(libs.androidx.recyclerview) + + // implementation 'androidx.preference:preference-ktx:1.2.1' + implementation(libs.androidx.preference.ktx) + + // implementation 'com.google.android.material:material:1.12.0' + implementation(libs.google.material) + + // implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") + implementation(libs.kotlinx.serialization.json) + + // implementation "eu.jonahbauer:android-preference-annotations:1.1.2" + implementation(libs.jonahbauer.android.preference.annotations) + + // implementation 'androidx.activity:activity:1.10.1' + implementation(libs.androidx.activity) + + // annotationProcessor "eu.jonahbauer:android-preference-annotations:1.1.2" + // If you are using KSP, use ksp(...) instead of kapt(...) or annotationProcessor(...) + // Otherwise, if you still need kapt: + // kapt(libs.jonahbauer.android.preference.annotations) + // Or if you need annotationProcessor for Java libraries: + kapt(libs.jonahbauer.android.preference.annotations) + + // testImplementation 'junit:junit:4.13.2' + testImplementation(libs.junit) + + // androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation(libs.androidx.test.ext.junit) + + // androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + androidTestImplementation(libs.androidx.espresso.core) + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.appcompat) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 9e3e326..c1fba79 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -2,7 +2,7 @@ -dontobfuscate -dontoptimize # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/build.gradle b/build.gradle deleted file mode 100644 index e128ac7..0000000 --- a/build.gradle +++ /dev/null @@ -1,35 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - ext.kotlin_version = '2.0.0' - ext.android_plugin_version = '8.10.0' - repositories { - google() - mavenCentral() - - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.10.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "com.android.tools.build:gradle:$android_plugin_version" - classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - mavenCentral() - - } -} - -tasks.register('clean', Delete) { - delete layout.buildDirectory -} - diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..842176e --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,13 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.kotlin.kapt) apply false + alias(libs.plugins.kotlin.serialization) apply false +} + +tasks.register("clean", Delete::class) { + delete(layout.buildDirectory) +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 4093087..80aef5f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,7 @@ org.gradle.jvmargs=-Xmx1536m # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true +android.enableJetifier=false # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official android.nonTransitiveRClass=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..2f41128 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,71 @@ +[versions] +agp = "8.10.0" +kotlin = "2.1.0" +kapt = "1.8.10" +serialization = "1.8.10" +junit = "4.13.2" +junitVersion = "1.2.1" +espresso-core = "3.6.1" +lifecycleRuntimeKtx = "2.9.0" +activityCompose = "1.10.1" +composeBom = "2025.05.00" +appcompat = "1.7.0" +constraintlayout = "2.2.0" +gridlayout = "1.0.0" +recyclerview = "1.4.0" +material = "1.12.0" +android-preference-annotations = "1.1.2" +activity = "1.10.1" +kotlinx-serialization-json = "1.7.3" +activity-ktx = "1.8.0" +core-ktx = "1.15.0" +palette-ktx = "1.0.0" +preference-ktx = "1.2.1" + +[libraries] +# AndroidX dependencies +androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activity-ktx" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } +androidx-gridlayout = { group = "androidx.gridlayout", name = "gridlayout", version.ref = "gridlayout" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-palette-ktx = { group = "androidx.palette", name = "palette-ktx", version.ref = "palette-ktx" } +androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "preference-ktx" } +androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" } +androidx-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } + +# Google Material +google-material = { group = "com.google.android.material", name = "material", version.ref = "material" } + +# Kotlin and Serialization +kotlin-stdlib-jdk7 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk7", version.ref = "kotlin" } # Use kotlin version +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" } + +# Annotation Processors +jonahbauer-android-preference-annotations = { group = "eu.jonahbauer", name = "android-preference-annotations", version.ref = "android-preference-annotations" } +# The databinding library is bundled with the Android Gradle plugin. You do not need to declare a dependency on the library, but you must enable it in your module's build.gradle file. +# see https://developer.android.com/jetpack/androidx/releases/databinding +# android-databinding-compiler = { group = "com.android.databinding", name = "compiler", version.ref = "agp" } # Use agp version + +# Testing dependencies +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kapt" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "serialization" } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index b9709f4..0000000 --- a/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name='Launcher' -include ':app' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..5054e60 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "Launcher" +include(":app") \ No newline at end of file From 0e320c243226a17551cc485f9e321deb7c8bbc6a Mon Sep 17 00:00:00 2001 From: Luke Wass Date: Mon, 12 May 2025 12:48:30 -0500 Subject: [PATCH 7/7] Extract repetitive string as constant --- app/build.gradle.kts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7190581..c147714 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -34,16 +34,18 @@ android { } } - flavorDimensions += "distribution" + val distributionDimension = "distribution" + + flavorDimensions += distributionDimension productFlavors { create("default") { - dimension = "distribution" + dimension = distributionDimension isDefault = true buildConfigField("boolean", "USE_ACCESSIBILITY_SERVICE", "true") } create("accrescent") { - dimension = "distribution" + dimension = distributionDimension applicationIdSuffix = ".accrescent" versionNameSuffix = "+accrescent" buildConfigField("boolean", "USE_ACCESSIBILITY_SERVICE", "false")