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/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/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/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/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/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/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.. { - 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/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/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 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. 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!)