mirror of
https://github.com/jrpie/Launcher.git
synced 2025-05-17 07:51:06 +02:00
Merge branch 'master' into migrate-build-files-to-kotlin
This commit is contained in:
commit
9e2c1531b2
19 changed files with 210 additions and 47 deletions
|
@ -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<AbstractAppInfo> = 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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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<View>): 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) { }
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -32,6 +32,12 @@ class WidgetPanel(val id: Int, var label: String) {
|
|||
.filter { it.panelId == this.id }.forEach { it.delete(context) }
|
||||
}
|
||||
|
||||
fun getWidgets(): List<Widget> {
|
||||
return LauncherPreferences.widgets().widgets().filter {
|
||||
it.panelId == this.id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
val HOME = WidgetPanel(0, "home")
|
||||
|
|
|
@ -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..<GRID_SIZE - minWidth) {
|
||||
rect.left = x
|
||||
rect.right = x + minWidth
|
||||
for (y in 0..<GRID_SIZE - minHeight) {
|
||||
rect.top = y
|
||||
rect.bottom = y + minHeight
|
||||
if (!widgets.any { Rect(it).intersect(rect) }) {
|
||||
return WidgetPosition(rect)
|
||||
}
|
||||
}
|
||||
}
|
||||
return WidgetPosition(0, 0, minWidth.toShort(), minHeight.toShort())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ fun bindAppWidgetOrRequestPermission(activity: Activity, providerInfo: AppWidget
|
|||
|
||||
|
||||
fun getAppWidgetProviders( context: Context ): List<LauncherWidgetProvider> {
|
||||
val list = mutableListOf<LauncherWidgetProvider>(LauncherClockWidgetProvider())
|
||||
val list = mutableListOf<LauncherWidgetProvider>(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<LauncherWidgetProvider> {
|
|||
}.flatten()
|
||||
)
|
||||
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
|
||||
fun updateWidget(widget: Widget) {
|
||||
LauncherPreferences.widgets().widgets(
|
||||
(LauncherPreferences.widgets().widgets() ?: setOf())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/list_widget_panels_row_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -14,10 +15,23 @@
|
|||
android:layout_marginEnd="5dp"
|
||||
android:gravity="start"
|
||||
android:text=""
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:text="Panel #1"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<TextView
|
||||
android:id="@+id/list_widget_panels_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="60sp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:gravity="start"
|
||||
android:text=""
|
||||
tools:text="Contains 5 widgets"
|
||||
android:textSize="11sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/list_widget_panels_label" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
16
app/src/main/res/layout/widget_debug_info.xml
Normal file
16
app/src/main/res/layout/widget_debug_info.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:longClickable="false"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ui.widgets.DebugInfoView">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/debugInfoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -406,8 +406,8 @@
|
|||
|
||||
<string name="widget_panel_default_name">Widget Panel #%1$d</string>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="one">Contains %d widget.</item>
|
||||
<item quantity="other">Contains %d widgets.</item>
|
||||
<item quantity="one">Contains %1$d widget.</item>
|
||||
<item quantity="other">Contains %1$d widgets.</item>
|
||||
</plurals>
|
||||
|
||||
|
||||
|
|
2
fastlane/metadata/android/en-US/changelogs/46.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/46.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
* Fixed several bugs related to widgets
|
||||
* Copy device info when clicking the version number (thank you, wassupluke!)
|
Loading…
Add table
Add a link
Reference in a new issue