diff --git a/.scripts/release.sh b/.scripts/release.sh index dc6959d..f207c87 100755 --- a/.scripts/release.sh +++ b/.scripts/release.sh @@ -1,25 +1,9 @@ #!/bin/bash - -# This script builds all variants of µLauncher to create a release, namely: -# - app-release.apk (GitHub release; used by F-Droid for reproducible builds) -# - launcher-accrescent.apks (Accrescent) -# - app-release.aab (Play Store) - -# This is only intended to work on my (@jrpie) computer. -# To use this script for building a fork you need to: -# - install bundletool.jar and -# - create a keystore and modify the variables below accordingly - export JAVA_HOME="/usr/lib/jvm/java-21-openjdk/" OUTPUT_DIR="$HOME/launcher-release" BUILD_TOOLS_DIR="$HOME/Android/Sdk/build-tools/35.0.0" - -# keystore for the default release KEYSTORE="$HOME/data/keys/launcher_jrpie.jks" -# keystore for the default accrescent release KEYSTORE_ACCRESCENT="$HOME/data/keys/launcher_jrpie_accrescent.jks" - -# keepassxc-password is a custom script to fetch passwords from my password manager KEYSTORE_PASS=$(keepassxc-password "android_keys/launcher") KEYSTORE_ACCRESCENT_PASS=$(keepassxc-password "android_keys/launcher-accrescent") @@ -27,11 +11,12 @@ if [[ $(git status --porcelain) ]]; then echo "There are uncommitted changes." read -p "Continue anyway? (y/n) " -n 1 -r - echo + echo # (optional) move to a new line if ! [[ $REPLY =~ ^[Yy]$ ]] then exit 1 fi + fi rm -rf "$OUTPUT_DIR" diff --git a/app/build.gradle b/app/build.gradle index 7e92f3b..1a0a6fb 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 44 + versionName "0.1.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -106,7 +106,6 @@ dependencies { 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' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e60a85b..a5f8831 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,19 +19,6 @@ android:supportsRtl="true" android:theme="@style/launcherBaseTheme" tools:ignore="UnusedAttribute"> - - - - - \ No newline at end of file + diff --git a/app/src/main/java/de/jrpie/android/launcher/Application.kt b/app/src/main/java/de/jrpie/android/launcher/Application.kt index 3c2e3bc..e6cce23 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Application.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Application.kt @@ -12,8 +12,6 @@ import android.os.Build.VERSION_CODES import android.os.UserHandle import androidx.core.content.ContextCompat import androidx.lifecycle.MutableLiveData -import android.appwidget.AppWidgetHost -import android.appwidget.AppWidgetManager import androidx.preference.PreferenceManager import de.jrpie.android.launcher.actions.TorchManager import de.jrpie.android.launcher.apps.AbstractAppInfo @@ -26,15 +24,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch - -const val APP_WIDGET_HOST_ID = 42; - - class Application : android.app.Application() { val apps = MutableLiveData>() val privateSpaceLocked = MutableLiveData() - lateinit var appWidgetHost: AppWidgetHost - lateinit var appWidgetManager: AppWidgetManager private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { @@ -111,15 +103,10 @@ class Application : android.app.Application() { torchManager = TorchManager(this) } - appWidgetHost = AppWidgetHost(this.applicationContext, APP_WIDGET_HOST_ID) - appWidgetManager = AppWidgetManager.getInstance(this.applicationContext) - - appWidgetHost.startListening() - - val preferences = PreferenceManager.getDefaultSharedPreferences(this) LauncherPreferences.init(preferences, this.resources) + // Try to restore old preferences migratePreferencesToNewVersion(this) @@ -170,10 +157,4 @@ class Application : android.app.Application() { apps.postValue(getApps(packageManager, applicationContext)) } } - - override fun onTerminate() { - appWidgetHost.stopListening() - super.onTerminate() - - } } diff --git a/app/src/main/java/de/jrpie/android/launcher/Functions.kt b/app/src/main/java/de/jrpie/android/launcher/Functions.kt index 9679ae5..afc2c31 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Functions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Functions.kt @@ -6,9 +6,6 @@ import android.app.role.RoleManager import android.content.ActivityNotFoundException import android.content.ClipData import android.content.ClipboardManager -import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProvider -import android.appwidget.AppWidgetProviderInfo import android.content.Context import android.content.Intent import android.content.pm.LauncherApps @@ -226,4 +223,4 @@ fun copyToClipboard(context: Context, text: String) { val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipData = ClipData.newPlainText("Debug Info", text) clipboardManager.setPrimaryClip(clipData) -} +} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/actions/Action.kt b/app/src/main/java/de/jrpie/android/launcher/actions/Action.kt index a883922..9a2dc62 100644 --- a/app/src/main/java/de/jrpie/android/launcher/actions/Action.kt +++ b/app/src/main/java/de/jrpie/android/launcher/actions/Action.kt @@ -6,18 +6,14 @@ import android.content.SharedPreferences.Editor import android.graphics.Rect import android.graphics.drawable.Drawable import android.widget.Toast -import androidx.core.content.edit import de.jrpie.android.launcher.R import de.jrpie.android.launcher.preferences.LauncherPreferences import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import androidx.core.content.edit -/** - * Represents an action that can be bound to a [Gesture]. - * There are four types of actions: [AppAction], [ShortcutAction], [LauncherAction] and [WidgetPanelAction] - */ @Serializable sealed interface Action { fun invoke(context: Context, rect: Rect? = null): Boolean @@ -25,10 +21,6 @@ sealed interface Action { fun getIcon(context: Context): Drawable? fun isAvailable(context: Context): Boolean - fun showConfigurationDialog(context: Context, onSuccess: (Action) -> Unit) { - onSuccess(this) - } - // Can the action be used to reach µLauncher settings? fun canReachSettings(): Boolean diff --git a/app/src/main/java/de/jrpie/android/launcher/actions/WidgetPanelAction.kt b/app/src/main/java/de/jrpie/android/launcher/actions/WidgetPanelAction.kt deleted file mode 100644 index d7829a6..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/actions/WidgetPanelAction.kt +++ /dev/null @@ -1,83 +0,0 @@ -package de.jrpie.android.launcher.actions - -import android.content.Context -import android.content.Intent -import android.graphics.Rect -import android.graphics.drawable.Drawable -import android.view.View -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AlertDialog -import androidx.core.content.res.ResourcesCompat -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import de.jrpie.android.launcher.R -import de.jrpie.android.launcher.ui.widgets.WidgetPanelActivity -import de.jrpie.android.launcher.ui.widgets.manage.EXTRA_PANEL_ID -import de.jrpie.android.launcher.ui.widgets.manage.WidgetPanelsRecyclerAdapter -import de.jrpie.android.launcher.widgets.WidgetPanel -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -@SerialName("action:panel") -class WidgetPanelAction(val widgetPanelId: Int) : Action { - - override fun invoke(context: Context, rect: Rect?): Boolean { - - if (WidgetPanel.byId(widgetPanelId) == null) { - Toast.makeText(context, R.string.alert_widget_panel_not_found, Toast.LENGTH_LONG).show() - } else { - context.startActivity(Intent(context, WidgetPanelActivity::class.java).also { - it.putExtra(EXTRA_PANEL_ID, widgetPanelId) - }) - } - return true - } - - override fun label(context: Context): String { - return WidgetPanel.byId(widgetPanelId)?.label - ?: context.getString(R.string.list_other_open_widget_panel) - } - - override fun isAvailable(context: Context): Boolean { - return true - } - - override fun canReachSettings(): Boolean { - return false - } - - override fun getIcon(context: Context): Drawable? { - return ResourcesCompat.getDrawable( - context.resources, - R.drawable.baseline_widgets_24, - context.theme - ) - } - - override fun showConfigurationDialog(context: Context, onSuccess: (Action) -> Unit) { - AlertDialog.Builder(context, R.style.AlertDialogCustom).apply { - setTitle(R.string.dialog_select_widget_panel_title) - setNegativeButton(R.string.dialog_cancel) { _, _ -> } - setView(R.layout.dialog_select_widget_panel) - }.create().also { it.show() }.also { alertDialog -> - val infoTextView = - alertDialog.findViewById(R.id.dialog_select_widget_panel_info) - alertDialog.findViewById(R.id.dialog_select_widget_panel_recycler) - ?.apply { - setHasFixedSize(true) - layoutManager = LinearLayoutManager(alertDialog.context) - adapter = - WidgetPanelsRecyclerAdapter(alertDialog.context, false) { widgetPanel -> - onSuccess(WidgetPanelAction(widgetPanel.id)) - alertDialog.dismiss() - } - if (adapter?.itemCount == 0) { - infoTextView?.visibility = View.VISIBLE - } - } - } - true - } -} diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java b/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java index d509ef2..85979fe 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/LauncherPreferences$Config.java @@ -8,8 +8,6 @@ import de.jrpie.android.launcher.actions.lock.LockMethod; import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer; import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer; import de.jrpie.android.launcher.preferences.serialization.SetPinnedShortcutInfoPreferenceSerializer; -import de.jrpie.android.launcher.preferences.serialization.SetWidgetPanelSerializer; -import de.jrpie.android.launcher.preferences.serialization.SetWidgetSerializer; import de.jrpie.android.launcher.preferences.theme.Background; import de.jrpie.android.launcher.preferences.theme.ColorTheme; import de.jrpie.android.launcher.preferences.theme.Font; @@ -74,7 +72,6 @@ import eu.jonahbauer.android.preference.annotations.Preferences; @Preference(name = "search_auto_launch", type = boolean.class, defaultValue = "true"), @Preference(name = "search_web", type = boolean.class, description = "false"), @Preference(name = "search_auto_open_keyboard", type = boolean.class, defaultValue = "true"), - @Preference(name = "search_auto_close_keyboard", type = boolean.class, defaultValue = "false"), }), @PreferenceGroup(name = "enabled_gestures", prefix = "settings_enabled_gestures_", suffix = "_key", value = { @Preference(name = "double_swipe", type = boolean.class, defaultValue = "true"), @@ -84,9 +81,5 @@ import eu.jonahbauer.android.preference.annotations.Preferences; @PreferenceGroup(name = "actions", prefix = "settings_actions_", suffix = "_key", value = { @Preference(name = "lock_method", type = LockMethod.class, defaultValue = "DEVICE_ADMIN"), }), - @PreferenceGroup(name = "widgets", prefix = "settings_widgets_", suffix= "_key", value = { - @Preference(name = "widgets", type = Set.class, serializer = SetWidgetSerializer.class), - @Preference(name = "custom_panels", type = Set.class, serializer = SetWidgetPanelSerializer.class) - }), }) public final class LauncherPreferences$Config {} \ No newline at end of file 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..59ecc7a 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 @@ -2,29 +2,23 @@ package de.jrpie.android.launcher.preferences import android.content.Context import android.util.Log -import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.BuildConfig import de.jrpie.android.launcher.actions.Action +import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.AbstractAppInfo import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER -import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.DetailedAppInfo import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion1 import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion2 import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion3 -import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion4 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.WidgetPanel -import de.jrpie.android.launcher.widgets.WidgetPosition -import de.jrpie.android.launcher.widgets.deleteAllWidgets /* Current version of the structure of preferences. * Increase when breaking changes are introduced and write an appropriate case in * `migratePreferencesToNewVersion` */ -const val PREFERENCE_VERSION = 100 +const val PREFERENCE_VERSION = 4 const val UNKNOWN_PREFERENCE_VERSION = -1 private const val TAG = "Launcher - Preferences" @@ -46,24 +40,18 @@ fun migratePreferencesToNewVersion(context: Context) { } 1 -> { - migratePreferencesFromVersion1(context) + migratePreferencesFromVersion1() Log.i(TAG, "migration of preferences complete (1 -> ${PREFERENCE_VERSION}).") } 2 -> { - migratePreferencesFromVersion2(context) + migratePreferencesFromVersion2() Log.i(TAG, "migration of preferences complete (2 -> ${PREFERENCE_VERSION}).") } 3 -> { - migratePreferencesFromVersion3(context) + migratePreferencesFromVersion3() Log.i(TAG, "migration of preferences complete (3 -> ${PREFERENCE_VERSION}).") } - // There was a bug where instead of the preference version the app version was written. - in 4..99 -> { - migratePreferencesFromVersion4(context) - Log.i(TAG, "migration of preferences complete (4 -> ${PREFERENCE_VERSION}).") - } - else -> { Log.w( TAG, @@ -83,17 +71,6 @@ fun resetPreferences(context: Context) { Log.i(TAG, "Resetting preferences") LauncherPreferences.clear() LauncherPreferences.internal().versionCode(PREFERENCE_VERSION) - deleteAllWidgets(context) - - LauncherPreferences.widgets().widgets( - setOf( - ClockWidget( - (context.applicationContext as Application).appWidgetHost.allocateAppWidgetId(), - WidgetPosition(1, 3, 10, 4), - WidgetPanel.HOME.id - ) - ) - ) val hidden: MutableSet = mutableSetOf() diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version1.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version1.kt index 6cd9819..a1cb022 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version1.kt +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version1.kt @@ -1,13 +1,11 @@ package de.jrpie.android.launcher.preferences.legacy -import android.content.Context -import androidx.core.content.edit import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.AppAction import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.LauncherAction -import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER import de.jrpie.android.launcher.apps.AppInfo +import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION import kotlinx.serialization.Serializable @@ -15,6 +13,7 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.json.JSONException import org.json.JSONObject +import androidx.core.content.edit @Serializable @@ -130,7 +129,7 @@ private fun migrateAction(key: String) { * Migrate preferences from version 1 (used until version j-0.0.18) to the current format * (see [PREFERENCE_VERSION]) */ -fun migratePreferencesFromVersion1(context: Context) { +fun migratePreferencesFromVersion1() { assert(LauncherPreferences.internal().versionCode() == 1) Gesture.entries.forEach { g -> migrateAction(g.id) } migrateAppInfoSet(LauncherPreferences.apps().keys().hidden()) @@ -138,5 +137,5 @@ fun migratePreferencesFromVersion1(context: Context) { migrateAppInfoStringMap(LauncherPreferences.apps().keys().customNames()) LauncherPreferences.internal().versionCode(2) - migratePreferencesFromVersion2(context) + migratePreferencesFromVersion2() } \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version2.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version2.kt index 9714359..4e6eae1 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version2.kt +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version2.kt @@ -1,6 +1,5 @@ package de.jrpie.android.launcher.preferences.legacy -import android.content.Context import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.LauncherAction @@ -12,10 +11,10 @@ import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION * Migrate preferences from version 2 (used until version 0.0.21) to the current format * (see [PREFERENCE_VERSION]) */ -fun migratePreferencesFromVersion2(context: Context) { +fun migratePreferencesFromVersion2() { assert(LauncherPreferences.internal().versionCode() == 2) // previously there was no setting for this Action.setActionForGesture(Gesture.BACK, LauncherAction.CHOOSE) LauncherPreferences.internal().versionCode(3) - migratePreferencesFromVersion3(context) + migratePreferencesFromVersion3() } \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version3.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version3.kt index e0a8447..4a9241f 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version3.kt +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version3.kt @@ -1,17 +1,17 @@ package de.jrpie.android.launcher.preferences.legacy -import android.content.Context import android.content.SharedPreferences import android.content.SharedPreferences.Editor -import androidx.core.content.edit -import de.jrpie.android.launcher.apps.AbstractAppInfo import de.jrpie.android.launcher.apps.AppInfo +import de.jrpie.android.launcher.apps.AbstractAppInfo import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import java.util.HashSet +import androidx.core.content.edit /** * Migrate preferences from version 3 (used until version 0.0.23) to the current format @@ -70,7 +70,8 @@ private fun migrateMapAppInfoString(key: String, preferences: SharedPreferences, } } -fun migratePreferencesFromVersion3(context: Context) { +fun migratePreferencesFromVersion3() { + assert(PREFERENCE_VERSION == 4) assert(LauncherPreferences.internal().versionCode() == 3) val preferences = LauncherPreferences.getSharedPreferences() @@ -81,5 +82,4 @@ fun migratePreferencesFromVersion3(context: Context) { } LauncherPreferences.internal().versionCode(4) - migratePreferencesFromVersion4(context) } \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version4.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version4.kt deleted file mode 100644 index aaeeb18..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/Version4.kt +++ /dev/null @@ -1,27 +0,0 @@ -package de.jrpie.android.launcher.preferences.legacy - -import android.content.Context -import de.jrpie.android.launcher.Application -import de.jrpie.android.launcher.preferences.LauncherPreferences -import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION -import de.jrpie.android.launcher.widgets.ClockWidget -import de.jrpie.android.launcher.widgets.WidgetPanel -import de.jrpie.android.launcher.widgets.WidgetPosition - -fun migratePreferencesFromVersion4(context: Context) { - assert(PREFERENCE_VERSION == 100) - assert(LauncherPreferences.internal().versionCode() < 100) - - LauncherPreferences.widgets().widgets( - setOf( - ClockWidget( - (context.applicationContext as Application).appWidgetHost.allocateAppWidgetId(), - WidgetPosition(1, 3, 10, 4), - WidgetPanel.HOME.id - ) - ) - ) - - - LauncherPreferences.internal().versionCode(100) -} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/VersionUnknown.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/VersionUnknown.kt index f954b31..2d1152d 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/VersionUnknown.kt +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/legacy/VersionUnknown.kt @@ -3,10 +3,10 @@ package de.jrpie.android.launcher.preferences.legacy import android.content.Context import android.content.SharedPreferences import android.util.Log -import androidx.core.content.edit import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.theme.Background import de.jrpie.android.launcher.preferences.theme.ColorTheme +import androidx.core.content.edit private fun migrateStringPreference( @@ -392,5 +392,5 @@ fun migratePreferencesFromVersionUnknown(context: Context) { LauncherPreferences.internal().versionCode(1) Log.i(TAG, "migrated preferences to version 1.") - migratePreferencesFromVersion1(context) + migratePreferencesFromVersion1() } \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/serialization/PreferenceSerializers.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/serialization/PreferenceSerializers.kt index 7b5d794..3e19daf 100644 --- a/app/src/main/java/de/jrpie/android/launcher/preferences/serialization/PreferenceSerializers.kt +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/serialization/PreferenceSerializers.kt @@ -4,8 +4,6 @@ package de.jrpie.android.launcher.preferences.serialization import de.jrpie.android.launcher.apps.AbstractAppInfo import de.jrpie.android.launcher.apps.PinnedShortcutInfo -import de.jrpie.android.launcher.widgets.Widget -import de.jrpie.android.launcher.widgets.WidgetPanel import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializationException import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializer import kotlinx.serialization.Serializable @@ -30,40 +28,6 @@ class SetAbstractAppInfoPreferenceSerializer : } } - -@Suppress("UNCHECKED_CAST") -class SetWidgetSerializer : - PreferenceSerializer?, java.util.Set?> { - @Throws(PreferenceSerializationException::class) - override fun serialize(value: java.util.Set?): java.util.Set? { - return value?.map(Widget::serialize) - ?.toHashSet() as? java.util.Set - } - - @Throws(PreferenceSerializationException::class) - override fun deserialize(value: java.util.Set?): java.util.Set? { - return value?.map(java.lang.String::toString)?.map(Widget::deserialize) - ?.toHashSet() as? java.util.Set - } -} - -@Suppress("UNCHECKED_CAST") -class SetWidgetPanelSerializer : - PreferenceSerializer?, java.util.Set?> { - @Throws(PreferenceSerializationException::class) - override fun serialize(value: java.util.Set?): java.util.Set? { - return value?.map(WidgetPanel::serialize) - ?.toHashSet() as? java.util.Set - } - - @Throws(PreferenceSerializationException::class) - override fun deserialize(value: java.util.Set?): java.util.Set? { - return value?.map(java.lang.String::toString)?.map(WidgetPanel::deserialize) - ?.toHashSet() as? java.util.Set - } -} - - @Suppress("UNCHECKED_CAST") class SetPinnedShortcutInfoPreferenceSerializer : PreferenceSerializer?, java.util.Set?> { diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/Helper.kt b/app/src/main/java/de/jrpie/android/launcher/ui/Helper.kt index a863c67..1ca4d2b 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/Helper.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/Helper.kt @@ -1,6 +1,5 @@ package de.jrpie.android.launcher.ui -import android.app.Activity import android.content.Context import android.graphics.ColorMatrix import android.graphics.ColorMatrixColorFilter @@ -39,17 +38,10 @@ fun ImageView.transformGrayscale(grayscale: Boolean) { } -// Taken from https://stackoverflow.com/a/50743764 +// Taken from https://stackoverflow.com/a/50743764/12787264 fun View.openSoftKeyboard(context: Context) { this.requestFocus() - (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager) - .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) + // open the soft keyboard + val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) } - -// https://stackoverflow.com/a/17789187 -fun closeSoftKeyboard(activity: Activity) { - activity.currentFocus?.let { focus -> - (activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager) - .hideSoftInputFromWindow( focus.windowToken, 0 ) - } -} \ No newline at end of file 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 192a8e9..53a0876 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 @@ -1,7 +1,6 @@ package de.jrpie.android.launcher.ui import android.annotation.SuppressLint -import android.app.Activity import android.content.SharedPreferences import android.content.res.Configuration import android.content.res.Resources @@ -11,7 +10,8 @@ import android.view.KeyEvent import android.view.MotionEvent import android.view.View import android.window.OnBackInvokedDispatcher -import de.jrpie.android.launcher.Application +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible import de.jrpie.android.launcher.R import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Gesture @@ -20,6 +20,7 @@ import de.jrpie.android.launcher.databinding.HomeBinding import de.jrpie.android.launcher.openTutorial import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.tutorial.TutorialActivity +import java.util.Locale /** * [HomeActivity] is the actual application Launcher, @@ -33,10 +34,10 @@ import de.jrpie.android.launcher.ui.tutorial.TutorialActivity * - Setting global variables (preferences etc.) * - Opening the [TutorialActivity] on new installations */ -class HomeActivity : UIObject, Activity() { +class HomeActivity : UIObject, AppCompatActivity() { private lateinit var binding: HomeBinding - private var touchGestureDetector: TouchGestureDetector? = null + private lateinit var touchGestureDetector: TouchGestureDetector private var sharedPreferencesListener = SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> @@ -44,26 +45,40 @@ class HomeActivity : UIObject, Activity() { prefKey?.startsWith("display.") == true ) { recreate() - } else if (prefKey?.startsWith("action.") == true) { - updateSettingsFallbackButtonVisibility() - } else if (prefKey == LauncherPreferences.widgets().keys().widgets()) { - binding.homeWidgetContainer.updateWidgets(this@HomeActivity, - LauncherPreferences.widgets().widgets() - ) } + if (prefKey?.startsWith("action.") == true) { + updateSettingsFallbackButtonVisibility() + } } override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + super.onCreate(savedInstanceState) super.onCreate() + touchGestureDetector = TouchGestureDetector( + this, 0, 0, + LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f + ) + touchGestureDetector.updateScreenSize(windowManager) // Initialise layout binding = HomeBinding.inflate(layoutInflater) setContentView(binding.root) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + binding.root.setOnApplyWindowInsetsListener { _, windowInsets -> + @Suppress("deprecation") // required to support API 29 + val insets = windowInsets.systemGestureInsets + touchGestureDetector.setSystemGestureInsets(insets) + + windowInsets + } + } + + + // Handle back key / gesture on Android 13+, cf. onKeyDown() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { onBackInvokedDispatcher.registerOnBackInvokedCallback( @@ -79,11 +94,12 @@ class HomeActivity : UIObject, Activity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - touchGestureDetector?.updateScreenSize(windowManager) + touchGestureDetector.updateScreenSize(windowManager) } override fun onStart() { - super.onStart() + super.onStart() + super.onStart() // If the tutorial was not finished, start it @@ -94,15 +110,6 @@ class HomeActivity : UIObject, Activity() { LauncherPreferences.getSharedPreferences() .registerOnSharedPreferenceChangeListener(sharedPreferencesListener) - (application as Application).appWidgetHost.startListening() - - } - - - - override fun onStop() { - (application as Application).appWidgetHost.stopListening() - super.onStop() } override fun onWindowFocusChanged(hasFocus: Boolean) { @@ -128,6 +135,44 @@ class HomeActivity : UIObject, Activity() { } } + private fun initClock() { + val locale = Locale.getDefault() + val dateVisible = LauncherPreferences.clock().dateVisible() + val timeVisible = LauncherPreferences.clock().timeVisible() + + var dateFMT = "yyyy-MM-dd" + var timeFMT = "HH:mm" + if (LauncherPreferences.clock().showSeconds()) { + timeFMT += ":ss" + } + + if (LauncherPreferences.clock().localized()) { + dateFMT = android.text.format.DateFormat.getBestDateTimePattern(locale, dateFMT) + timeFMT = android.text.format.DateFormat.getBestDateTimePattern(locale, timeFMT) + } + + var upperFormat = dateFMT + var lowerFormat = timeFMT + var upperVisible = dateVisible + var lowerVisible = timeVisible + + if (LauncherPreferences.clock().flipDateTime()) { + upperFormat = lowerFormat.also { lowerFormat = upperFormat } + upperVisible = lowerVisible.also { lowerVisible = upperVisible } + } + + binding.homeUpperView.isVisible = upperVisible + binding.homeLowerView.isVisible = lowerVisible + + binding.homeUpperView.setTextColor(LauncherPreferences.clock().color()) + binding.homeLowerView.setTextColor(LauncherPreferences.clock().color()) + + binding.homeLowerView.format24Hour = lowerFormat + binding.homeUpperView.format24Hour = upperFormat + binding.homeLowerView.format12Hour = lowerFormat + binding.homeUpperView.format12Hour = upperFormat + } + override fun getTheme(): Resources.Theme { val mTheme = modifyTheme(super.getTheme()) mTheme.applyStyle(R.style.backgroundWallpaper, true) @@ -143,33 +188,11 @@ class HomeActivity : UIObject, Activity() { override fun onResume() { super.onResume() - /* This should be initialized in onCreate() - However on some devices there seems to be a bug where the touchGestureDetector - is not working properly after resuming the app. - Reinitializing the touchGestureDetector every time the app is resumed might help to fix that. - (see issue #138) - */ - touchGestureDetector = TouchGestureDetector( - this, 0, 0, + touchGestureDetector.edgeWidth = LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f - ).also { - it.updateScreenSize(windowManager) - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - binding.root.setOnApplyWindowInsetsListener { _, windowInsets -> - @Suppress("deprecation") // required to support API 29 - val insets = windowInsets.systemGestureInsets - touchGestureDetector?.setSystemGestureInsets(insets) - - windowInsets - } - } + initClock() updateSettingsFallbackButtonVisibility() - - binding.homeWidgetContainer.updateWidgets(this@HomeActivity, - LauncherPreferences.widgets().widgets() - ) } override fun onDestroy() { @@ -207,10 +230,30 @@ class HomeActivity : UIObject, Activity() { } override fun onTouchEvent(event: MotionEvent): Boolean { - touchGestureDetector?.onTouchEvent(event) + touchGestureDetector.onTouchEvent(event) return true } + override fun setOnClicks() { + + binding.homeUpperView.setOnClickListener { + if (LauncherPreferences.clock().flipDateTime()) { + Gesture.TIME(this) + } else { + Gesture.DATE(this) + } + } + + binding.homeLowerView.setOnClickListener { + if (LauncherPreferences.clock().flipDateTime()) { + Gesture.DATE(this) + } else { + Gesture.TIME(this) + } + } + } + + private fun handleBack() { Gesture.BACK(this) } diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/PinShortcutActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/PinShortcutActivity.kt index 3dbdda8..71908ba 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/PinShortcutActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/PinShortcutActivity.kt @@ -49,21 +49,7 @@ class PinShortcutActivity : AppCompatActivity(), UIObject { val request = launcherApps.getPinItemRequest(intent) this.request = request - if (request == null) { - finish() - return - } - - if (request.requestType == PinItemRequest.REQUEST_TYPE_APPWIDGET) { - - // TODO - request.getAppWidgetProviderInfo(this) - // startActivity() - finish() - return - } - - if (request.requestType != PinItemRequest.REQUEST_TYPE_SHORTCUT) { + if (request == null || request.requestType != PinItemRequest.REQUEST_TYPE_SHORTCUT) { finish() return } diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt b/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt index a8e59ba..1a55bbb 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/ListFragmentApps.kt @@ -11,16 +11,13 @@ import android.widget.Toast import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import de.jrpie.android.launcher.R import de.jrpie.android.launcher.apps.AppFilter import de.jrpie.android.launcher.databinding.ListAppsBinding import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.UIObject -import de.jrpie.android.launcher.ui.closeSoftKeyboard import de.jrpie.android.launcher.ui.list.ListActivity import de.jrpie.android.launcher.ui.openSoftKeyboard -import kotlin.math.absoluteValue /** @@ -93,20 +90,6 @@ class ListFragmentApps : Fragment(), UIObject { } } adapter = appsRecyclerAdapter - if (LauncherPreferences.functionality().searchAutoCloseKeyboard()) { - addOnScrollListener(object : RecyclerView.OnScrollListener() { - var totalDy: Int = 0 - var threshold = (resources.displayMetrics.density * 100).toInt() - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - totalDy += dy - - if (totalDy.absoluteValue > 100) { - totalDy = 0 - closeSoftKeyboard(requireActivity()) - } - } - }) - } } binding.listAppsSearchview.setOnQueryTextListener(object : diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/list/other/OtherRecyclerAdapter.kt b/app/src/main/java/de/jrpie/android/launcher/ui/list/other/OtherRecyclerAdapter.kt index 06be78a..f176469 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/list/other/OtherRecyclerAdapter.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/list/other/OtherRecyclerAdapter.kt @@ -11,7 +11,6 @@ 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.actions.WidgetPanelAction import de.jrpie.android.launcher.ui.list.ListActivity /** @@ -24,10 +23,8 @@ import de.jrpie.android.launcher.ui.list.ListActivity class OtherRecyclerAdapter(val activity: Activity) : RecyclerView.Adapter() { - private val othersList: Array = - LauncherAction.entries.filter { it.isAvailable(activity) } - .plus(WidgetPanelAction(-1)) - .toTypedArray() + private val othersList: Array = + LauncherAction.entries.filter { it.isAvailable(activity) }.toTypedArray() inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener { @@ -39,12 +36,10 @@ class OtherRecyclerAdapter(val activity: Activity) : val pos = bindingAdapterPosition val content = othersList[pos] + activity.finish() val gestureId = (activity as? ListActivity)?.forGesture ?: return val gesture = Gesture.byId(gestureId) ?: return - content.showConfigurationDialog(activity) { configuredAction -> - Action.setActionForGesture(gesture, configuredAction) - activity.finish() - } + Action.setActionForGesture(gesture, content) } init { @@ -53,11 +48,11 @@ class OtherRecyclerAdapter(val activity: Activity) : } override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { - val otherLabel = othersList[i].label(activity) - val icon = othersList[i].getIcon(activity) + val otherLabel = activity.getString(othersList[i].label) + val icon = othersList[i].icon viewHolder.textView.text = otherLabel - viewHolder.iconView.setImageDrawable(icon) + viewHolder.iconView.setImageResource(icon) } override fun getItemCount(): Int { diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/settings/launcher/SettingsFragmentLauncher.kt b/app/src/main/java/de/jrpie/android/launcher/ui/settings/launcher/SettingsFragmentLauncher.kt index bb9df74..a8efb43 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/settings/launcher/SettingsFragmentLauncher.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/settings/launcher/SettingsFragmentLauncher.kt @@ -11,8 +11,6 @@ import de.jrpie.android.launcher.actions.openAppsList import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.theme.ColorTheme import de.jrpie.android.launcher.setDefaultHomeScreen -import de.jrpie.android.launcher.ui.widgets.manage.ManageWidgetPanelsActivity -import de.jrpie.android.launcher.ui.widgets.manage.ManageWidgetsActivity /** @@ -83,22 +81,6 @@ class SettingsFragmentLauncher : PreferenceFragmentCompat() { true } - val manageWidgets = findPreference( - LauncherPreferences.widgets().keys().widgets() - ) - manageWidgets?.setOnPreferenceClickListener { - startActivity(Intent(requireActivity(), ManageWidgetsActivity::class.java)) - true - } - - val manageWidgetPanels = findPreference( - LauncherPreferences.widgets().keys().customPanels() - ) - manageWidgetPanels?.setOnPreferenceClickListener { - startActivity(Intent(requireActivity(), ManageWidgetPanelsActivity::class.java)) - true - } - val hiddenApps = findPreference( LauncherPreferences.apps().keys().hidden() ) diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/tutorial/tabs/TutorialFragment5Finish.kt b/app/src/main/java/de/jrpie/android/launcher/ui/tutorial/tabs/TutorialFragment5Finish.kt index 8feaa07..2fd093e 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/tutorial/tabs/TutorialFragment5Finish.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/tutorial/tabs/TutorialFragment5Finish.kt @@ -42,6 +42,7 @@ class TutorialFragment5Finish : Fragment(), UIObject { if (!LauncherPreferences.internal().started()) { LauncherPreferences.internal().started(true) LauncherPreferences.internal().startedTime(System.currentTimeMillis() / 1000L) + LauncherPreferences.internal().versionCode(VERSION_CODE) } context?.let { setDefaultHomeScreen(it, checkDefault = true) } activity?.finish() 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 deleted file mode 100644 index 33c4888..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/ClockView.kt +++ /dev/null @@ -1,80 +0,0 @@ -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 androidx.core.view.isVisible -import de.jrpie.android.launcher.actions.Gesture -import de.jrpie.android.launcher.databinding.ClockBinding -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) - init { - initClock() - setOnClicks() - } - - - private fun initClock() { - val locale = Locale.getDefault() - val dateVisible = LauncherPreferences.clock().dateVisible() - val timeVisible = LauncherPreferences.clock().timeVisible() - - var dateFMT = "yyyy-MM-dd" - var timeFMT = "HH:mm" - if (LauncherPreferences.clock().showSeconds()) { - timeFMT += ":ss" - } - - if (LauncherPreferences.clock().localized()) { - dateFMT = android.text.format.DateFormat.getBestDateTimePattern(locale, dateFMT) - timeFMT = android.text.format.DateFormat.getBestDateTimePattern(locale, timeFMT) - } - - var upperFormat = dateFMT - var lowerFormat = timeFMT - var upperVisible = dateVisible - var lowerVisible = timeVisible - - if (LauncherPreferences.clock().flipDateTime()) { - upperFormat = lowerFormat.also { lowerFormat = upperFormat } - upperVisible = lowerVisible.also { lowerVisible = upperVisible } - } - - binding.clockUpperView.isVisible = upperVisible - binding.clockLowerView.isVisible = lowerVisible - - binding.clockUpperView.setTextColor(LauncherPreferences.clock().color()) - binding.clockLowerView.setTextColor(LauncherPreferences.clock().color()) - - binding.clockLowerView.format24Hour = lowerFormat - binding.clockUpperView.format24Hour = upperFormat - binding.clockLowerView.format12Hour = lowerFormat - binding.clockUpperView.format12Hour = upperFormat - } - - fun setOnClicks() { - binding.clockUpperView.setOnClickListener { - if (LauncherPreferences.clock().flipDateTime()) { - Gesture.TIME(context) - } else { - Gesture.DATE(context) - } - } - - binding.clockLowerView.setOnClickListener { - if (LauncherPreferences.clock().flipDateTime()) { - Gesture.DATE(context) - } else { - Gesture.TIME(context) - } - } - } - - - -} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/WidgetContainerView.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/WidgetContainerView.kt deleted file mode 100644 index 5f8adf1..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/WidgetContainerView.kt +++ /dev/null @@ -1,144 +0,0 @@ -package de.jrpie.android.launcher.ui.widgets - -import android.app.Activity -import android.content.Context -import android.graphics.PointF -import android.graphics.RectF -import android.util.AttributeSet -import android.util.Log -import android.view.MotionEvent -import android.view.View -import android.view.View.MeasureSpec.makeMeasureSpec -import android.view.ViewGroup -import androidx.core.graphics.contains -import androidx.core.view.size -import de.jrpie.android.launcher.widgets.Widget -import de.jrpie.android.launcher.widgets.WidgetPanel -import de.jrpie.android.launcher.widgets.WidgetPosition -import kotlin.math.max - - -/** - * This only works in an Activity, not AppCompatActivity - */ -open class WidgetContainerView( - var widgetPanelId: Int, - context: Context, - attrs: AttributeSet? = null -) : ViewGroup(context, attrs) { - constructor(context: Context, attrs: AttributeSet) : this(WidgetPanel.HOME.id, context, attrs) - - var widgetViewById = HashMap() - - open fun updateWidgets(activity: Activity, widgets: Collection?) { - synchronized(widgetViewById) { - if (widgets == null) { - return - } - Log.i("WidgetContainer", "updating ${activity.localClassName}") - widgetViewById.forEach { removeView(it.value) } - widgetViewById.clear() - widgets.filter { it.panelId == widgetPanelId }.forEach { widget -> - widget.createView(activity)?.let { - addView(it, LayoutParams(widget.position)) - widgetViewById[widget.id] = it - } - } - } - } - - override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { - if (ev == null) { - return false - } - val position = PointF(ev.x, ev.y) - - return widgetViewById.filter { - RectF( - it.value.x, - it.value.y, - it.value.x + it.value.width, - it.value.y + it.value.height - ).contains(position) == true - }.any { - Widget.byId(context, it.key)?.allowInteraction == false - } - } - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - - var maxHeight = suggestedMinimumHeight - var maxWidth = suggestedMinimumWidth - - val mWidth = MeasureSpec.getSize(widthMeasureSpec) - val mHeight = MeasureSpec.getSize(heightMeasureSpec) - - (0...onCreate(savedInstanceState) - super.onCreate() - widgetPanelId = intent.getIntExtra(EXTRA_PANEL_ID, WidgetPanel.Companion.HOME.id) - val binding = ActivityWidgetPanelBinding.inflate(layoutInflater) - setContentView(binding.root) - binding.widgetPanelWidgetContainer.widgetPanelId = widgetPanelId - binding.widgetPanelWidgetContainer.updateWidgets( - this, - LauncherPreferences.widgets().widgets() - ) - } - - override fun getTheme(): Resources.Theme { - val mTheme = modifyTheme(super.getTheme()) - mTheme.applyStyle(R.style.backgroundWallpaper, true) - LauncherPreferences.clock().font().applyToTheme(mTheme) - LauncherPreferences.theme().colorTheme().applyToTheme( - mTheme, - LauncherPreferences.theme().textShadow() - ) - - return mTheme - } - - - override fun onStart() { - super.onStart() - super.onStart() - } - - override fun isHomeScreen(): Boolean { - return true - } -} \ 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 deleted file mode 100644 index cb57fda..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetPanelsActivity.kt +++ /dev/null @@ -1,103 +0,0 @@ -package de.jrpie.android.launcher.ui.widgets.manage - -import android.annotation.SuppressLint -import android.content.Intent -import android.content.SharedPreferences -import android.content.res.Resources -import android.os.Bundle -import android.widget.EditText -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.LinearLayoutManager -import de.jrpie.android.launcher.R -import de.jrpie.android.launcher.databinding.ActivityManageWidgetPanelsBinding -import de.jrpie.android.launcher.preferences.LauncherPreferences -import de.jrpie.android.launcher.ui.UIObject -import de.jrpie.android.launcher.widgets.WidgetPanel -import de.jrpie.android.launcher.widgets.updateWidgetPanel - -class ManageWidgetPanelsActivity : AppCompatActivity(), UIObject { - - private val sharedPreferencesListener = - SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> - if (prefKey == LauncherPreferences.widgets().keys().customPanels()) { - viewAdapter.widgetPanels = - (LauncherPreferences.widgets().customPanels() ?: setOf()).toTypedArray() - - @SuppressLint("NotifyDataSetChanged") - viewAdapter.notifyDataSetChanged() - } - } - private lateinit var binding: ActivityManageWidgetPanelsBinding - private lateinit var viewAdapter: WidgetPanelsRecyclerAdapter - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - super.onCreate() - - binding = ActivityManageWidgetPanelsBinding.inflate(layoutInflater) - setContentView(binding.main) - - val viewManager = LinearLayoutManager(this) - viewAdapter = WidgetPanelsRecyclerAdapter(this, true) { widgetPanel -> - startActivity( - Intent( - this@ManageWidgetPanelsActivity, - ManageWidgetsActivity::class.java - ).also { - it.putExtra(EXTRA_PANEL_ID, widgetPanel.id) - }) - } - binding.manageWidgetPanelsRecycler.apply { - setHasFixedSize(true) - layoutManager = viewManager - adapter = viewAdapter - } - binding.manageWidgetPanelsClose.setOnClickListener { finish() } - binding.manageWidgetPanelsAddPanel.setOnClickListener { - AlertDialog.Builder(this@ManageWidgetPanelsActivity, R.style.AlertDialogCustom).apply { - setTitle(R.string.dialog_create_widget_panel_title) - setNegativeButton(R.string.dialog_cancel) { _, _ -> } - setPositiveButton(R.string.dialog_ok) { dialogInterface, _ -> - val panelId = WidgetPanel.allocateId() - val label = (dialogInterface as? AlertDialog) - ?.findViewById(R.id.dialog_create_widget_panel_edit_text)?.text?.toString() - ?: (getString(R.string.widget_panel_default_name, panelId)) - - updateWidgetPanel(WidgetPanel(panelId, label)) - } - setView(R.layout.dialog_create_widget_panel) - }.create().also { it.show() }.apply { - findViewById(R.id.dialog_create_widget_panel_edit_text) - ?.setText( - getString( - R.string.widget_panel_default_name, - WidgetPanel.allocateId() - ) - ) - } - true - } - } - - override fun onStart() { - super.onStart() - super.onStart() - LauncherPreferences.getSharedPreferences() - .registerOnSharedPreferenceChangeListener(sharedPreferencesListener) - } - - override fun onPause() { - LauncherPreferences.getSharedPreferences() - .unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) - super.onPause() - } - - override fun getTheme(): Resources.Theme { - return modifyTheme(super.getTheme()) - } - - override fun setOnClicks() { - binding.manageWidgetPanelsClose.setOnClickListener { finish() } - } -} \ No newline at end of file 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 deleted file mode 100644 index a841919..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/ManageWidgetsActivity.kt +++ /dev/null @@ -1,184 +0,0 @@ -package de.jrpie.android.launcher.ui.widgets.manage - -import android.app.Activity -import android.appwidget.AppWidgetManager -import android.content.Intent -import android.content.SharedPreferences -import android.content.res.Resources -import android.graphics.Rect -import android.os.Bundle -import android.util.Log -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat -import com.google.android.material.floatingactionbutton.FloatingActionButton -import de.jrpie.android.launcher.Application -import de.jrpie.android.launcher.R -import de.jrpie.android.launcher.preferences.LauncherPreferences -import de.jrpie.android.launcher.ui.UIObject -import de.jrpie.android.launcher.ui.widgets.WidgetContainerView -import de.jrpie.android.launcher.widgets.AppWidget -import de.jrpie.android.launcher.widgets.WidgetPanel -import de.jrpie.android.launcher.widgets.WidgetPosition -import kotlin.math.min - - -// http://coderender.blogspot.com/2012/01/hosting-android-widgets-my.html - -const val REQUEST_CREATE_APPWIDGET = 1 -const val REQUEST_PICK_APPWIDGET = 2 - -const val EXTRA_PANEL_ID = "widgetPanelId" - -// We can't use AppCompatActivity, since some AppWidgets don't work there. -class ManageWidgetsActivity : Activity(), UIObject { - - private var panelId: Int = WidgetPanel.HOME.id - - private var sharedPreferencesListener = - SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> - if (prefKey == LauncherPreferences.widgets().keys().widgets()) { - findViewById(R.id.manage_widgets_container).updateWidgets(this, - LauncherPreferences.widgets().widgets() - ) - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - super.onCreate() - setContentView(R.layout.activity_manage_widgets) - - panelId = intent.extras?.getInt(EXTRA_PANEL_ID, WidgetPanel.HOME.id) ?: WidgetPanel.HOME.id - - findViewById(R.id.manage_widgets_button_add).setOnClickListener { - selectWidget() - } - - ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> - val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) - v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) - insets - } - - findViewById(R.id.manage_widgets_container).let { - it.widgetPanelId = panelId - it.updateWidgets(this, LauncherPreferences.widgets().widgets()) - } - } - - override fun onStart() { - super.onStart() - super.onStart() - - LauncherPreferences.getSharedPreferences() - .registerOnSharedPreferenceChangeListener(sharedPreferencesListener) - - } - - override fun onResume() { - super.onResume() - findViewById(R.id.manage_widgets_container).updateWidgets(this, - LauncherPreferences.widgets().widgets() - ) - - } - override fun getTheme(): Resources.Theme { - val mTheme = modifyTheme(super.getTheme()) - mTheme.applyStyle(R.style.backgroundWallpaper, true) - LauncherPreferences.clock().font().applyToTheme(mTheme) - LauncherPreferences.theme().colorTheme().applyToTheme( - mTheme, - LauncherPreferences.theme().textShadow() - ) - return mTheme - } - - override fun onDestroy() { - LauncherPreferences.getSharedPreferences() - .unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) - super.onDestroy() - } - - - fun selectWidget() { - val appWidgetHost = (application as Application).appWidgetHost - startActivityForResult( - Intent(this, SelectWidgetActivity::class.java).also { - it.putExtra( - AppWidgetManager.EXTRA_APPWIDGET_ID, - appWidgetHost.allocateAppWidgetId() - ) - it.putExtra( - EXTRA_PANEL_ID, - panelId - ) - }, REQUEST_PICK_APPWIDGET - ) - } - - - fun createWidget(data: Intent) { - Log.i("Launcher", "creating widget") - val appWidgetManager = (application as Application).appWidgetManager - val appWidgetId = data.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: return - - val provider = appWidgetManager.getAppWidgetInfo(appWidgetId) - - 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 widget = AppWidget(appWidgetId, position, panelId, provider) - LauncherPreferences.widgets().widgets( - (LauncherPreferences.widgets().widgets() ?: HashSet()).also { - it.add(widget) - } - ) - } - - private fun configureWidget(data: Intent) { - val extras = data.extras - val appWidgetId = extras!!.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) - val widget = AppWidget(appWidgetId, panelId = panelId) - if (widget.isConfigurable(this)) { - widget.configure(this, REQUEST_CREATE_APPWIDGET) - } else { - createWidget(data) - } - } - - override fun onActivityResult( - requestCode: Int, resultCode: Int, - data: Intent? - ) { - super.onActivityResult(requestCode, resultCode, data) - if (resultCode == RESULT_OK) { - if (requestCode == REQUEST_PICK_APPWIDGET) { - configureWidget(data!!) - } else if (requestCode == REQUEST_CREATE_APPWIDGET) { - createWidget(data!!) - } - } else if (resultCode == RESULT_CANCELED && data != null) { - val appWidgetId = - data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) - if (appWidgetId != -1) { - AppWidget(appWidgetId).delete(this) - } - } - } - - - /** - * For a better preview, [ManageWidgetsActivity] should behave exactly like [HomeActivity] - */ - override fun isHomeScreen(): Boolean { - return true - } -} diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/SelectWidgetActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/SelectWidgetActivity.kt deleted file mode 100644 index a1bd3b5..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/SelectWidgetActivity.kt +++ /dev/null @@ -1,172 +0,0 @@ -package de.jrpie.android.launcher.ui.widgets.manage - -import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProviderInfo -import android.content.Intent -import android.content.res.Resources -import android.os.Build -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import de.jrpie.android.launcher.R -import de.jrpie.android.launcher.databinding.ActivitySelectWidgetBinding -import de.jrpie.android.launcher.ui.UIObject -import de.jrpie.android.launcher.widgets.ClockWidget -import de.jrpie.android.launcher.widgets.LauncherAppWidgetProvider -import de.jrpie.android.launcher.widgets.LauncherClockWidgetProvider -import de.jrpie.android.launcher.widgets.LauncherWidgetProvider -import de.jrpie.android.launcher.widgets.WidgetPanel -import de.jrpie.android.launcher.widgets.WidgetPosition -import de.jrpie.android.launcher.widgets.bindAppWidgetOrRequestPermission -import de.jrpie.android.launcher.widgets.getAppWidgetHost -import de.jrpie.android.launcher.widgets.getAppWidgetProviders -import de.jrpie.android.launcher.widgets.updateWidget - - -private const val REQUEST_WIDGET_PERMISSION = 29 - -/** - * This activity lets the user pick an app widget to add. - * It provides an interface similar to [android.appwidget.AppWidgetManager.ACTION_APPWIDGET_PICK], - * but shows more information and also shows widgets from other user profiles. - */ -class SelectWidgetActivity : AppCompatActivity(), UIObject { - lateinit var binding: ActivitySelectWidgetBinding - var widgetId: Int = -1 - var widgetPanelId: Int = WidgetPanel.HOME.id - - private fun tryBindWidget(info: LauncherWidgetProvider) { - when (info) { - is LauncherAppWidgetProvider -> { - if (bindAppWidgetOrRequestPermission( - this, - info.info, - widgetId, - REQUEST_WIDGET_PERMISSION - ) - ) { - setResult( - RESULT_OK, - Intent().also { - it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId) - it.putExtra(EXTRA_PANEL_ID, widgetPanelId) - } - ) - finish() - } - } - is LauncherClockWidgetProvider -> { - updateWidget(ClockWidget(widgetId, WidgetPosition(0, 4, 12, 3), widgetPanelId)) - finish() - } - } - } - - override fun onStart() { - super.onStart() - super.onStart() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - super.onCreate() - - binding = ActivitySelectWidgetBinding.inflate(layoutInflater) - setContentView(binding.root) - - - widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) - widgetPanelId = intent.getIntExtra(EXTRA_PANEL_ID, WidgetPanel.HOME.id) - if (widgetId == -1) { - widgetId = getAppWidgetHost().allocateAppWidgetId() - } - - val viewManager = LinearLayoutManager(this) - val viewAdapter = SelectWidgetRecyclerAdapter() - - binding.selectWidgetRecycler.apply { - setHasFixedSize(false) - layoutManager = viewManager - adapter = viewAdapter - } - } - - override fun getTheme(): Resources.Theme { - return modifyTheme(super.getTheme()) - } - - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - if (requestCode == REQUEST_WIDGET_PERMISSION && resultCode == RESULT_OK) { - data ?: return - val provider = (data.getSerializableExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER) as? AppWidgetProviderInfo) ?: return - tryBindWidget(LauncherAppWidgetProvider(provider)) - } - } - - inner class SelectWidgetRecyclerAdapter() : - RecyclerView.Adapter() { - - private val widgets = getAppWidgetProviders(this@SelectWidgetActivity).toTypedArray() - - inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), - View.OnClickListener { - var textView: TextView = itemView.findViewById(R.id.list_widgets_row_name) - var descriptionView: TextView = itemView.findViewById(R.id.list_widgets_row_description) - var iconView: ImageView = itemView.findViewById(R.id.list_widgets_row_icon) - var previewView: ImageView = itemView.findViewById(R.id.list_widgets_row_preview) - - - override fun onClick(v: View) { - tryBindWidget(widgets[bindingAdapterPosition]) - } - - init { - itemView.setOnClickListener(this) - } - } - - override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { - val label = widgets[i].loadLabel(this@SelectWidgetActivity) - val description = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - widgets[i].loadDescription(this@SelectWidgetActivity) - } else { - "" - } - val preview = - widgets[i].loadPreviewImage(this@SelectWidgetActivity) - val icon = - widgets[i].loadIcon(this@SelectWidgetActivity) - - viewHolder.textView.text = label - viewHolder.descriptionView.text = description - viewHolder.descriptionView.visibility = - if (description?.isEmpty() == false) { View.VISIBLE } else { View.GONE } - viewHolder.iconView.setImageDrawable(icon) - - viewHolder.previewView.setImageDrawable(preview) - viewHolder.previewView.visibility = - if (preview != null) { View.VISIBLE } else { View.GONE } - - viewHolder.previewView.requestLayout() - } - - override fun getItemCount(): Int { - return widgets.size - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val inflater = LayoutInflater.from(parent.context) - val view: View = inflater.inflate(R.layout.list_widgets_row, parent, false) - return ViewHolder(view) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetManagerView.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetManagerView.kt deleted file mode 100644 index 76a2572..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetManagerView.kt +++ /dev/null @@ -1,199 +0,0 @@ -package de.jrpie.android.launcher.ui.widgets.manage - -import android.annotation.SuppressLint -import android.app.Activity -import android.content.Context -import android.graphics.Point -import android.graphics.Rect -import android.graphics.RectF -import android.os.Build -import android.os.Handler -import android.os.Looper -import android.util.AttributeSet -import android.view.HapticFeedbackConstants -import android.view.MotionEvent -import android.view.View -import android.view.ViewConfiguration -import androidx.core.graphics.contains -import androidx.core.graphics.minus -import androidx.core.graphics.toRect -import de.jrpie.android.launcher.ui.widgets.WidgetContainerView -import de.jrpie.android.launcher.widgets.GRID_SIZE -import de.jrpie.android.launcher.widgets.Widget -import de.jrpie.android.launcher.widgets.WidgetPanel -import de.jrpie.android.launcher.widgets.WidgetPosition -import de.jrpie.android.launcher.widgets.updateWidget - -/** - * A variant of the [WidgetContainerView] which allows to manage widgets. - */ -class WidgetManagerView(widgetPanelId: Int, context: Context, attrs: AttributeSet? = null) : - WidgetContainerView(widgetPanelId, context, attrs) { - constructor(context: Context, attrs: AttributeSet?) : this(WidgetPanel.HOME.id, context, attrs) - - val TOUCH_SLOP: Int - val TOUCH_SLOP_SQUARE: Int - val LONG_PRESS_TIMEOUT: Long - - - private var overlayViewById = HashMap() - - init { - val configuration = ViewConfiguration.get(context) - TOUCH_SLOP = configuration.scaledTouchSlop - TOUCH_SLOP_SQUARE = TOUCH_SLOP * TOUCH_SLOP - - LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout().toLong() - } - - - enum class EditMode(val resize: (dx: Int, dy: Int, screenWidth: Int, screenHeight: Int, rect: Rect) -> Rect) { - MOVE({ dx, dy, sw, sh, rect -> - val cdx = dx.coerceIn(-rect.left, sw - rect.right) - val cdy = dy.coerceIn(-rect.top, sh - rect.bottom) - Rect(rect.left + cdx, rect.top + cdy, rect.right + cdx, rect.bottom + cdy) - }), - TOP({ _, dy, _, sh, rect -> - val cdy = dy.coerceIn(-rect.top, rect.bottom - rect.top - (2 * sh / GRID_SIZE) + 5) - Rect(rect.left, rect.top + cdy, rect.right, rect.bottom) - }), - BOTTOM({ _, dy, _, sh, rect -> - val cdy = - dy.coerceIn((2 * sh / GRID_SIZE) + 5 + rect.top - rect.bottom, sh - rect.bottom) - Rect(rect.left, rect.top, rect.right, rect.bottom + cdy) - }), - LEFT({ dx, _, sw, _, rect -> - val cdx = dx.coerceIn(-rect.left, rect.right - rect.left - (2 * sw / GRID_SIZE) + 5) - Rect(rect.left + cdx, rect.top, rect.right, rect.bottom) - }), - RIGHT({ dx, _, sw, _, rect -> - val cdx = - dx.coerceIn((2 * sw / GRID_SIZE) + 5 + rect.left - rect.right, sw - rect.right) - Rect(rect.left, rect.top, rect.right + cdx, rect.bottom) - }), - } - - private var selectedWidgetOverlayView: WidgetOverlayView? = null - private var selectedWidgetView: View? = null - private var currentGestureStart: Point? = null - private var startWidgetPosition: Rect? = null - private var lastPosition = Rect() - - private val longPressHandler = Handler(Looper.getMainLooper()) - - - override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { - return true - } - - @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent?): Boolean { - if (event == null) { - return false - } - synchronized(this) { - if (event.actionMasked == MotionEvent.ACTION_DOWN) { - val start = Point(event.x.toInt(), event.y.toInt()) - currentGestureStart = start - val view = overlayViewById.asIterable() - .map { it.value }.firstOrNull { overlayView -> - RectF( - overlayView.x, - overlayView.y, - overlayView.x + overlayView.width, - overlayView.y + overlayView.height - ) - .toRect() - .contains(start) - } ?: return true - - val position = - (view.layoutParams as Companion.LayoutParams).position.getAbsoluteRect( - width, - height - ) - selectedWidgetOverlayView = view - selectedWidgetView = widgetViewById[view.widgetId] ?: return true - startWidgetPosition = position - - val positionInView = start.minus(Point(position.left, position.top)) - view.mode = - view.getHandles().firstOrNull { it.position.contains(positionInView) }?.mode - ?: EditMode.MOVE - - longPressHandler.postDelayed({ - synchronized(this@WidgetManagerView) { - view.showPopupMenu() - view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - endInteraction() - } - }, LONG_PRESS_TIMEOUT) - } - if (event.actionMasked == MotionEvent.ACTION_MOVE || - event.actionMasked == MotionEvent.ACTION_UP - ) { - val distanceX = event.x - (currentGestureStart?.x ?: return true) - val distanceY = event.y - (currentGestureStart?.y ?: return true) - if (distanceX * distanceX + distanceY * distanceY > TOUCH_SLOP_SQUARE) { - longPressHandler.removeCallbacksAndMessages(null) - } - val view = selectedWidgetOverlayView ?: return true - val start = startWidgetPosition ?: return true - val absoluteNewPosition = (view.mode ?: return true).resize( - distanceX.toInt(), - distanceY.toInt(), - width, height, - start - ) - val newPosition = WidgetPosition.fromAbsoluteRect( - absoluteNewPosition, width, height - ) - if (absoluteNewPosition != lastPosition) { - lastPosition = absoluteNewPosition - (view.layoutParams as Companion.LayoutParams).position = newPosition - (selectedWidgetView?.layoutParams as? Companion.LayoutParams)?.position = - newPosition - requestLayout() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS) - } - } - - if (event.actionMasked == MotionEvent.ACTION_UP) { - longPressHandler.removeCallbacksAndMessages(null) - val id = selectedWidgetOverlayView?.widgetId ?: return true - val widget = Widget.byId(context, id) ?: return true - widget.position = newPosition - endInteraction() - updateWidget(widget) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - view.performHapticFeedback(HapticFeedbackConstants.GESTURE_END) - } - } - } - } - return true - } - - private fun endInteraction() { - startWidgetPosition = null - selectedWidgetOverlayView?.mode = null - } - - override fun updateWidgets(activity: Activity, widgets: Collection?) { - super.updateWidgets(activity, widgets) - - synchronized(overlayViewById) { - overlayViewById.forEach { removeView(it.value) } - overlayViewById.clear() - widgets?.filter { it.panelId == widgetPanelId }?.forEach { widget -> - WidgetOverlayView(activity).let { - it.widgetId = widget.id - addView(it) - (it.layoutParams as Companion.LayoutParams).position = widget.position - overlayViewById[widget.id] = it - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetOverlayView.kt b/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetOverlayView.kt deleted file mode 100644 index 1b8a2d2..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetOverlayView.kt +++ /dev/null @@ -1,132 +0,0 @@ -package de.jrpie.android.launcher.ui.widgets.manage - -import android.content.Context -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.Rect -import android.graphics.drawable.Drawable -import android.util.AttributeSet -import android.view.View -import android.widget.PopupMenu -import androidx.core.graphics.toRectF -import de.jrpie.android.launcher.R -import de.jrpie.android.launcher.widgets.Widget -import de.jrpie.android.launcher.widgets.updateWidget - - -private const val HANDLE_SIZE = 100 -private const val HANDLE_EDGE_SIZE = (1.2 * HANDLE_SIZE).toInt() - -/** - * An overlay to show configuration options for a widget in [WidgetManagerView] - */ -class WidgetOverlayView : View { - - - val paint = Paint() - val handlePaint = Paint() - val selectedHandlePaint = Paint() - var mode: WidgetManagerView.EditMode? = null - class Handle(val mode: WidgetManagerView.EditMode, val position: Rect) - init { - handlePaint.style = Paint.Style.STROKE - handlePaint.setARGB(255, 255, 255, 255) - - selectedHandlePaint.style = Paint.Style.FILL_AND_STROKE - selectedHandlePaint.setARGB(100, 255, 255, 255) - - paint.style = Paint.Style.STROKE - paint.setARGB(255, 255, 255, 255) - } - - private var preview: Drawable? = null - var widgetId: Int = -1 - set(newId) { - field = newId - preview = Widget.byId(context, widgetId)?.getPreview(context) - } - - constructor(context: Context) : super(context) { - init(null, 0) - } - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(attrs, 0) - } - - constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super( - context, - attrs, - defStyle - ) { - init(attrs, defStyle) - } - - private fun init(attrs: AttributeSet?, defStyle: Int) { } - - override fun onDraw(canvas: Canvas) { - super.onDraw(canvas) - - getHandles().forEach { - if (it.mode == mode) { - canvas.drawRoundRect(it.position.toRectF(), 5f, 5f, selectedHandlePaint) - } else { - canvas.drawRoundRect(it.position.toRectF(), 5f, 5f, handlePaint) - } - } - val bounds = getBounds() - canvas.drawRoundRect(bounds.toRectF(), 5f, 5f, paint) - - if (mode == null) { - return - } - - //preview?.bounds = bounds - //preview?.draw(canvas) - - - } - - fun showPopupMenu() { - val widget = Widget.byId(context, widgetId)?: return - val menu = PopupMenu(context, this) - menu.menu.let { - it.add( - context.getString(R.string.widget_menu_remove) - ).setOnMenuItemClickListener { _ -> - Widget.byId(context, widgetId)?.delete(context) - return@setOnMenuItemClickListener true - } - it.add( - if (widget.allowInteraction) { - context.getString(R.string.widget_menu_disable_interaction) - } else { - context.getString(R.string.widget_menu_enable_interaction) - } - ).setOnMenuItemClickListener { _ -> - widget.allowInteraction = !widget.allowInteraction - updateWidget(widget) - return@setOnMenuItemClickListener true - } - } - menu.show() - } - - fun getHandles(): List { - return listOf( - Handle(WidgetManagerView.EditMode.TOP, - Rect(HANDLE_EDGE_SIZE, 0, width - HANDLE_EDGE_SIZE, HANDLE_SIZE)), - Handle(WidgetManagerView.EditMode.BOTTOM, - Rect(HANDLE_EDGE_SIZE, height - HANDLE_SIZE, width - HANDLE_EDGE_SIZE, height)), - Handle(WidgetManagerView.EditMode.LEFT, - Rect(0, HANDLE_EDGE_SIZE, HANDLE_SIZE, height - HANDLE_EDGE_SIZE)), - Handle(WidgetManagerView.EditMode.RIGHT, - Rect(width - HANDLE_SIZE, HANDLE_EDGE_SIZE, width, height - HANDLE_EDGE_SIZE)) - ) - - } - - private fun getBounds(): Rect { - return Rect(0,0, width, height) - } -} \ No newline at end of file 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 deleted file mode 100644 index 40c2c2f..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/ui/widgets/manage/WidgetPanelsRecyclerAdapter.kt +++ /dev/null @@ -1,98 +0,0 @@ -package de.jrpie.android.launcher.ui.widgets.manage - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.EditText -import android.widget.PopupMenu -import android.widget.TextView -import androidx.appcompat.app.AlertDialog -import androidx.recyclerview.widget.RecyclerView -import de.jrpie.android.launcher.R -import de.jrpie.android.launcher.preferences.LauncherPreferences -import de.jrpie.android.launcher.widgets.WidgetPanel -import de.jrpie.android.launcher.widgets.updateWidgetPanel - - -class WidgetPanelsRecyclerAdapter( - val context: Context, - val showMenu: Boolean = false, - val onSelectWidgetPanel: (WidgetPanel) -> Unit -) : - RecyclerView.Adapter() { - - var widgetPanels = (LauncherPreferences.widgets().customPanels() ?: setOf()).toTypedArray() - - class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - var labelView: TextView = itemView.findViewById(R.id.list_widget_panels_label) - } - - override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { - viewHolder.labelView.text = widgetPanels[i].label - - viewHolder.itemView.setOnClickListener { - onSelectWidgetPanel(widgetPanels[i]) - } - - if (showMenu) { - viewHolder.itemView.setOnLongClickListener { - showOptionsPopup( - viewHolder, - widgetPanels[i] - ) - } - } - } - - @Suppress("SameReturnValue") - private fun showOptionsPopup( - viewHolder: ViewHolder, - widgetPanel: WidgetPanel - ): Boolean { - //create the popup menu - - val popup = PopupMenu(context, viewHolder.labelView) - popup.menu.add(R.string.manage_widget_panels_delete).setOnMenuItemClickListener { _ -> - widgetPanel.delete(context) - true - } - popup.menu.add(R.string.manage_widget_panels_rename).setOnMenuItemClickListener { _ -> - AlertDialog.Builder(context, R.style.AlertDialogCustom).apply { - setNegativeButton(R.string.dialog_cancel) { _, _ -> } - setPositiveButton(R.string.dialog_ok) { dialogInterface, _ -> - var newLabel = (dialogInterface as? AlertDialog) - ?.findViewById(R.id.dialog_rename_widget_panel_edit_text) - ?.text?.toString() - if (newLabel == null || newLabel.isEmpty()) { - newLabel = - (context.getString(R.string.widget_panel_default_name, widgetPanel.id)) - } - widgetPanel.label = newLabel - updateWidgetPanel(widgetPanel) - } - setView(R.layout.dialog_rename_widget_panel) - }.create().also { it.show() }.apply { - findViewById(R.id.dialog_rename_widget_panel_edit_text)?.let { - it.setText(widgetPanel.label) - it.hint = context.getString(R.string.widget_panel_default_name, widgetPanel.id) - } - } - true - } - - popup.show() - return true - } - - override fun getItemCount(): Int { - return widgetPanels.size - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val view: View = - LayoutInflater.from(context).inflate(R.layout.list_widget_panels_row, parent, false) - val viewHolder = ViewHolder(view) - return viewHolder - } -} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt deleted file mode 100644 index 22a63eb..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt +++ /dev/null @@ -1,126 +0,0 @@ -package de.jrpie.android.launcher.widgets - -import android.app.Activity -import android.appwidget.AppWidgetHostView -import android.appwidget.AppWidgetProviderInfo -import android.content.Context -import android.graphics.drawable.Drawable -import android.os.Build -import android.os.Bundle -import android.util.DisplayMetrics -import android.util.SizeF -import android.view.View -import de.jrpie.android.launcher.Application -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -@SerialName("widget:app") -class AppWidget( - override val id: Int, - override var position: WidgetPosition = WidgetPosition(0,0,1,1), - override var panelId: Int = WidgetPanel.HOME.id, - override var allowInteraction: Boolean = false, - - // We keep track of packageName, className and user to make it possible to restore the widget - // on a new device when restoring settings (currently not implemented) - // In normal operation only id and position are used. - val packageName: String? = null, - val className: String? = null, - val user: Int? = null -): Widget() { - - - constructor( - id: Int, - position: WidgetPosition, - panelId: Int, - widgetProviderInfo: AppWidgetProviderInfo - ) : - this( - id, - position, - panelId, - false, - widgetProviderInfo.provider.packageName, - widgetProviderInfo.provider.className, - widgetProviderInfo.profile.hashCode() - ) - - /** - * Get the [AppWidgetProviderInfo] by [id]. - * If the widget is not installed, use [restoreAppWidgetProviderInfo] instead. - */ - fun getAppWidgetProviderInfo(context: Context): AppWidgetProviderInfo? { - if (id < 0) { - return null - } - return (context.applicationContext as Application).appWidgetManager - .getAppWidgetInfo(id) - } - - /** - * Restore the AppWidgetProviderInfo from [user], [packageName] and [className]. - * Only use this when the widget is not installed, - * in normal operation use [getAppWidgetProviderInfo] instead. - */ - /*fun restoreAppWidgetProviderInfo(context: Context): AppWidgetProviderInfo? { - return getAppWidgetProviders(context).firstOrNull { - it.profile.hashCode() == user - && it.provider.packageName == packageName - && it.provider.className == className - } - }*/ - - override fun toString(): String { - return "WidgetInfo(id=$id, position=$position, packageName=$packageName, className=$className, user=$user)" - } - - override fun createView(activity: Activity): AppWidgetHostView? { - val providerInfo = activity.getAppWidgetManager().getAppWidgetInfo(id) ?: return null - val view = activity.getAppWidgetHost() - .createView(activity, this.id, providerInfo) - - val dp = activity.resources.displayMetrics.density - val screenWidth = activity.resources.displayMetrics.widthPixels - val screenHeight = activity.resources.displayMetrics.heightPixels - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - val absolutePosition = position.getAbsoluteRect(screenWidth, screenHeight) - view.updateAppWidgetSize(Bundle.EMPTY, - listOf(SizeF( - absolutePosition.width() / dp, - absolutePosition.height() / dp - ))) - } - view.setPadding(0,0,0,0) - return view - } - - override fun findView(views: Sequence): AppWidgetHostView? { - return views.mapNotNull { it as? AppWidgetHostView }.firstOrNull { it.appWidgetId == id } - } - - override fun getIcon(context: Context): Drawable? { - return context.getAppWidgetManager().getAppWidgetInfo(id)?.loadIcon(context, DisplayMetrics.DENSITY_HIGH) - } - - override fun getPreview(context: Context): Drawable? { - return context.getAppWidgetManager().getAppWidgetInfo(id)?.loadPreviewImage(context, DisplayMetrics.DENSITY_HIGH) - } - - override fun isConfigurable(context: Context): Boolean { - return context.getAppWidgetManager().getAppWidgetInfo(id)?.configure != null - } - override fun configure(activity: Activity, requestCode: Int) { - if (!isConfigurable(activity)) { - return - } - activity.getAppWidgetHost().startAppWidgetConfigureActivityForResult( - activity, - id, - 0, - requestCode, - null - ) - } -} diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/ClockWidget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/ClockWidget.kt deleted file mode 100644 index d0d1c0e..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/ClockWidget.kt +++ /dev/null @@ -1,42 +0,0 @@ -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.ClockView -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - - -@Serializable -@SerialName("widget:clock") -class ClockWidget( - 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 ClockView(activity, null, id) - } - - override fun findView(views: Sequence): ClockView? { - return views.mapNotNull { it as? ClockView }.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 deleted file mode 100644 index 018b29b..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/LauncherWidgetProvider.kt +++ /dev/null @@ -1,58 +0,0 @@ -package de.jrpie.android.launcher.widgets - -import android.appwidget.AppWidgetProviderInfo -import android.content.Context -import android.graphics.drawable.Drawable -import android.os.Build -import android.util.DisplayMetrics -import androidx.appcompat.content.res.AppCompatResources -import de.jrpie.android.launcher.R - -sealed class LauncherWidgetProvider { - abstract fun loadLabel(context: Context): CharSequence? - abstract fun loadPreviewImage(context: Context): Drawable? - abstract fun loadIcon(context: Context): Drawable? - abstract fun loadDescription(context: Context): CharSequence? -} - -class LauncherAppWidgetProvider(val info: AppWidgetProviderInfo) : LauncherWidgetProvider() { - - override fun loadLabel(context: Context): CharSequence? { - return info.loadLabel(context.packageManager) - } - override fun loadPreviewImage(context: Context): Drawable? { - return info.loadPreviewImage(context, DisplayMetrics.DENSITY_DEFAULT) - } - - override fun loadIcon(context: Context): Drawable? { - return info.loadIcon(context, DisplayMetrics.DENSITY_DEFAULT) - } - - override fun loadDescription(context: Context): CharSequence? { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - info.loadDescription(context) - } else { - null - } - } - -} -class LauncherClockWidgetProvider : LauncherWidgetProvider() { - - override fun loadLabel(context: Context): CharSequence? { - return context.getString(R.string.widget_clock_label) - } - - override fun loadDescription(context: Context): CharSequence? { - return context.getString(R.string.widget_clock_description) - } - - override fun loadPreviewImage(context: Context): Drawable? { - return null - } - - override fun loadIcon(context: Context): Drawable? { - return AppCompatResources.getDrawable(context, R.drawable.baseline_clock_24) - } -} - 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 deleted file mode 100644 index e31250b..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt +++ /dev/null @@ -1,66 +0,0 @@ -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.Application -import de.jrpie.android.launcher.preferences.LauncherPreferences -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json - - -@Serializable -sealed class Widget { - abstract val id: Int - abstract var position: WidgetPosition - abstract val panelId: Int - abstract var allowInteraction: Boolean - - /** - * @param activity The activity where the view will be used. Must not be an AppCompatActivity. - */ - abstract fun createView(activity: Activity): View? - abstract fun findView(views: Sequence): View? - abstract fun getPreview(context: Context): Drawable? - abstract fun getIcon(context: Context): Drawable? - abstract fun isConfigurable(context: Context): Boolean - abstract fun configure(activity: Activity, requestCode: Int) - - fun delete(context: Context) { - context.getAppWidgetHost().deleteAppWidgetId(id) - - LauncherPreferences.widgets().widgets( - LauncherPreferences.widgets().widgets()?.also { - it.remove(this) - } - ) - } - - fun getPanel(): WidgetPanel? { - return WidgetPanel.byId(panelId) - } - - override fun hashCode(): Int { - return id - } - - override fun equals(other: Any?): Boolean { - return (other as? Widget)?.id == id - } - - fun serialize(): String { - return Json.encodeToString(serializer(), this) - } - companion object { - fun deserialize(serialized: String): Widget { - return Json.decodeFromString(serialized) - } - fun byId(context: Context, id: Int): Widget? { - // TODO: do some caching - return LauncherPreferences.widgets().widgets().firstOrNull() { - it.id == id - } - } - } -} 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 deleted file mode 100644 index 93e588d..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPanel.kt +++ /dev/null @@ -1,58 +0,0 @@ -package de.jrpie.android.launcher.widgets - -import android.content.Context -import de.jrpie.android.launcher.preferences.LauncherPreferences -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json - - -@Serializable -@SerialName("panel") -class WidgetPanel(val id: Int, var label: String) { - - override fun equals(other: Any?): Boolean { - return (other as? WidgetPanel)?.id == id - } - - override fun hashCode(): Int { - return id - } - - fun serialize(): String { - return Json.encodeToString(this) - } - - fun delete(context: Context) { - LauncherPreferences.widgets().customPanels( - (LauncherPreferences.widgets().customPanels() ?: setOf()).minus(this) - ) - (LauncherPreferences.widgets().widgets() ?: return) - .filter { it.panelId == this.id }.forEach { it.delete(context) } - } - - - companion object { - val HOME = WidgetPanel(0, "home") - fun byId(id: Int): WidgetPanel? { - if (id == 0) { - return HOME - } - return LauncherPreferences.widgets().customPanels()?.firstOrNull { it.id == id } - } - - fun allocateId(): Int { - return ( - (LauncherPreferences.widgets().customPanels() ?: setOf()) - .plus(HOME) - .maxOfOrNull { it.id } ?: 0 - ) + 1 - } - - fun deserialize(serialized: String): WidgetPanel { - return Json.decodeFromString(serialized) - } - - } -} \ No newline at end of file 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 deleted file mode 100644 index b575665..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/WidgetPosition.kt +++ /dev/null @@ -1,58 +0,0 @@ -package de.jrpie.android.launcher.widgets - -import android.graphics.Rect -import kotlinx.serialization.Serializable -import kotlin.math.ceil -import kotlin.math.roundToInt -import kotlin.math.max - -const val GRID_SIZE: Short = 12 - -@Serializable -data class WidgetPosition(var x: Short, var y: Short, var width: Short, var height: Short) { - - fun getAbsoluteRect(screenWidth: Int, screenHeight: Int): Rect { - val gridWidth = screenWidth / GRID_SIZE.toFloat() - val gridHeight= screenHeight / GRID_SIZE.toFloat() - - return Rect( - (x * gridWidth).toInt(), - (y * gridHeight).toInt(), - ((x + width) * gridWidth).toInt(), - ((y + height) * gridHeight).toInt() - ) - } - - companion object { - fun fromAbsoluteRect(absolute: Rect, screenWidth: Int, screenHeight: Int): WidgetPosition { - val gridWidth = screenWidth / 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 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) - - } - - fun center(minWidth: Int, minHeight: Int, screenWidth: Int, screenHeight: Int): WidgetPosition { - val gridWidth = screenWidth / GRID_SIZE.toFloat() - val gridHeight= screenHeight / GRID_SIZE.toFloat() - - val cellsWidth = ceil(minWidth / gridWidth).toInt().toShort() - val cellsHeight = ceil(minHeight / gridHeight).toInt().toShort() - - return WidgetPosition( - ((GRID_SIZE - cellsWidth) / 2).toShort(), - ((GRID_SIZE - cellsHeight) / 2).toShort(), - cellsWidth, - cellsHeight - ) - - } - } -} \ No newline at end of file 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 deleted file mode 100644 index b7f140b..0000000 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/Widgets.kt +++ /dev/null @@ -1,97 +0,0 @@ -package de.jrpie.android.launcher.widgets - -import android.app.Activity -import android.app.Service -import android.appwidget.AppWidgetHost -import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProviderInfo -import android.content.Context -import android.content.Intent -import android.content.pm.LauncherApps -import android.os.Build -import android.os.UserManager -import android.util.Log -import de.jrpie.android.launcher.Application -import de.jrpie.android.launcher.preferences.LauncherPreferences - -fun deleteAllWidgets(context: Context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.getAppWidgetHost().appWidgetIds.forEach { AppWidget(it).delete(context) } - } -} - -/** - * Tries to bind [providerInfo] to the id [id]. - * @param providerInfo The widget to be bound. - * @param id The id to bind the widget to. If -1 is provided, a new id is allocated. - * @param - * @param requestCode Used to start an activity to request permission to bind the widget. - * - * @return true iff the app widget was bound successfully. - */ -fun bindAppWidgetOrRequestPermission(activity: Activity, providerInfo: AppWidgetProviderInfo, id: Int, requestCode: Int? = null): Boolean { - val appWidgetId = if(id == -1) { - activity.getAppWidgetHost().allocateAppWidgetId() - } else { id } - - Log.i("Launcher", "Binding new widget ${appWidgetId}") - if (!activity.getAppWidgetManager().bindAppWidgetIdIfAllowed( - appWidgetId, - providerInfo.provider - ) - ) { - Log.i("Widgets", "requesting permission for widget") - val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_BIND).apply { - putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId) - putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, providerInfo.provider) - } - activity.startActivityForResult(intent, requestCode ?: 0) - return false - } - return true -} - - -fun getAppWidgetProviders( context: Context ): List { - val list = mutableListOf(LauncherClockWidgetProvider()) - val appWidgetManager = context.getAppWidgetManager() - val profiles = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - (context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps).profiles - } else { - (context.getSystemService(Service.USER_SERVICE) as UserManager).userProfiles - } - list.addAll( - profiles.map { - appWidgetManager.getInstalledProvidersForProfile(it) - .map { LauncherAppWidgetProvider(it) } - }.flatten() - ) - - - return list -} - - -fun updateWidget(widget: Widget) { - LauncherPreferences.widgets().widgets( - (LauncherPreferences.widgets().widgets() ?: setOf()) - .minus(widget) - .plus(widget) - ) -} - -fun updateWidgetPanel(widgetPanel: WidgetPanel) { - LauncherPreferences.widgets().customPanels( - (LauncherPreferences.widgets().customPanels() ?: setOf()) - .minus(widgetPanel) - .plus(widgetPanel) - ) -} - -fun Context.getAppWidgetHost(): AppWidgetHost { - return (this.applicationContext as Application).appWidgetHost -} -fun Context.getAppWidgetManager(): AppWidgetManager { - return (this.applicationContext as Application).appWidgetManager -} diff --git a/app/src/main/res/drawable/baseline_add_24.xml b/app/src/main/res/drawable/baseline_add_24.xml deleted file mode 100644 index 13267ce..0000000 --- a/app/src/main/res/drawable/baseline_add_24.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/baseline_clock_24.xml b/app/src/main/res/drawable/baseline_clock_24.xml deleted file mode 100644 index 7968998..0000000 --- a/app/src/main/res/drawable/baseline_clock_24.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/baseline_widgets_24.xml b/app/src/main/res/drawable/baseline_widgets_24.xml deleted file mode 100644 index fd0f571..0000000 --- a/app/src/main/res/drawable/baseline_widgets_24.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/app/src/main/res/layout/activity_manage_widget_panels.xml b/app/src/main/res/layout/activity_manage_widget_panels.xml deleted file mode 100644 index 60413a3..0000000 --- a/app/src/main/res/layout/activity_manage_widget_panels.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_manage_widgets.xml b/app/src/main/res/layout/activity_manage_widgets.xml deleted file mode 100644 index c77f0e3..0000000 --- a/app/src/main/res/layout/activity_manage_widgets.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_select_widget.xml b/app/src/main/res/layout/activity_select_widget.xml deleted file mode 100644 index 82db94d..0000000 --- a/app/src/main/res/layout/activity_select_widget.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_widget_panel.xml b/app/src/main/res/layout/activity_widget_panel.xml deleted file mode 100644 index 6ef6b20..0000000 --- a/app/src/main/res/layout/activity_widget_panel.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/clock.xml b/app/src/main/res/layout/clock.xml deleted file mode 100644 index d81fc5f..0000000 --- a/app/src/main/res/layout/clock.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_choose_color.xml b/app/src/main/res/layout/dialog_choose_color.xml index dc7ddca..90d13c3 100644 --- a/app/src/main/res/layout/dialog_choose_color.xml +++ b/app/src/main/res/layout/dialog_choose_color.xml @@ -24,21 +24,6 @@ android:layout_width="match_parent" android:layout_height="10dp" /> - - - - - - + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_create_widget_panel.xml b/app/src/main/res/layout/dialog_create_widget_panel.xml deleted file mode 100644 index 900823d..0000000 --- a/app/src/main/res/layout/dialog_create_widget_panel.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_rename_widget_panel.xml b/app/src/main/res/layout/dialog_rename_widget_panel.xml deleted file mode 100644 index effb783..0000000 --- a/app/src/main/res/layout/dialog_rename_widget_panel.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_select_widget_panel.xml b/app/src/main/res/layout/dialog_select_widget_panel.xml deleted file mode 100644 index 5f83d51..0000000 --- a/app/src/main/res/layout/dialog_select_widget_panel.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/home.xml b/app/src/main/res/layout/home.xml index 717151f..ecefdea 100644 --- a/app/src/main/res/layout/home.xml +++ b/app/src/main/res/layout/home.xml @@ -10,10 +10,29 @@ android:fitsSystemWindows="true" tools:context=".ui.HomeActivity"> - + + + - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/list_widgets_header.xml b/app/src/main/res/layout/list_widgets_header.xml deleted file mode 100644 index 7779f2b..0000000 --- a/app/src/main/res/layout/list_widgets_header.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/list_widgets_row.xml b/app/src/main/res/layout/list_widgets_row.xml deleted file mode 100644 index 878aaad..0000000 --- a/app/src/main/res/layout/list_widgets_row.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index b0f66f9..1b7d9a2 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -153,7 +153,7 @@ لا تفعل شيئًا قفل الشاشة تبديل الفلاش - تشغيل شاشة رئيسية أخرى + شغل شاشة منزل أخرى أضف اختصارًا اربط بإيماءة درس تعليمي @@ -261,56 +261,4 @@ اسحب من حواف الشاشة خطأ: قفل الشاشة باستخدام إمكانية الوصول غير مدعوم على هذا الجهاز. الرجاء استخدام طريقة مسؤول الجهاز بدلاً من ذلك. يتيح تعيين μlauncher كخدمة إمكانية الوصول قفل الشاشة وفتح قائمة التطبيقات الحديثة. يرجى ملاحظة أنه يتطلب كمية كبيرة من الأذونات. يجب ألا تمنح مثل هذه الأذونات باستخفاف لأي تطبيق. سوف يستخدم μlauncher خدمة إمكانية الوصول فقط لأداء الإجراءات التالية عند طلب المستخدم: * قفل شاشة * فتح التطبيقات الحديثة μlauncher لن يستخدم أبدًا خدمة إمكانية الوصول لجمع البيانات. يمكنك التحقق من شيفرة المصدر للتأكد. يرجى ملاحظة أنه يمكنك قفل الشاشة من خلال منح أذونات مسؤول الجهاز، لكنها لا تعمل مع بصمات الأصابع وفتح الوجه. - إنشاء لوحة أداة جديدة - إدارة الأدوات المصغّرة - إدارة لوحات الأدوات المصغّرة - اختر طريقة القفل - هناك طريقتان لقفل الشاشة. - للأسف، كلا الطريقتين لهما عيوب:

- -

إدارة الجهاز

- لا تعمل مع فتح القفل باستخدام بصمة الإصبع أو التعرف على الوجه. - -
-
- -

خدمة الوصول

- تتطلب صلاحيات واسعة. - سيستخدم تطبيق μLauncher هذه الصلاحيات فقط لقفل الشاشة. -
- (يجب ألا تثق بتطبيق عشوائي قمت بتحميله للتو بهذا الادعاء، ولكن يمكنك التحقق من الكود المصدري.) -
- في بعض الأجهزة، لن يُستخدم رمز PIN الخاص بالتشغيل لتشفير البيانات بعد تفعيل خدمة الوصول. - يمكن إعادة تفعيل هذا لاحقًا. - -



- يمكنك تغيير اختيارك لاحقًا في الإعدادات. -]]>
- الساعة الافتراضية لـ μLauncher - <![CDATA[لم يتم العثور على لوحات عناصر واجهة المستخدم. يمكنك إنشاء لوحات الأدوات في الإعدادات > المشغّل > إدارة لوحات الأدوات.]]. - اختر الأداة - إزالة - تهيئة - Enable Interaction - تعطيل التفاعل - ساعة - حذف - إعادة التسمية - لوحة الأداة المصغّرة #%1$d - حسنا - لوحات الأداة - تحديد لوحة الأداة - افتح لوحة الأدوات - لم تعد لوحة الأدوات هذه موجودة. - الأدوات - - يحتوي على %d أداة. - يحتوي على %d أداة. - يحتوي على %d أدوات. - يحتوي على %d أدوات. - يحتوي على %d أداة. - - - إغلاق لوحة المفاتيح عند التمرير diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 71bc28e..318ad43 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,17 +1,17 @@ - Scorri a destra sul bordo inferiore dello schermo + Scorri verso destra sul bordo inferiore dello schermo Aspetto - Associa app + Scegliere Tema - μLauncher è progettato per essere minimale, efficiente e privo di distrazione.\n\nNon contiene annunci e non raccoglie dati. + Questo launcher è progettato per essere minimale, efficiente e privo di distrazioni. Non contiene pagamenti, pubblicità o servizi di tracciamento. Predefinito - Non mostrare nella lista le applicazioni associate a gesti + Non mostrare applicazioni collegate a gesti nella lista delle app Testo - Impostare µLauncher come servizio accessibilità permette l\'azione di blocco dello schermo. Nota che sono richiesti permessi eccessivi. Non si dovrebbero mai concedere con leggerezza permessi ad alcuna app. µLauncher utilizza i servizi di accessibilità esclusivamente per il blocco dello schermo. Puoi verificare il codice sorgente. Nota che il blocco schermo si può attivare anche concedendo a µLauncher i permessi di amministratore, tuttavia tale metodo non funziona con lo sblocco tramite impronta o riconoscimento facciale. - Sans serif - Scorri verso l\'alto con due dita - Store non trovato + Impostare µLauncher come servizio accessibilità permette l\'azione di blocco dello schermo. Si precisa che sono richiesti permessi eccessivi. Non si dovrebbe mai concedere con leggerezza permessi ad alcuna app. µLauncher utilizza i servizi di accessibilità esclusivamente per il blocco dello schermo. Puoi verificare il codice sorgente. Si segnala che il blocco schermo si può attivare anche concedendo a µLauncher i permessi di amministratore, tuttavia tale metodo non funziona con lo sblocco tramite impronta o riconoscimento facciale. + Sans serif (senza grazie) + Trascina due dita dal basso verso l\'alto + Negozio non trovato Griglia Scegli un sistema di blocco @@ -30,118 +30,114 @@
(Non ci si dovrebbe mai fidare di un\'applicazione qualsiasi appena scaricata su queste cose, ma puoi verificare il codice sorgente.) - In alcuni dispositivi, il PIN iniziale non verrà più utilizzato per la crittografia dei dati dopo aver attivato un servizio di accessibilità. - - Può essere riattivato dopo. -



Puoi cambiare le tue scelte in seguito nelle impostazioni. ]]>
- Impossibile avviare l\'app - Modificare le impostazioni? - Apri impostazioni per associare un\'azione a questo gesto + Impossibile aprire l\'applicazione + Desideri modificare le impostazioni? + Apri le impostazioni per abbinare un\'azione a questo gesto Impostazioni Launcher Meta Scorri verso il basso con due dita Sinistra - Scorri verso sinistra - Due dita a sinistra - Scorri verso sinistra con due dita + Scorrere verso sinistra + Due dita verso sinistra + Scorrere verso sinistra con due dita Destra Scorri verso destra - Due dita a destra - Scorri verso destra con due dita + Due dita verso destra + Scorri a destra con due dita Destra (in alto) - Scorri a destra sul bordo superiore dello schermo - Scorri a sinistra sul bordo inferiore dello schermo - Scorri a sinistra sul bordo superiore dello schermo - Su (bordo sinistro) - Su - Scorri verso l\'alto - Giù - Scorri giù con due dita - Scorri verso il basso - Destra (in basso) - Sinistra (in basso) - Sinistra (in alto) - Scorri in alto sul bordo sinistro dello schermo - Su (bordo destro) - Scorri in alto sul bordo destro dello schermo - Giù (bordo sinistro) - Scorri in basso sul bordo sinistro dello schermo - Giù (bordo destro) - Scorri in basso sul bordo destro dello schermo - Volume + - Doppio tap - Doppio tap in spazio vuoto - Tap lungo - Tap lungo in spazio vuoto + Scorri verso destra sul bordo superiore dello schermo + Scorri verso sinistra sul bordo inferiore dello schermo + Scorri verso sinistra sul bordo superiore dello schermo + Verso l\'alto (lato sinistro) + Verso l\'alto + Striscia il dito dal basso verso l\'alto + Verso il basso + Trascina due dita dall\'alto verso il basso + Trascina un dito dall\'alto verso il basso + Destra (bordo inferiore) + Sinistra (bordo inferiore) + Sinistra (bordo superiore) + Scorri verso l\'alto sul bordo sinistro dello schermo + Alto (lato destro) + Scorri verso l\'alto sul bordo destro dello schermo + Basso (bordo sinistro) + Scorri verso il basso sul bordo sinistro dello schermo + Basso (Lato destro) + Scorri verso il basso sul lato destro dello schermo + Aumenta il volume + Doppio click + Doppio click in un\'area vuota + Tocco prolungato + Tocco prolungato su un\'area vuota Data - Tap sulla data + Premi sulla data Ora - Tap sull\'ora - Premi il pulsante Volume + - Volume - - Premi il pulsante Volume - - Installa apps + Premi sull\'ora + Premi il pulsante di aumento del volume + Riduci il volume + Premi il pulsante per ridurre il volume + Installa le applicazioni Icone monocromatiche - Mostra orario - Mostra data - Usa formato data locale - Mostra secondi + Mostra l\'ora + Mostra la data + Usa il formato ora locale + Mostra i secondi Scorri con due dita - Azioni a due dita + Azioni a scorrimento con due dita Apri il risultato della ricerca - Azioni sui bordi dello schermo - Scorri sui bordi dello schermo - Larghezza bordo - Codice sorgente + Azioni a scorrimento ai lati dello schermo + Scorri sul lato dello schermo + Larghezza margine laterale + Vedi il codice sorgente Tutte le applicazioni Applicazioni preferite - Musica: traccia successiva - Abbassa volume - Musica: traccia precedente - Alza volume + Musica: passa alla traccia successiva + Musica: riduci il volume + Musica: torna alla traccia precedente + Musica: Aumenta il volume Annulla Impostazioni rapide - Azione necessaria per abilitare il blocco schermo. - Ombreggiatura testo - Sfondo (lista apps e impostazioni) + Azione necessaria per abilitare il blocco dello schermo. + Ombreggiatura del testo + Sfondo (lista applicazioni e impostazioni) Font Inverti data e ora - Imposta sfondo + Scegli uno sfondo Schermo Mantieni lo schermo acceso - Ruota schermo - Funzioni - Apri automaticamente la tastiera + Ruota lo schermo + Funzionalità + Apri automaticamente la tastiera per cercare Sensibilità - Scegli applicazione + Scegli un\'applicazione Configurazione - Abbiamo impostato alcune app predefinite. Puoi modificarle ora se vuoi: - Puoi anche modificare la selezione in seguito. + Abbiamo impostato alcune app predefinite per te. Puoi modificarle ora se lo desideri: + Puoi anche cambiare la tua selezione in seguito. Iniziamo! - Sei pronto per iniziare!\n\nSpero che lo apprezzi!\n\n- Finn (che ha fatto Launcher) e Josia (che ha apportato alcuni miglioramenti e mantiene il fork μLauncher) + Sei pronto per iniziare! Spero questa applicazione ti risulti preziosa! - Finn (che ha ideato il launcher)\n \te Josia (che ha aggiunto qualche miglioramento e mantiene il fork μLauncher) Inizia Impostazioni Altre opzioni - Puoi avviare le tue app principali scorrendo il dito sullo schermo o premendo un pulsante. - Errore: impossibile espandere la barra di stato. Questa azione utilizza funzionalità non incluse nelle API Android. Sfortunatamente, non sembra funzionare sul tuo dispositivo. - Applicazione nascosta. Puoi renderla nuovamente visibile dalle impostazioni. - µLauncher deve amministrare il dispositivo per poter bloccare lo schermo. - Abilita il blocco schermo + Puoi aprire le tue app facendo scorrere il dito sullo schermo o premendo un pulsante. Configura i gesti nella prossima slide. + Errore: impossibile espandere la barra di stato. Questa azione utilizza funzionalità non incluse nelle API Android pubbliche. Sfortunatamente, non sembra funzionare sul tuo dispositivo. + Applicazione nascosta. Puoi renderla nuovamente visibile nelle impostazioni. + µLauncher deve essere autorizzato come amministratore del dispositivo per bloccare lo schermo. + Abilita il blocco dello schermo Nessuna camera con torcia rilevata. Errore: impossibile accedere alla torcia. - Il servizio accessibilità per µLauncher non è attivo. Attivalo nelle impostazioni + Il servizio accessibilità per µLauncher non è attivo. Per favore attivalo nelle impostazioni Errore: impossibile bloccare lo schermo. (Se hai appena aggiornato l\'app, prova a disabilitare e riattivare il servizio accessibilità nelle impostazioni del telefono) - Errore: Il blocco schermo tramite accessibilità non è supportato su questo dispositivo. In alternativa usa il servizio amministratore dispositivo. - μLauncher + Errore: Il blocco schermo tramite accessibilità non è supportato su questo dispositivo. Per favore usa invece il servizio amministratore dispositivo. + µLauncher - blocco schermo Scegli come bloccare lo schermo Usa il servizio accessibilità - Usa Amministratore dispositivo + Usa l\'amministratore dispositivo Scegli un sistema di blocco dello schermo Scuro Chiaro @@ -149,22 +145,22 @@ Sfocato Solido Predefinito di sistema - Serif - Monospace - Serif monospace + Serif (con grazie) + Monospace (a larghezza fissa) + Serif monospace (a larghezza fissa con grazie) Applicazioni Applicazioni nascoste - Configura la lista applicazioni + Configurazione della lista applicazioni Predefinito - Soffuso - Imposta μLauncher come predefinito - Informazioni app - Tutorial di µLauncher - Ripristina le impostazioni - Stai per ripristinare tutte le impostazioni. Continuare? + Offuscato + Imposta μLauncher come predefinito per la schermata principale + Informazioni sulle applicazioni + Apri il tutorial del launcher + Ripristina le impostazioni predefinite + Stai per eliminare tutte le preferenze impostate. Vuoi continuare? Segnala un bug Contatta lo sviluppatore del fork - Unisciti alla chat di μLauncher + Partecipa alla chat di μLauncher Informativa sulla privacy Contatta lo sviluppatore originale Unisciti a noi su Discord! @@ -172,9 +168,9 @@ Applicazioni preferite Applicazioni nascoste Applicazioni - Altro + Altri Disinstalla - Informazioni app + Informazioni sull\'app Aggiungi ai preferiti Rimuovi dai preferiti Nascondi @@ -182,29 +178,29 @@ Rinomina Cerca Impostazioni μLauncher - Espandi pannello notifiche + Espandi il pannello notifiche Non fare niente - Blocca schermo - Torcia ON/OFF + Blocca lo schermo + Accendi/spegni la torcia Tutorial - 👋\n\nPrenditi qualche secondo per imparare ad usare questo launcher! + Prenditi qualche secondo per imparare ad usare questo launcher! Concetto - E\' software libero (licenza MIT)!\nAssicurati di controllare il repository! + L\'app è open source (sotto licenza MIT) e disponibile su GitHub! Visita il nostro archivio! Utilizzo La schermata principale contiene solo data e ora. Nessuna distrazione. Questa funzione richiede Android 6 o successivi. Rinomina %1$s Dinamico Colore - Scorri su con due dita + Due dita verso l\'alto Sono consapevole che questo concederà privilegi estesi a µLauncher. Accetto che µLauncher utilizzi il servizio di accessibilità per fornire funzionalità non correlate all\'accessibilità. Accetto che µLauncher non raccolga alcun dato. Nascondi le app in pausa - Blocca/Sblocca Spazio Privato - Questa funzione richiede Android 15 o successivi. + Attiva/Disattiva Blocco Spazio Privato + Questa funzionalità richiede Android 15 o successivi. Rosso - Alpha + Trasparente Blu Verde Colore @@ -212,79 +208,24 @@ Attiva Servizi di Accessibilità Sono consapevole che esistono altre opzioni (utilizzando i privilegi di amministratore del dispositivo o il pulsante di accensione). Attivazione dei Servizi di Accessibilità - Cerca sul web - Invio in ricerca app per avviare una ricerca web. + Cerca su internet + Premi invio durante la ricerca nell\'elenco delle app per avviare una ricerca su internet. Cerca (senza avvio automatico) Licenze Open Source Licenze Open Source Segnala un bug - Grazie per il tuo contributo al miglioramento di µLauncher!\nAggiungi le seguenti informazioni alla segnalazione del bug: + Grazie per aver contribuito a migliorare µLauncher!\nSi prega di aggiungere le seguenti informazioni alla segnalazione del bug: Copia negli appunti - Non segnalare le vulnerabilità di sicurezza pubblicamente su GitHub, ma usa invece: + Non segnalare pubblicamente le vulnerabilità di sicurezza su GitHub, ma utilizza invece: Annulla - Spazio per disabilitare temporaneamente. + Premi spazio per disabilitare temporaneamente questa funzionalità. Segnala una vulnerabilità di sicurezza Crea una segnalazione Spazio privato bloccato Spazio privato sbloccato Spazio privato non disponibile - µLauncher deve essere il launcher predefinito per poter accedere allo spazio privato. + µLauncher deve essere la schermata iniziale predefinita per accedere allo spazio privato. Impossibile aprire l\'URL: nessun browser trovato. - Nessuna applicazione trovata per gestire la ricerca. - privilegi estesi a μLauncher.
μLauncher userà questi privilegi solo per eseguire le seguenti azioni: -
    -
  • Blocco shermo
  • -
  • App recenti
  • -
- μLauncher non raccoglierà mai alcun dato. In particolare, μLauncher non utilizza il servizio di accessibilità per raccogliere dati.]]>
- Spazio privato - Spazio privato - Regola volume - Associa al gesto - Nascondi barra di stato - Nascondi barra di navigazione - Dona - App recenti - Tap + Su - Tap e scorri su - Tap + Giù - Tap e scorri verso il basso - Tap + Sinistra - Tap + Destra - Alto sx -> centro dx -> basso sx - Tap e scorri vesro sinistra - Tap e scorri verso destra - (Inverso)]]> - Basso sx -> centro dx -> alto sx - Alto dx -> centro sx -> basso dx - V - Alto sx -> centro basso -> alto dx - V (Inverso) - Alto dx -> centro basso -> alto sx - Λ - Basso sx -> centro alto -> basso dx - Basso dx -> centro alto -> basso sx - - - Λ (Inverso) - Musica: Riproduci / Pausa - Inverti la lista applicazioni - Azioni - Pulsante / gesto indietro - Indietro - Basso dx -> centro sx -> alto dx - Nascondi lo spazio privato dalla lista app - Avvia un altro launcher - Aggiungi scorciatoia - ]]> - Mostra in lista app - Blocca spazio privato - Sblocca spazio privato - Versione - Errore: impossibile abilitare il servizio di accessibilità. - Quando corrisponde una sola app, viene avviata automaticamente.\nPuoi disabilitare l\'avvio con uno spazio prima della query. - Tutte le app - Puoi cercare rapidamente tra tutte le app nella lista app.\n\nScorri su per la lista o associa ad un gesto diverso. - Errore: impossibile mostrare le app recenti. (Se hai appena aggiornato l\'app, prova a disabilitare e riabilitare il servizio di accessibilità dalle impostazioni del telefono) - Chiudi la tastiera durante lo scorrimento + Non è stata trovata un\'applicazione per gestire la ricerca. + privilegi più ampi a µLauncher.
µLauncher utilizzerà questi privilegi solo per bloccare lo schermo. µLauncher non raccoglierà mai alcun dato. In particolare, µLauncher non usa il servizio di accessibilità per raccogliere nessun dato.]]>
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml deleted file mode 100644 index 8da53d4..0000000 --- a/app/src/main/res/values-nl/strings.xml +++ /dev/null @@ -1,312 +0,0 @@ - - - Met twee vingers naar boven vegen - Bewerk widgets - Kleur - App-winkel niet gevonden - Uiterlijk - Kleurenschema - Standaard - Donker - Kies app - µLauncher als standaard instellen - App info - Bekijk de µLauncher handleiding - Broncode bekijken - Een probleem melden - Een probleem melden - Naar klembord kopiëren - Meld veiligheidsproblemen niet publiek op GitHub, gebruik daarvoor het volgende: - Rapport maken - Neem contact met de ontwikkelaar van de fork op - Word lid van de µLauncher chat - Instellingen terugzetten - Aan gebaar binden - In aaps-lijst tonen - 👋\n\nEen korte uitleg over hoe µLauncher functioneert. - Foutmelding: De toegankelijkheidsdienst kon niet ingeschakeld worden. - Tikken en dan naar rechts vegen - Druk tijdens het zoeken naar apps enter, om op het internet te zoeken. - Instellingen openen om voor dit gebaar een actie te kiezen - Gebruik gelokalizeerde datumformaat - Annuleren - Terug-knop of gebaar - Onderin naar links vegen - Rechts naar beneden vegen - In de hoek vegen - Handleiding - Met twee vingers naar beneder vegen - Apps installeren - Rooster - Hierdoor verwijdert u alle instellingen. Doorgaan? - Bedankt voor het helpen verbeteren van μLauncher!\nHet zou behulpzaam zijn om volgende informatie aan het rapport toe te voegen: - Shortcut toevoegen - Foutmelding: Er werd geen zaklamp gevonden. - Foutmelding: Geen toegang tot de zaklamp. - Door μLauncher in te stellen als toegankelijkheidsdienst kan het scherm worden vergrendeld en het menu met recente apps worden geopend. Merk op dat veel toestemingen vereist zijn. Wees hierdoor erg vorzichtig bij het geven van zulke machten aan een app. μLauncher zal de toegankelijkheidsdienst alleen gebruiken om de volgende acties uit te voeren wanneer de gebruiker daarom vraagt: * vergrendelscherm * recente apps openen μLauncher zal de toegankelijkheidsdienst nooit gebruiken om gegevens te verzamelen. U kunt de broncode controleren om er zeker van te zijn. Merk op dat het vergrendelen van het scherm ook kan worden bereikt door μLauncher apparaatbeheerdersrechten te geven, maar dat werkt echter niet met vingerafdruk- en gezichtsontgrendeling. - Methode voor vergrendeling kiezen - Er zijn twee methodes om het scherm te vergrendelen. - Helaas hebben beide nadelen:

- -

Apparaatbeheerder

- Werkt niet met ontgrendeling via vingerafdruk of gezichtsherkenning. - -
-
- -

Toegankelijkheidsdienst

- Vereist veel rechten. - μLauncher gebruikt deze rechten alleen om het scherm te vergrendelen. -
- (Echter moet u niet zomaar een willekeurige app zulke rechten geven, maar u kunt de Broncodebekijken.) -
- Op sommige apparaten wordt de pin niet meer gebruikt om data te vergrendelen na het aanzetten van een toegankelijkheidsdienst. - Dit kan nadehand heraktiveerd worden . - -



- U kunt uw keuze altijd in de instellingen veranderen. - ]]>
- uitgebreide privileges aan μLauncher.
μLauncher gebruikt deze privileges alleenmaar voor volgende doeleinde: -
    -
  • Vergrendelscherm
  • -
  • Recente apps
  • -
- μLauncher verzamelt nooit gegevens. Onder anderen, μLauncher gebruikt de toegankelijkheidsdienst om gegevens verzamelen.]]>
- Bewerk widget paneel - Licht - Dynamisch - Tekstschaduw - Achtergrond (zichtbaar in de instelligen en de app-lijst) - Doorzichtig - Dimmen - Vervagen - Eenkleurig - Lettertype - Systeemstandaard - Sans sarif - Serif - Monospace - Serif monospace - Eenkleurige aap-icoontjes - - Toetenbord in de apps-lijst automatisch openen - Apps - Tekst - Doneer - Privacybeleid - Contact opnemen met de oorspronkelijke ontwikkelaar - Wordt lid van onze Discord - Alle apps - Favorieten - Verstopte apps - Privébereik - App kiezen - Apps - Andere - Deïnstalleren - App info - Aan favorieten toevoegen - Uit favorieten verwijderen - Verstoppen - Zichtbaar maken - Hernoemen - Zoeken - Zoeken (geen snelstart) - µLauncher instellingen - Alle apps - Favoriete apps - Privéruimte - Privéruimte (ont)sluiten - Volume omhoog - Volume omlaag - Volume veranderen - Muziek: Volgende - Muziek: Vorige - Muziek: Afspelen / Pauzeren - Medling-scherm uitvouwen - Recente apps - Scherm vergrendelen - Zaklamp aan / uit - Andere launcher gebruiken - Concept - µLauncher biedt een minimalistische, efficiënte en afleidingsvrije omgeving.\n\nDe app is vrije software, het heeft geen advertenties en verzamelt geen data. - Versie - Gebruik - Het startscherm toont allen de datum en tijd. Geen afleiding. - Vaak gebruikte apps kunnen via gebaren of de volumeknoppen geopend worden. - Alle apps - In de applijst kan snel en eenvoudig naar apps gezocht worden.\n\nVeeg omhoog om de lijst te openen, of verander het gebaar in de settings. - Als maar één app bij het zoekbegrip past, wordt deze automatisch geopend.\nDoor een spatie voor het zoekbegrip intevoegen wordt dit onderdrukt. - Instellen - Wij hebben een paar standaard-apps voor u gekozen, u mag deze gerust veranderen: - De selectie kan op elk moment in de instellingen aangepast worden. - Starten! - Het kan beginnen!\n\nWij hopen dat deze app u helpt!\n\n- Finn (de ontwikelaar) en Josia (de ontwikkelaar van de fork µLauncher) - Starten - Instellingen - Meer opties - Foutmelding: Deze actie gebruikt een functie dat niet onderdeel is van de Android API, uw apparaat ondersteunt deze functie niet. - Deze functie is pas vanaf Android 6 beschikbaar. - Deze functie is pas vanaf Android 15 beschikbaar. - De app werd verstopt, het kan in de settings weer zichtbaar gemaakt worden. - Ongedaan maken - Snelle instellingen - Foutmelding: Kon geen recente apps tonen (probeer de toegankelijkheidsdienst in de apparaatinstellingen uit en weer aan te zetten) - µLauncher moet apparaatbeheerder zijn om het scherm te mogen vergrendelen. - Dit is nodig om het scherm te kunnen vergrendelen. - De actie \"scherm vergrendelen\" activeren - De toegankelijkheidsdienst voor µLauncher staat niet aan. Schakel het aan in de instellingen - Foutmelding: Kon het scherm niet vergrendelen (probeer de toegankelijkheidsdienst in de apparaatinstellingen uit en weer aan te zetten) - Privégedeelte vergrendelt - Privégedeelte ontgrendelt - Privégedeelte is niet bereikbaar - µLauncher moet als standaard-launcher ingesteld zijn om tot de privégegedeelte toegeang te krijgen. - Privégedeelte vergrendelen - Privégedeelte ontgrendelen - Foutmelding: Op dit apparaat kan het scherm via de toegankelijkheidsdienst niet vergrendelt worden. Maak µLauncher apparaatbeheerder hiervoor. - µLauncher - Methode voor vergrendeling kiezen - Gebruik toegankelijkheidsdienst - Gebruik apparaatadministratie - Kies een methode om het scherm te vergrendelen - %1$s hernoemen - Rood - Doorzichtigheid - Blauw - Groen - Kleur - Kleur kiezen - Ik ben me ervan bewust dat er andere opties bestaan (met beheerdersrechten of de aan/uit-knop). - Ik geef μLauncher toestemming om de toegankelijkheidservice te gebruiken om functionaliteit te bieden die niet gerelateerd is aan toegankelijkheid. - Ik ben me ervan bewust ik hierdoor uitgebreide privileges verleen aan μLauncher. - Ik geef μLauncher toestemming om geen gegevens te verzamelen. - Toegankelijkheidsservice activeren - Toegankelijkheidsservice activeren - Open Source licenties - Open Source licenties - Geen app gevonden om de zoekopdracht uit te voeren. - Kies widget - Verwijder - Configureren - Interactie inschakelen - Interactie uitschakelen - Klok - De standaard klok van µLauncher - Verwijder - Hernoem - Widget Paneel #%1$d - - Beinhoudt %d widget. - Beinhoudt %d widgets. - - Oké - Widget paneel - Selecteer een widget paneel - Maak een nieuwe widget paneel - Launcher > Beheer widget paneelen.]]> - Open widget paneel - Deze widget paneel bestaat niet meer. - Widgets - App kan niet geopend worden - App-instellingen aanpassen? - Instellingen - Acties - Launcher - Meta - Terug - Naar boven - Naar boven vegen - Tikken en dan naar boven vegen - Dubbel tikken en naar boven vegen - Naar beneden vegen - Naar beneden - Tikken en naar beneden - Tikken en naar beneden vegen - Tikken en boven - Dubbel naar beneden - Naar links - Naar links vegen - Tikken en links - Tikken en dan naar links vegen - Dubbel links - Met twee vingers naar links vegen - Naar rechts - Naar rechts vegen - Tikken en rechts - Dubbel rechts - Met twee vingers naar beneden vegen - Rechts (boven) - Bovenin naar rechts vegen - Rechts (beneden) - Onderin naar rechts vegen - Links (onder) - Links (boven) - Bovenin naar liniks vegen - Omhoog (links) - Links naar boven vegen - Omhoog (rechts) - Rechts naar boven vegen - Omlaag (links) - Links naar beneden vegen - Omlaag (rechts) - ]]> - Boven links -> midden rechts -> onder links - (Achteruit)]]> - Onder links -> midden rechts -> boven links - - Volume omhoog knop - Druk de \"volume omhoog\" knop - Volume omlaag knop - Druk de \"volume omlaag\" knop - Dubbelklik - Dubbeltik op een lege plek - Lange tik - Op een lege plek lang tikken - Datum - Op de datum tikken - Klok - Op de tijd tikken - Boven rechts -> midden links -> onder rechts - - Onder rechts -> midden links -> boven rechts - V - Boven links -> onder midden -> boven rechts - V (Achteruit) - Boven rechts -> onder rechts -> boven links - Λ - Onder links -> boven midden -> onder rechts - Λ (Achteruit) - Onder rechts -> boven midden -> boven links - Toon de tijd - Toon de datum - Toon sekondes - Spiegel datum en tijd - Achtergrond kiezen - Beeldscherm - Beeldscherm aanhouden - Statusbalk verbergen - Navigatiebalk verbergen - Scherm draaien - Functionaliteit - Dubbele veeg acties - Met twee vingers vegen - Hoek-acties - Kantbreedte - Start zoekresultaten - Spatie drukken om deze functie tijdelijk te onderdruken. - Op het internet zoeken - Beveiligingsprobleem melden - MIT licentie\nDe broncode is op GitHub te vinden. - Toetsenbord sluiten bij scrollen - Gevoeligheid - Verstopte apps - Toon apps die aan een gebaar gekoppeld zijn niet in de apps-lijst - Gepauzeerde apps verstoppen - Toon de privéruimte niet in de apps-lijst - Opmaat van de apps-lijst - Apps-lijst omkeren - Standaard - Niets doen - URL kan niet geopend worden: geen browser gevonden. -
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml deleted file mode 100644 index 3c2f290..0000000 --- a/app/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,266 +0,0 @@ - - - W prawo (Dół) - Przeciągnij w dół, po lewej krawędzi ekranu - - Otwórz ustawienia by wybrać akcje dla tego gestu - Ustawienia - Akcja - Przycisk cofnięcia / akcja cofnięcia - W górę - Przeciągnij w górę - Kliknij + W górę - Kliknij i przeciągnij w górę - Dwoma w górę - Przezeciągnij dwoma palcami w górę - W dół - Przeciągnij w dół - Kliknij + W dół - Dwoma w dół - Przeciągnij dwoma palcami w dół - W lewo - Przeciągnij w lewo - Kliknij + W lewo - Kliknij i przeciągnij w lewo - Dwoma w lewo - Przeciągnij dwoma palcami w lewo - W prawo - Kliknij + W prawo - Kliknij i przeciągnij w prawo - Dwoma w prawo - Przeciągnij dwoma palcami w prawo - W prawo (Góra) - Przeciągnij w prawo, w dolnej części ekranu - W lewo (Dół) - Przeciągnij w lewo, w dolnej części ekranu - W lewo (Góra) - W górę (Lewa krawędź) - Przeciągnij w górę, po lewej krawędzi ekranu - W górę (Prawa krawędź) - Przeciągnij w górę, po prawej krawędzi ekranu - W dół (Lewa krawędź) - W dół (Prawa krawędź) - Przeciągnij w dół, po prawej krawędzi ekranu - Górny lewy -> środek prawo -> dolny lewy - (Odwrotnie)]]> - ]]> - V - Λ - Nie można otworzyć aplikacji - Cofnij - Chcesz zmienić to ustawienie? - Przeciągnij w prawo - Dolny lewy -> środek prawo -> górny lewy - Kliknij i przeciągnij w dół - Przeciągnij w prawo, w górnej części ekranu - Przeciągnij w lewo, w górnej części ekranu - Zgłoś słabości zabezpieczeń - Wyszytkie aplikacje - Użytek - Przestrzeń prywatna jest niedostępna - Zamień date i zegar - Nie pokazuje aplikacji przypisanych do gestów w liście aplikacji - Dziękujemy za pomoc w udoskonaleniu μLauncher!\nProsze przemyśl dodanie podany informacji to twojego zgłoszenia błędu: - Dołącz do nas na discordzie! - Muzyka: Poprzednie - Wygląd - Domyślna systemowa - Serif - Akcje podwójnego przeciągnięcia - Launcher - Meta - Prawy górny -> środek lewo -> prawy dolnym - - Prawy dolnym -> środek lewo -> prawy górny - V (Odwrotnie) - Lewy dolny -> środkowy górny -> prawy dolny - Λ (Odwrotnie) - Przycisk podgłośnienia - Naciśnij przycisk podgłośnienia - Przycisk przyciszenia - Naciśnij przycisk przyciszenia - Prawy górny -> środkowy górny -> lewy górny - Dwuklik - Naciśnij dwukrotnie w pustym miejscu - Wydłużone kliknięcie - Data - Kliknij na date - Zegar - Zarządzaj widżetami - Zarządzaj panelem widżetów - Wybierz aplikacje - Zainstaluj aplikacje - Kliknij na zegar - Sklep nie został zanleziony - Kolor motywu - Domyślne - Ciemny - Jasny - Dynamiczny - Cień tekstu - Tło (lista aplikacji i ustawienia) - Przeźroczysty - Przygaszony - Rozmazanie - Jednolity - Czcionką - Monospace - Sans serif - Serif monospace - Monochromatyczne ikony aplikacji - - Kolor - Pokazuj date - Pokazuj sekundy - Wybierz tapete - Wyświetlanie - Zatrzymaj na ekranie - Schowaj pasek statusów - Showaj pasek nawigacji - Obracają ekran - Funkcjonalność - Przeciągnij dwoma palcami - Przeciąganie na krawedziach - Przeciągnij koło krawędź ekranu - Rozmiary krawędź - Automatycznie uruchamiaj wyszukiwanie - Wyszukuje w sieci - Kliknij enter, wyszukując w liście aplikacji, by wyszukać w internecie. - Pokazuje klawiaturę do wyszukiwania - Zamknij klawiaturę podczas przewijania - Czułość - Aplikacje - Ukryte aplikacje - Ukryj zatrzymane aplikacje - Ukruj przestrzeń prywatną z listy aplikacji - Układ listy aplikacji - Odwruć liste aplikacji - Domyślny - Tekst - Siatka - Informacje aplikacji - Zobacz samouczek µLauncher - Zresetuj ustawienia - Odrzucisz wszystkie swoje preferencje. Czy chcesz kontynuować? - Zobacz kod zrudłowy - Zgłoś błąd - Zgłoś błąd - Skopiuj do schowka - Proszę nie zgłaszaj słabości zabezpieczeń publicznie na GitHub, użyj natomiast podanego linku: - Utwórz zgłoszenie - Skontaktuj się z deweloperem forku - Dołącz do czatu μLauncher - Wesprzyj - Polityka prywatność - Skontaktuj się z deweloperem orginału - Lista aplikacji - Ulubione aplikacje - Ukryte aplikacje - Przestrzeń prywatna - Wybierz aplikacje - Aplikacje - Inne - Odinstaluj - Informacje aplikacji - Usuń z ulubionych - Ukryj - Pokaż - Zmień nazwe - Wyszukaj - Wyszukaj (wyłoczono automatyczne uruchomienie) - Ustawienia μLauncher - Ulubione aplikacje - Przestrzeń prywatna - Przełącz zamek prywatnej przestrzeni - Podgłośnij - Przycisz - Dostosuj głośność - Muzyka: Następnym - Muzyka: Wznów / Wstrzymaj - Rozwiń panel powiadomień - Ostatnio używane aplikacje - Nie rób nic - Ekran blokady - Przełącz latarke - Uruchomiono inny ekran główny - Dodaj skrut - Przypisz do gestu - Pokaż w liście aplikacji - Samouczek - 👋\n\nPoświeć kilka chwil, aby nauczyć się jak używać togo launchera! - Koncept - Wersja - Wszystkie aplikacje - Przygotowanie - Gratulacje! - Start - Ustawienia - Więcej opcji - Cofnij - Przestrzeń prywatna odblokowana - Zablokuj przestrzeń prywatną - Odblokuj przestrzeń prywatną - μLauncher - Wybierz metodę zablokowywania - Wybierz metodę blokowania ekranu - Zmień nazwe %1$s - Czerwony - Przezroczystości - Niebieski - Zielony - Wybierz kolor - Anuluj - Nie znaleziono żadnej aplikacji do wyszukania w sieci - Pokazuj zegar - Użyj lokalnego formatu daty - Kliknij dłużej w pustym miejscu - Lewy górny -> środkowy dolny -> prawy górny - Prawy górny -> środkowy dolny -> lewy górny - Kliknij spacje, by tymczasowo wyłączyć tą funkcje. - Szybkie ustawienia - Przestrzeń prywatna zablokowana - Ustaw μLauncher jako ekran główny - Kolor - Dodaj do ulubionych - Jest to darmowe oprogramowanie (na licencji MIT)!\nZachęcamy do dowiedzenia naszego repozytorium! - μLauncher jest projektowany z uwagą na minimalizm, efektywności i brak rozproszeń. \n\nNie zawiera reklam i niezbiera twojich danych. - Twój ekran główny zawiera lokalną datę i czas. Żadnych dystrykcji. - Możesz uruchomić swoje najważniejsze aplikacje za pomocą gestów i użyciem przycisków. - Możesz szybko wyszukiwać aplikacje poprzez liste aplikacji.\n\nPrzeciągnij do góry aby ją otworzyć, lub przypisz ją do innego gestu. - Gdy tylko jedna aplikacja pasuje do twojego wyszukiwania, uruchomi się automatycznie.\nTa opcja może być wyłączona, przez wpisanie spacji przed wyszukaniem. - Wybraliśmy pare domyślnych aplikacji dla ciebie. Możesz zmienić je teraz jeśli chcesz: - Albo zmień je później. - Ta funkcja wymaga wersji 6 lub wyższej Androida. - Ta funkcja wymaga wersji 15 lub wyższej Androida. - Aplikacja schowana. Możesz przywrócić jej widoczność spowrotem w ustawieniwch. - Error: Brak dostępu do latarki. - Aktywuj akcje zablokowana ekranu - Zyrażam zgodę by, μLauncher nie zbierał żadnych moich danych. - Niemożna otworzyć adresu URL: nie znaleziono przeglądarki - Wybierz widrzet - Usuń - Skonfiguruj - Zegar - Aktywuje interakcje - Dezaktywuj interakcje - Usuń - Domuślny zegar μLauncher - Zmień nazwe - Panel widrzetów #%1$d - - Zawiera %d widrzet. - Zawiera %d widrzety. - Zawiera %d widrzetów. - Zawiera %d widrzetów. - - Licencja Open Source - Licencja Open Source - Okej - Panel widrzetów - Wybierz panel widrzetów - Stwórz nowy panel widrzetów - Otwórz panel widrzetów - Widrzety - Ten panle widrzetów jusz nie istnieje. - Nie wykryto aparatu z latarkom. - diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 3efb611..fcdd9e8 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -102,7 +102,7 @@ Diminuir volume Música: Próximo Música: Anterior - Não fazer nada + Não faça nada Add Shortcut @@ -391,33 +387,5 @@ Open Source Licenses No app found to handle search. Can\'t open URL: no browser found. - Choose Widget - - Remove - Configure - Enable Interaction - Disable Interaction - - - Clock - The default clock of μLauncher - Delete - Rename - - Widget Panel #%1$d - - Contains %d widget. - Contains %d widgets. - - - - Ok - Widget Panels - Select a Widget Panel - Create new widget panel - Launcher > Manage Widget Panels.]]> - Open Widget Panel - This widget panel no longer exists. - Widgets diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c5b7252..20ccb67 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -66,12 +66,12 @@ 0 2 - + - + - - - - - diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 0ee7c17..6ef5d07 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -3,10 +3,10 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> - + - - - - - ACTIONS. - - -## Available Gestures - -### Swipes - -- Basic swipes: Swipe up, down, left, or right -- Double swipes: Swipe up, down, left, or right with two fingers -- Edge swipes: - - Swipe up or down on the left or right edge - - Swipe left or right on the top or bottom edge - - The size of the edges is configurable in settings. - For a swipe to be detected as an edge swipe, the finger must not leave the respective edge region while swiping. - -### Taps - -- Tap on date or time -- Double tap -- Long click - -### Tap-then-Swipes - -- Tap then swipe up, down, left, or right - - To execute these gesture consistently, it is helpful to think of them as double taps, - where the finger stays on the screen after the second tap and then does a swipe. - The swipe must start very shortly after the tap ended. - -### Complex Gestures - -- Draw <, >, V, or Λ -- Draw <, >, V, or Λ in reverse direction - -### Hardware Buttons as Gestures - -- Back button (or back gesture if gesture navigation is enabled) -- Volume buttons - -*** - -## Available Actions - -To any of the available gestures, one of the following actions can be bound: - -- Launch an app (or a pinned shortcut) -- Open a widget panel. - Widget panels can hold widgets that are not needed on the home screen itself. - They can be created and managed in µLauncher Settings > Manage Widget Panels -- Open a list of all, favorite, or private apps (hidden apps are excluded). - Actions related to private space are only shown if private space is set up on the device. - µLauncher's settings can be accessed from those lists. - If private space is set up, an icon to (un)lock it is shown on the top right. -- Open µLauncher's settings -- Toggle private space lock -- Lock the screen: This allows to lock the screen. - There are two mechanisms by which the screen can be locked, accessibility service and device admin. -- Toggle the flashlight -- Raise, lower or adjust volume -- Play or pause media playback -- Skip to previous or next audio track -- Open notifications panel: Might be useful if the top of your screen is broken. -- Open quick settings panel: Why swipe down twice? -- Open [recent apps](https://developer.android.com/guide/components/activities/recents): Requires accessibility service. Can be used as a workaround for a Android bug. -- Launch another home screen: Allows using another installed home screen temporarily. -- Do nothing: Just prevents showing the message saying that no action is bound to this gesture. diff --git a/docs/build.md b/docs/build.md index 1ffc338..75921f9 100644 --- a/docs/build.md +++ b/docs/build.md @@ -1,11 +1,11 @@ -# Building from Source +# Building µLauncher ## Using the command line -Install JDK 17 and the Android SDK. +Install JDK 17 and the Android Sdk. Make sure that `JAVA_HOME` and `ANDROID_HOME` are set correctly. -```bash +``` git clone https://github.com/jrpie/Launcher cd Launcher @@ -15,8 +15,7 @@ cd Launcher This will create an apk file at `app/build/outputs/apk/default/release/app-default-release-unsigned.apk`. Note that you need to sign it: - -```bash +``` apksigner sign --ks "$YOUR_KEYSTORE" \ --ks-key-alias "$YOUR_ALIAS" \ --ks-pass="pass:$YOUR_PASSWORD" \ @@ -29,17 +28,13 @@ apksigner sign --ks "$YOUR_KEYSTORE" \ app-default-release-unsigned.apk ``` + See [this guide](https://developer.android.com/build/building-cmdline) for further instructions. -## Using Android Studio +## Using Android Studio Install [Android Studio](https://developer.android.com/studio), import this project and build it. See [this guide](https://developer.android.com/studio/run) -for further instructions. How to - -## CI Pipeline - -The [CI pipeline](https://github.com/jrpie/Launcher/actions) automatically creates debug builds. -> Note: These builds are *not* signed. They are in built in debug mode and only suitable for testing. +for further instructions. diff --git a/docs/contributing.md b/docs/contributing.md deleted file mode 100644 index 8e9de53..0000000 --- a/docs/contributing.md +++ /dev/null @@ -1,24 +0,0 @@ -# Contributing - -There are several ways to contribute to this app: -* You can add or improve [translations][toolate]. -
translation status -* If you found a bug or have an idea for a new feature you can [join the chat][chat] or open an [issue][issues]. - - > Please note that I work on this project in my free time. Thus I might not respond immediately and not all ideas will be implemented. - -* You can implement a new feature yourself: - - Create a [fork][fork] of this repository. - - Create a new branch named `feature/` or `fix/` and commit your changes. - - Open a new pull request. - - -See [build.md](build.md) for instructions how to build this project. -The [CI pipeline](https://github.com/jrpie/Launcher/actions) automatically creates debug builds. - - ---- - [fork]: https://github.com/jrpie/Launcher/fork/ - [issues]: https://github.com/jrpie/Launcher/issues/ - [chat]: https://s.jrpie.de/launcher-chat - [toolate]: https://toolate.othing.xyz/projects/jrpie-launcher/ diff --git a/docs/home.md b/docs/home.md deleted file mode 100644 index 9812e93..0000000 --- a/docs/home.md +++ /dev/null @@ -1,43 +0,0 @@ -# Welcome to the μLauncher Documentation - -## What is μLauncher? - -µLauncher is an *minimal* and *distraction-free* Android home screen that lets you launch apps using [swipe gestures and button presses](/actions-and-gestured.md). - -This project is a fork of [finnmglas's app Launcher](https://github.com/finnmglas/Launcher). An incomplete list of changes can be found [here](https://github.com/wassupluke/Launcher/blob/master/docs/launcher.md). - -## Where can I get μLauncher? - -[![Get it on F-Droid](https://fdroid.gitlab.io/artwork/badge/get-it-on.png)](https://f-droid.org/packages/de.jrpie.android.launcher/) - -[![Get it on Accrescent](https://accrescent.app/badges/get-it-on.png)](https://accrescent.app/app/de.jrpie.android.launcher.accrescent) - -[![Get it on Obtainium](https://raw.githubusercontent.com/ImranR98/Obtainium/b1c8ac6f2ab08497189721a788a5763e28ff64cd/assets/graphics/badge_obtainium.png)](https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/{%22id%22:%22de.jrpie.android.launcher%22,%22url%22:%22https://github.com/jrpie/Launcher%22,%22author%22:%22jrpie%22,%22name%22:%22%c2%b5Launcher%22,%22additionalSettings%22:%22{\%22apkFilterRegEx\%22:\%22release\%22,\%22invertAPKFilter\%22:false,\%22about\%22:\%22%c2%b5Launcher%20is%20a%20minimal%20home%20screen.\%22}%22}) - -[![Get it on GitHub](https://raw.githubusercontent.com/NeoApplications/Neo-Backup/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png)](https://github.com/jrpie/launcher/releases/latest) - -> You can also [get it on Google Play](https://play.google.com/store/apps/details?id=de.jrpie.android.launcher), but this is not recommend. - - -## How can I contribute? - -See [docs/contribute](/contribute.md) - -## Screenshots - -![μLauncher Home Screen screenshot](https://github.com/jrpie/launcher/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg) - -![μLauncher Settings screenshot](https://github.com/jrpie/launcher/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg) - -![μLauncher All Apps list view with icons screenshot](https://github.com/jrpie/launcher/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg) - -![μLauncher Favorite Apps list view with icons screenshot](https://github.com/jrpie/launcher/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg) - -![μLauncher Choose App to bind to gesture screenshot](https://github.com/jrpie/launcher/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/5.jpg) - -![μLauncher App options card from list view with icons screenshot](https://github.com/jrpie/launcher/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/7.jpg -) - -![μLauncher All Apps list view without icons screenshot](https://github.com/jrpie/launcher/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/8.jpg) - - diff --git a/docs/changes-fork.md b/docs/launcher.md similarity index 70% rename from docs/changes-fork.md rename to docs/launcher.md index 8efc965..cb290a0 100644 --- a/docs/changes-fork.md +++ b/docs/launcher.md @@ -1,45 +1,40 @@ -# Notable changes compared to Finn's Launcher +# Notable changes compared to [Finn's Launcher][original-repo]: -µLauncher is a fork of [finnmglas's app Launcher](https://github.com/finnmglas/Launcher). +µLauncher is a fork of [finnmglas's app Launcher][original-repo]. Here is an incomplete list of changes: -- Additional gestures: - - Back - - V,Λ,<,> - - Edge gestures: There is a setting to allow distinguishing swiping at the edges of the screen from swiping in the center. +- Additional gestures: + - Back + - V,Λ,<,> + - Edge gestures: There is a setting to allow distinguishing swiping at the edges of the screen from swiping in the center. - Compatible with [work profile](https://www.android.com/enterprise/work-profile/), so apps like [Shelter](https://gitea.angry.im/PeterCxy/Shelter) can be used. - Compatible with [private space](https://source.android.com/docs/security/features/private-space) -- Support for [app widgets](https://developer.android.com/develop/ui/views/appwidgets/overview) -- Support for [pinned shortcuts](https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts) - Option to rename apps - Option to hide apps - Favorite apps - New actions: - Toggle Torch - Lock screen - - Open a widget panel - The home button now works as expected. - Improved gesture detection. -## Visual - +### Visual - This app uses the system wallpaper instead of a custom solution. - The font has been changed to [Hack][hack-font], other fonts can be selected. - Font Awesome Icons were replaced by Material icons. - The gear button on the home screen was removed. A smaller button is show at the top right when necessary. -## Search +### Search - The search algorithm was modified to prefer matches at the beginning of the app name, i.e. when searching for `"te"`, `"termux"` is sorted before `"notes"`. - The search bar was moved to the bottom of the screen. -## Technical - +### Technical - Improved gesture detection. - Different apps set as default. - Package name was changed to `de.jrpie.android.launcher` to avoid clashing with the original app. @@ -47,10 +42,9 @@ The decision to create a hard fork was made two years later.--> - Fixed some bugs - Some refactoring + The complete list of changes can be viewed [here](https://github.com/jrpie/launcher/compare/340ee731...master). --- - -\[original-repo\]: [https://github.com/finnmglas/Launcher](https://github.com/finnmglas/Launcher) - -\[hack-font\]: [https://sourcefoundry.org/hack/](https://sourcefoundry.org/hack/) + [original-repo]: https://github.com/finnmglas/Launcher + [hack-font]: https://sourcefoundry.org/hack/ diff --git a/docs/profiles.md b/docs/profiles.md deleted file mode 100644 index d9eaf52..0000000 --- a/docs/profiles.md +++ /dev/null @@ -1,21 +0,0 @@ -# Work Profile - -µLauncher is compatible with [work profile](https://www.android.com/enterprise/work-profile/), so apps like [Shelter](https://gitea.angry.im/PeterCxy/Shelter) can be used. -Apps from the work profile are shown in the usual app list. - - -# Private Space - -µLauncher is compatible with [private space](https://source.android.com/docs/security/features/private-space). - - -The private space can be (un)locked by a dedicated action. - -It is configurable whether apps from private space are - -1. shown in the usual app list - (in this case, (un)locking is accessible through a lock icon on the top right of the app drawer) - or -2. only shown in a separate list. - - diff --git a/docs/settings.md b/docs/settings.md deleted file mode 100644 index f033f62..0000000 --- a/docs/settings.md +++ /dev/null @@ -1,235 +0,0 @@ -# Launcher Settings - -Tweaks and customizations can be made from within the Launcher Settings page. - -These settings let you change wallpapers, change colors and fonts, enable monochrome app icons, change the app drawer layout, and much more. - -In the following documentation, 'app drawer' will be used to refer to the 'All Apps', 'Favorite Apps' and 'Private Space' views. - -## Appearance - -> ### Choose a wallpaper - -This triggers Android's mechanism to change the wallpaper using a photos app, file explorer, or native wallpaper setting app. -µLauncher uses the system-wide wallpaper, i.e. this change also affects other launchers. - -> ### Font (in-app font) - -Set the font used within the app settings. This setting does not affect the date/time home screen font. - -**type:** `dropdown` - -**options:** `Hack`,`System default`,`Sans serif`,`Serif`,`Monospace`,`Serif monospace` - -> ### Text Shadow - -**type:** `toggle` - -> ### Background (app list and setting) - -**type:** `dropdown` - -**type:** `Transparent`,`Dim`,`Blur`,`Solid` - -> ### Monochrome app icons - -Remove coloring from all app icons. Can help decrease visual stimulus when enabled. - -**type:** `toggle` - -## Date & Time - -> ### Font (home screen) - -Set the home screen font for date and time. This setting does not affect the in-app font. - -**type:** `dropdown` - -**options:** `Hack`,`System default`,`Sans serif`,`Serif`,`Monospace`,`Serif monospace` - -> ### Color [`[bug]`](https://github.com/jrpie/launcher/issues/151) - -Set the color for the home screen date and time. - -Accepts a HEX color code (consisting of a '#' followed by three sets of two alphanumeric (letters and numbers) characters. A fourth set of two alphanumeric characters may be added to set the transparency of the color. - -[Color wheel picker](https://rgbacolorpicker.com/color-wheel-picker) - -**type:** `HEX`,`RGBA` - -> ### Use localized date format - -Adapt the display of dates and times to the specific conventions of a particular locale or region. Different locales use different date orders (e.g., MM/DD/YYYY in the US, DD/MM/YYYY in Europe). - -**type:** `toggle` - -> ### Show time - -Show the current time on the home screen. - -**type:** `toggle` - -> ### Show seconds - -Show the current time down to the second on the home screen. - -**type:** `toggle` - -> ### Show date - -Show the current date on the home screen. - -**type:** `toggle` - -> ### Flip date and time - -Place the current time above the current date on the home screen. - -**type:** `toggle` - -## Functionality - -> ### Launch search results - -Launches any app that matches user keyboard input when no other apps match. - -As you type inside the app drawer, the app narrows down the list of apps shown based on the app title matching your text input. -With the 'launch search results' setting, once only one matching app remains, it is launched immediately. -Usually it suffices to type two or three characters the single out the desired app. - -This feature becomes more powerful when combined with [renaming](#additional-settings) apps, effectively letting you define custom app names that could be considered 'aliases' or shortcuts. -For instance, if you want the keyboard input `gh` to open your `GitHub` app, you could rename `GitHub` to `GitHub gh`, `gh GitHub`, or simply `gh`. -Assuming no other installed apps have the `gh` combination of letters in them, opening the app drawer and typing `gh` would immediately launch your `GitHub` app. - -Press space to temporarily disable this feature and allow text entry without prematurely launching an app. Useful when combined with the [Search the web](#search-the-web) feature. - -**type:** `toggle` - -> ### Search the web - -Press return/enter while searching the app list to launch a web search. - -**type:** `toggle` - -> ### Start keyboard for search - -Automatically open the keyboard when the app drawer is opened. - -**type:** `toggle` - -> ### Double swipe gestures - -Enable double swipe (two finger) gestures in launcher settings. Does not erase gesture bindings if accidentally turned off. - -**type:** `toggle` - -> ### Edge swipe gestures - -Enable edge swipe (near edges of screen) gestures in launcher settings. Does not erase gesture bindings if accidentally turned off. - -**type:** `toggle` - -> ### Edge width - -Change how large a margin is used for detecting edge gestures. Shows the edge margin preview when using the slider. - -**type:** `slider` - -> ### Choose method for locking the screen - -There are two methods to lock the screen and unfortunately both have downsides. - -1. **`Device Admin`** - - - Doesn't work with unlocking by fingerprint or face recognition. - -2. **`Accessibility Service`** - - - Requires excessive privileges. - - μLauncher will use those privileges *only* for locking the screen. - - As a rule of thumb, it is [not recommended](https://android.stackexchange.com/questions/248171/is-it-safe-to-give-accessibility-permission-to-an-app) to grant access to accessibility services on a random app. Always review the [source code](https://github.com/jrpie/Launcher) before granting accessibility permissions so you familiarize yourself with what the code might do. - - On some devices, the start-up PIN will no longer be used for encrypting data after activating an accessibility service. - - This can be [reactivated](https://issuetracker.google.com/issues/37010136#comment36) afterwards. - - **type:** `text buttons` - - **options:** `USE DEVICE ADMIN`,`USE ACCESSIBILITY SERVICE` - -## Apps - -> ### Hidden apps - -Open an app drawer containing only hidden apps. - -> ### Don't show apps that are bound to a gesture in the app list - -Remove certain apps from the app drawer if they are already accessible via a gesture. - -Reduces redundancy and tidies up app drawer. - -**type:** `toggle` - -> ### Hide paused apps - -Remove paused apps from the app drawer. -For example an app belonging to the work profile is paused when the work profile is inactive. - -**type:** `toggle` - -> ### Hide private space from app list - -Remove private space from app drawer. - -**type:** `toggle` - -> ### Layout of app list - -Changes how the apps are displayed when accessing the app drawer. - -- `Default`: All apps in the drawer will show in a vertically-scrolled list with their app icon and title. -- `Text`: Removes the app icons, shows only app titles in the drawer as a vertically-scrolled list. - Work profile and private space apps are distinguished by a different label instead of a badge. -- `Grid`: Shows apps with their app icon and title in a grid layout. - -**type:** `dropdown` - -**options:** `Default`,`Text`,`Grid` - -> ### Reverse the app list - -Enable reverse alphabetical sorting of apps in the app drawer. -Useful for keeping apps within easier reach from the keyboard. - -**type:** `toggle` - -## Display - -> ### Rotate screen - -**type:** `toggle` - -> ### Keep screen on - -**type:** `toggle` - -> ### Hide status bar - -Remove the top status bar from the home screen. - -**type:** `toggle` - -> ### Hide navigation bar - -Remove the navigation bar from the home screen. Enabling this setting may make it difficult to use the device if gestures are not setup properly. - -**type:** `toggle` - -## Additional Settings - -> ### App Drawer Long Press on App - -Access additional per-app details and settings. To use, open the app drawer and long press on any app. - -**type:** `dropdown` - -**options:** `App Info`,`Add to favorites`,`Hide`,`Rename`,`Uninstall` diff --git a/fastlane/metadata/android/en-US/changelogs/45.txt b/fastlane/metadata/android/en-US/changelogs/45.txt deleted file mode 100644 index 6d20b8d..0000000 --- a/fastlane/metadata/android/en-US/changelogs/45.txt +++ /dev/null @@ -1,10 +0,0 @@ -* support for app widgets -* widget panels - -* added documentation (thank you, wassupluke!) -* added Dutch translation (thank you, renar and Sven van de Lagemaat!) -* added Polish translation (thank you, AsLoLoks!) -* improved Arabic translation (thank you, abdelbasset jabrane!) -* improved Chinese translation (thank you, monkeyotw!) -* improved Italian translation (thank you, Vladi69 and Nicola Bortoletto!) -* improved Portuguese translation (thank you, "Vossa Excelencia"!) diff --git a/fastlane/metadata/android/it-IT/changelogs/26.txt b/fastlane/metadata/android/it-IT/changelogs/26.txt deleted file mode 100644 index d43e091..0000000 --- a/fastlane/metadata/android/it-IT/changelogs/26.txt +++ /dev/null @@ -1 +0,0 @@ -bugfix diff --git a/fastlane/metadata/android/nl-NL/full_description.txt b/fastlane/metadata/android/nl-NL/full_description.txt deleted file mode 100644 index 3040dfd..0000000 --- a/fastlane/metadata/android/nl-NL/full_description.txt +++ /dev/null @@ -1,4 +0,0 @@ -µLauncher is een thuisscherm die je andere apps laat starten met gebruik van veeg gebaren en knoppen indrukken. -Het is minimalistisch, efficiënt en vrij van afleiding. - -Je thuisscherm laat alleen de datum, tijd en achtergrond zien. diff --git a/fastlane/metadata/android/nl-NL/short_description.txt b/fastlane/metadata/android/nl-NL/short_description.txt deleted file mode 100644 index 43e1dbf..0000000 --- a/fastlane/metadata/android/nl-NL/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Een afleidingsvrije, minimalistisch thuisscherm voor Android. diff --git a/fastlane/metadata/android/nl-NL/title.txt b/fastlane/metadata/android/nl-NL/title.txt deleted file mode 100644 index 4305604..0000000 --- a/fastlane/metadata/android/nl-NL/title.txt +++ /dev/null @@ -1 +0,0 @@ -µLauncher diff --git a/fastlane/metadata/android/pl-PL/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt deleted file mode 100644 index b018a99..0000000 --- a/fastlane/metadata/android/pl-PL/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Wolnym od dystrakcji, minimalistyczny ekran główny dla Androida. diff --git a/fastlane/metadata/android/pl-PL/title.txt b/fastlane/metadata/android/pl-PL/title.txt deleted file mode 100644 index 4305604..0000000 --- a/fastlane/metadata/android/pl-PL/title.txt +++ /dev/null @@ -1 +0,0 @@ -µLauncher