1
0
Fork 0
mirror of https://github.com/jrpie/Launcher.git synced 2025-04-27 22:30:52 +02:00

Compare commits

..

30 commits

Author SHA1 Message Date
a4fcdf60c7
add widget panels (see ) 2025-04-26 21:52:21 +02:00
ffaaba7abb
fix 2025-04-25 11:25:00 +02:00
e7a06c443d
add support for app widgets (see ) 2025-04-24 14:37:44 +02:00
077bd1ce44
add option to hide keyboard when scrolling (cf. ) 2025-04-23 01:51:58 +02:00
22633bdac3
try to fix 2025-04-15 19:24:23 +02:00
4f795289d5
improve English translation 2025-04-15 18:55:13 +02:00
2774b74d9d
0.1.4 2025-04-15 18:38:00 +02:00
3d49ec16a7
Merge pull request from toolatebot/weblate-jrpie-launcher-launcher
Translations update from Toolate
2025-04-13 16:27:29 +02:00
letterhaven
a0b2417363 Translated using Weblate (Arabic)
Currently translated at 99.6% (257 of 258 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/ar/
2025-04-13 14:07:19 +00:00
letterhaven
20a01e9f03 Added translation using Weblate (Arabic) 2025-04-13 14:07:19 +00:00
Lukas Hamm
24250ad345 Translated using Weblate (Lithuanian)
Currently translated at 5.4% (14 of 258 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/lt/
2025-04-13 14:07:18 +00:00
Lukas Hamm
7cce425339 Added translation using Weblate (Lithuanian) 2025-04-13 14:07:18 +00:00
class0068
0877ca6772 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 14.2% (3 of 21 strings)

Translation: jrpie-Launcher/metadata
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/metadata/zh_Hans/
2025-04-13 14:07:18 +00:00
class0068
03a9833b51 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (258 of 258 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/zh_Hans/
2025-04-13 14:07:18 +00:00
Vossa Excelencia
ce65741717 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (258 of 258 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/pt_BR/
2025-04-13 14:07:18 +00:00
class0068
c085087e1e Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (257 of 257 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/zh_Hans/
2025-04-13 14:07:18 +00:00
class0068
cbd23159da Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 98.8% (254 of 257 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/zh_Hans/
2025-04-13 14:07:18 +00:00
Vossa Excelencia
940e5785dc Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (254 of 254 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/pt_BR/
2025-04-13 14:07:18 +00:00
class0068
14ffbd1f6c Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (254 of 254 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/zh_Hans/
2025-04-13 14:07:18 +00:00
Vossa Excelencia
bfc84b57ca Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (254 of 254 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/pt_BR/
2025-04-13 14:07:18 +00:00
T
8b1963f3e1 Translated using Weblate (Spanish)
Currently translated at 98.0% (249 of 254 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/es/
2025-04-13 14:07:18 +00:00
toolatebot
4f801427a4 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/
2025-04-13 14:07:18 +00:00
class0068
8a487eb4c7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (254 of 254 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/zh_Hans/
2025-04-13 14:07:18 +00:00
class0068
e6dd2634ae Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (254 of 254 strings)

Translation: jrpie-Launcher/Launcher
Translate-URL: https://toolate.othing.xyz/projects/jrpie-launcher/launcher/zh_Hans/
2025-04-13 14:07:18 +00:00
0441b3fd3d
set max width for choose app button; change label from scegliere l'applicazione to scegliere in Italian 2025-04-13 14:54:11 +02:00
e7c1d28576
upgrade AGP 2025-04-13 14:40:57 +02:00
653d16b269
new action: launch other launchers 2025-03-29 21:09:15 +01:00
5d695ec0ea
fix 2025-03-29 18:45:53 +01:00
b4608ef153
add new action: show recent apps 2025-03-24 13:21:58 +01:00
8e140e2e69
rename tab "Apps" to "Actions" and "Volume Up/Down" to "Volume Up/Down Key" 2025-03-20 16:23:01 +01:00
79 changed files with 3306 additions and 343 deletions
.scripts
app
build.gradle
src/main
AndroidManifest.xml
java/de/jrpie/android/launcher
res
build.gradle
fastlane/metadata/android

View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
export JAVA_HOME="/usr/lib/jvm/java-23-openjdk/" export JAVA_HOME="/usr/lib/jvm/java-21-openjdk/"
OUTPUT_DIR="$HOME/launcher-release" OUTPUT_DIR="$HOME/launcher-release"
BUILD_TOOLS_DIR="$HOME/Android/Sdk/build-tools/35.0.0" BUILD_TOOLS_DIR="$HOME/Android/Sdk/build-tools/35.0.0"
KEYSTORE="$HOME/data/keys/launcher_jrpie.jks" KEYSTORE="$HOME/data/keys/launcher_jrpie.jks"

View file

@ -23,8 +23,8 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 35 targetSdkVersion 35
compileSdk 35 compileSdk 35
versionCode 43 versionCode 44
versionName "0.1.3" versionName "0.1.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -106,6 +106,7 @@ dependencies {
implementation 'com.google.android.material:material:1.12.0' implementation 'com.google.android.material:material:1.12.0'
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
implementation "eu.jonahbauer:android-preference-annotations:1.1.2" 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 "eu.jonahbauer:android-preference-annotations:1.1.2"
annotationProcessor "com.android.databinding:compiler:$android_plugin_version" annotationProcessor "com.android.databinding:compiler:$android_plugin_version"
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'

View file

@ -8,6 +8,7 @@
tools:ignore="QueryAllPackagesPermission" /> tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES" /> <uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
<application <application
android:name=".Application" android:name=".Application"
@ -19,6 +20,19 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/launcherBaseTheme" android:theme="@style/launcherBaseTheme"
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<activity
android:name=".ui.widgets.manage.ManageWidgetPanelsActivity"
android:exported="false" />
<activity
android:name=".ui.widgets.WidgetPanelActivity"
android:exported="false" />
<activity
android:name=".ui.widgets.manage.ManageWidgetsActivity"
android:exported="false"
android:theme="@style/launcherHomeTheme" />
<activity
android:name=".ui.widgets.manage.SelectWidgetActivity"
android:exported="false" />
<activity <activity
android:name=".ui.PinShortcutActivity" android:name=".ui.PinShortcutActivity"
android:autoRemoveFromRecents="true" android:autoRemoveFromRecents="true"
@ -85,7 +99,7 @@
<service <service
android:name=".actions.lock.LauncherAccessibilityService" android:name=".actions.lock.LauncherAccessibilityService"
android:exported="true" android:exported="true"
android:label="@string/accessibility_service_name" android:label="@string/app_name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter> <intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" /> <action android:name="android.accessibilityservice.AccessibilityService" />

View file

@ -12,6 +12,8 @@ import android.os.Build.VERSION_CODES
import android.os.UserHandle import android.os.UserHandle
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import android.appwidget.AppWidgetHost
import android.appwidget.AppWidgetManager
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import de.jrpie.android.launcher.actions.TorchManager import de.jrpie.android.launcher.actions.TorchManager
import de.jrpie.android.launcher.apps.AbstractAppInfo import de.jrpie.android.launcher.apps.AbstractAppInfo
@ -20,13 +22,22 @@ import de.jrpie.android.launcher.apps.isPrivateSpaceLocked
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion
import de.jrpie.android.launcher.preferences.resetPreferences import de.jrpie.android.launcher.preferences.resetPreferences
import de.jrpie.android.launcher.widgets.LauncherWidgetProvider
import de.jrpie.android.launcher.widgets.Widget
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
const val APP_WIDGET_HOST_ID = 42;
class Application : android.app.Application() { class Application : android.app.Application() {
val apps = MutableLiveData<List<AbstractDetailedAppInfo>>() val apps = MutableLiveData<List<AbstractDetailedAppInfo>>()
val widgets = MutableLiveData<Set<Widget>>()
val privateSpaceLocked = MutableLiveData<Boolean>() val privateSpaceLocked = MutableLiveData<Boolean>()
lateinit var appWidgetHost: AppWidgetHost
lateinit var appWidgetManager: AppWidgetManager
private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() { private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
@ -90,6 +101,8 @@ class Application : android.app.Application() {
customAppNames = LauncherPreferences.apps().customNames() customAppNames = LauncherPreferences.apps().customNames()
} else if (pref == LauncherPreferences.apps().keys().pinnedShortcuts()) { } else if (pref == LauncherPreferences.apps().keys().pinnedShortcuts()) {
loadApps() loadApps()
} else if (pref == LauncherPreferences.widgets().keys().widgets()) {
widgets.postValue(LauncherPreferences.widgets().widgets() ?: setOf())
} }
} }
@ -103,10 +116,15 @@ class Application : android.app.Application() {
torchManager = TorchManager(this) torchManager = TorchManager(this)
} }
appWidgetHost = AppWidgetHost(this.applicationContext, APP_WIDGET_HOST_ID)
appWidgetManager = AppWidgetManager.getInstance(this.applicationContext)
appWidgetHost.startListening()
val preferences = PreferenceManager.getDefaultSharedPreferences(this) val preferences = PreferenceManager.getDefaultSharedPreferences(this)
LauncherPreferences.init(preferences, this.resources) LauncherPreferences.init(preferences, this.resources)
// Try to restore old preferences // Try to restore old preferences
migratePreferencesToNewVersion(this) migratePreferencesToNewVersion(this)
@ -157,4 +175,10 @@ class Application : android.app.Application() {
apps.postValue(getApps(packageManager, applicationContext)) apps.postValue(getApps(packageManager, applicationContext))
} }
} }
override fun onTerminate() {
appWidgetHost.stopListening()
super.onTerminate()
}
} }

View file

@ -6,6 +6,9 @@ import android.app.role.RoleManager
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.appwidget.AppWidgetProviderInfo
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.LauncherApps import android.content.pm.LauncherApps
@ -38,6 +41,8 @@ import androidx.core.net.toUri
const val LOG_TAG = "Launcher" const val LOG_TAG = "Launcher"
const val REQUEST_SET_DEFAULT_HOME = 42
fun isDefaultHomeScreen(context: Context): Boolean { fun isDefaultHomeScreen(context: Context): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val roleManager = context.getSystemService(RoleManager::class.java) val roleManager = context.getSystemService(RoleManager::class.java)
@ -59,11 +64,12 @@ fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& context is Activity && context is Activity
&& !isDefault // using role manager only works when µLauncher is not already the default. && checkDefault // using role manager only works when µLauncher is not already the default.
) { ) {
val roleManager = context.getSystemService(RoleManager::class.java) val roleManager = context.getSystemService(RoleManager::class.java)
context.startActivity( context.startActivityForResult(
roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME) roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME),
REQUEST_SET_DEFAULT_HOME
) )
return return
} }

View file

@ -6,14 +6,18 @@ import android.content.SharedPreferences.Editor
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.widget.Toast import android.widget.Toast
import androidx.core.content.edit
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json 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 @Serializable
sealed interface Action { sealed interface Action {
fun invoke(context: Context, rect: Rect? = null): Boolean fun invoke(context: Context, rect: Rect? = null): Boolean
@ -21,6 +25,10 @@ sealed interface Action {
fun getIcon(context: Context): Drawable? fun getIcon(context: Context): Drawable?
fun isAvailable(context: Context): Boolean fun isAvailable(context: Context): Boolean
fun showConfigurationDialog(context: Context, onSuccess: (Action) -> Unit) {
onSuccess(this)
}
// Can the action be used to reach µLauncher settings? // Can the action be used to reach µLauncher settings?
fun canReachSettings(): Boolean fun canReachSettings(): Boolean

View file

@ -11,7 +11,9 @@ import android.view.KeyEvent
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.Application
import de.jrpie.android.launcher.BuildConfig
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.actions.lock.LauncherAccessibilityService
import de.jrpie.android.launcher.apps.AppFilter import de.jrpie.android.launcher.apps.AppFilter
import de.jrpie.android.launcher.apps.hidePrivateSpaceWhenLocked import de.jrpie.android.launcher.apps.hidePrivateSpaceWhenLocked
import de.jrpie.android.launcher.apps.isPrivateSpaceSupported import de.jrpie.android.launcher.apps.isPrivateSpaceSupported
@ -132,6 +134,14 @@ enum class LauncherAction(
R.drawable.baseline_settings_applications_24, R.drawable.baseline_settings_applications_24,
::expandSettingsPanel ::expandSettingsPanel
), ),
RECENT_APPS(
"recent_apps",
R.string.list_other_recent_apps,
R.drawable.baseline_apps_24,
LauncherAccessibilityService::openRecentApps,
false,
{ _ -> BuildConfig.USE_ACCESSIBILITY_SERVICE }
),
LOCK_SCREEN( LOCK_SCREEN(
"lock_screen", "lock_screen",
R.string.list_other_lock_screen, R.string.list_other_lock_screen,
@ -142,7 +152,13 @@ enum class LauncherAction(
"toggle_torch", "toggle_torch",
R.string.list_other_torch, R.string.list_other_torch,
R.drawable.baseline_flashlight_on_24, R.drawable.baseline_flashlight_on_24,
::toggleTorch ::toggleTorch,
),
LAUNCH_OTHER_LAUNCHER(
"launcher_other_launcher",
R.string.list_other_launch_other_launcher,
R.drawable.baseline_home_24,
::launchOtherLauncher
), ),
NOP("nop", R.string.list_other_nop, R.drawable.baseline_not_interested_24, {}); NOP("nop", R.string.list_other_nop, R.drawable.baseline_not_interested_24, {});
@ -248,6 +264,15 @@ private fun expandSettingsPanel(context: Context) {
} }
} }
private fun launchOtherLauncher(context: Context) {
context.startActivity(
Intent.createChooser(
Intent(Intent.ACTION_MAIN).also { it.addCategory(Intent.CATEGORY_HOME) },
context.getString(R.string.list_other_launch_other_launcher)
)
)
}
private fun openSettings(context: Context) { private fun openSettings(context: Context) {
context.startActivity(Intent(context, SettingsActivity::class.java)) context.startActivity(Intent(context, SettingsActivity::class.java))
} }

View file

@ -0,0 +1,83 @@
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<TextView>(R.id.dialog_select_widget_panel_info)
alertDialog.findViewById<RecyclerView>(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
}
}

View file

@ -22,26 +22,44 @@ class LauncherAccessibilityService : AccessibilityService() {
companion object { companion object {
private const val TAG = "Launcher Accessibility" private const val TAG = "Launcher Accessibility"
private const val ACTION_REQUEST_ENABLE = "ACTION_REQUEST_ENABLE"
const val ACTION_LOCK_SCREEN = "ACTION_LOCK_SCREEN" const val ACTION_LOCK_SCREEN = "ACTION_LOCK_SCREEN"
const val ACTION_RECENT_APPS = "ACTION_RECENT_APPS"
fun lockScreen(context: Context) { private fun invoke(context: Context, action: String, failureMessageRes: Int) {
try { try {
context.startService( context.startService(
Intent( Intent(
context, context,
LauncherAccessibilityService::class.java LauncherAccessibilityService::class.java
).apply { ).apply {
action = ACTION_LOCK_SCREEN this.action = action
}) })
} catch (e: Exception) { } catch (_: Exception) {
Toast.makeText( Toast.makeText(
context, context,
context.getString(R.string.alert_lock_screen_failed), context.getString(failureMessageRes),
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
} }
} }
fun lockScreen(context: Context) {
if (!isEnabled(context)) {
showEnableDialog(context)
} else {
invoke(context, ACTION_LOCK_SCREEN, R.string.alert_lock_screen_failed)
}
}
fun openRecentApps(context: Context) {
if (!isEnabled(context)) {
showEnableDialog(context)
} else {
invoke(context, ACTION_RECENT_APPS, R.string.alert_recent_apps_failed)
}
}
fun isEnabled(context: Context): Boolean { fun isEnabled(context: Context): Boolean {
val enabledServices = Settings.Secure.getString( val enabledServices = Settings.Secure.getString(
context.contentResolver, context.contentResolver,
@ -58,7 +76,7 @@ class LauncherAccessibilityService : AccessibilityService() {
setView(R.layout.dialog_consent_accessibility) setView(R.layout.dialog_consent_accessibility)
setTitle(R.string.dialog_consent_accessibility_title) setTitle(R.string.dialog_consent_accessibility_title)
setPositiveButton(R.string.dialog_consent_accessibility_ok) { _, _ -> setPositiveButton(R.string.dialog_consent_accessibility_ok) { _, _ ->
lockScreen(context) invoke(context, ACTION_REQUEST_ENABLE, R.string.alert_enable_accessibility_failed)
} }
setNegativeButton(R.string.dialog_cancel) { _, _ -> } setNegativeButton(R.string.dialog_cancel) { _, _ -> }
}.create().also { it.show() }.apply { }.create().also { it.show() }.apply {
@ -94,7 +112,9 @@ class LauncherAccessibilityService : AccessibilityService() {
} }
when (action) { when (action) {
ACTION_REQUEST_ENABLE -> {} // do nothing
ACTION_LOCK_SCREEN -> handleLockScreen() ACTION_LOCK_SCREEN -> handleLockScreen()
ACTION_RECENT_APPS -> performGlobalAction(GLOBAL_ACTION_RECENTS)
} }
} }
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)

View file

@ -6,6 +6,7 @@ import android.widget.Button
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import de.jrpie.android.launcher.BuildConfig import de.jrpie.android.launcher.BuildConfig
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.actions.lock.LauncherAccessibilityService
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences

View file

@ -8,6 +8,8 @@ import de.jrpie.android.launcher.actions.lock.LockMethod;
import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer; import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer;
import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer; import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer;
import de.jrpie.android.launcher.preferences.serialization.SetPinnedShortcutInfoPreferenceSerializer; 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.Background;
import de.jrpie.android.launcher.preferences.theme.ColorTheme; import de.jrpie.android.launcher.preferences.theme.ColorTheme;
import de.jrpie.android.launcher.preferences.theme.Font; import de.jrpie.android.launcher.preferences.theme.Font;
@ -72,6 +74,7 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
@Preference(name = "search_auto_launch", type = boolean.class, defaultValue = "true"), @Preference(name = "search_auto_launch", type = boolean.class, defaultValue = "true"),
@Preference(name = "search_web", type = boolean.class, description = "false"), @Preference(name = "search_web", type = boolean.class, description = "false"),
@Preference(name = "search_auto_open_keyboard", type = boolean.class, defaultValue = "true"), @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 = { @PreferenceGroup(name = "enabled_gestures", prefix = "settings_enabled_gestures_", suffix = "_key", value = {
@Preference(name = "double_swipe", type = boolean.class, defaultValue = "true"), @Preference(name = "double_swipe", type = boolean.class, defaultValue = "true"),
@ -81,5 +84,9 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
@PreferenceGroup(name = "actions", prefix = "settings_actions_", suffix = "_key", value = { @PreferenceGroup(name = "actions", prefix = "settings_actions_", suffix = "_key", value = {
@Preference(name = "lock_method", type = LockMethod.class, defaultValue = "DEVICE_ADMIN"), @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 {} public final class LauncherPreferences$Config {}

View file

@ -2,23 +2,29 @@ package de.jrpie.android.launcher.preferences
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import de.jrpie.android.launcher.Application
import de.jrpie.android.launcher.BuildConfig import de.jrpie.android.launcher.BuildConfig
import de.jrpie.android.launcher.actions.Action 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
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER 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.apps.DetailedAppInfo
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion1 import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion1
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion2 import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion2
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion3 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.preferences.legacy.migratePreferencesFromVersionUnknown
import de.jrpie.android.launcher.ui.HomeActivity 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. /* Current version of the structure of preferences.
* Increase when breaking changes are introduced and write an appropriate case in * Increase when breaking changes are introduced and write an appropriate case in
* `migratePreferencesToNewVersion` * `migratePreferencesToNewVersion`
*/ */
const val PREFERENCE_VERSION = 4 const val PREFERENCE_VERSION = 5
const val UNKNOWN_PREFERENCE_VERSION = -1 const val UNKNOWN_PREFERENCE_VERSION = -1
private const val TAG = "Launcher - Preferences" private const val TAG = "Launcher - Preferences"
@ -40,18 +46,23 @@ fun migratePreferencesToNewVersion(context: Context) {
} }
1 -> { 1 -> {
migratePreferencesFromVersion1() migratePreferencesFromVersion1(context)
Log.i(TAG, "migration of preferences complete (1 -> ${PREFERENCE_VERSION}).") Log.i(TAG, "migration of preferences complete (1 -> ${PREFERENCE_VERSION}).")
} }
2 -> { 2 -> {
migratePreferencesFromVersion2() migratePreferencesFromVersion2(context)
Log.i(TAG, "migration of preferences complete (2 -> ${PREFERENCE_VERSION}).") Log.i(TAG, "migration of preferences complete (2 -> ${PREFERENCE_VERSION}).")
} }
3 -> { 3 -> {
migratePreferencesFromVersion3() migratePreferencesFromVersion3(context)
Log.i(TAG, "migration of preferences complete (3 -> ${PREFERENCE_VERSION}).") Log.i(TAG, "migration of preferences complete (3 -> ${PREFERENCE_VERSION}).")
} }
4 -> {
migratePreferencesFromVersion4(context)
Log.i(TAG, "migration of preferences complete (4 -> ${PREFERENCE_VERSION}).")
}
else -> { else -> {
Log.w( Log.w(
TAG, TAG,
@ -71,6 +82,17 @@ fun resetPreferences(context: Context) {
Log.i(TAG, "Resetting preferences") Log.i(TAG, "Resetting preferences")
LauncherPreferences.clear() LauncherPreferences.clear()
LauncherPreferences.internal().versionCode(PREFERENCE_VERSION) 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<AbstractAppInfo> = mutableSetOf() val hidden: MutableSet<AbstractAppInfo> = mutableSetOf()

View file

@ -1,11 +1,13 @@
package de.jrpie.android.launcher.preferences.legacy 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.Action
import de.jrpie.android.launcher.actions.AppAction import de.jrpie.android.launcher.actions.AppAction
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.actions.LauncherAction
import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER
import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -13,7 +15,6 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import androidx.core.content.edit
@Serializable @Serializable
@ -129,7 +130,7 @@ private fun migrateAction(key: String) {
* Migrate preferences from version 1 (used until version j-0.0.18) to the current format * Migrate preferences from version 1 (used until version j-0.0.18) to the current format
* (see [PREFERENCE_VERSION]) * (see [PREFERENCE_VERSION])
*/ */
fun migratePreferencesFromVersion1() { fun migratePreferencesFromVersion1(context: Context) {
assert(LauncherPreferences.internal().versionCode() == 1) assert(LauncherPreferences.internal().versionCode() == 1)
Gesture.entries.forEach { g -> migrateAction(g.id) } Gesture.entries.forEach { g -> migrateAction(g.id) }
migrateAppInfoSet(LauncherPreferences.apps().keys().hidden()) migrateAppInfoSet(LauncherPreferences.apps().keys().hidden())
@ -137,5 +138,5 @@ fun migratePreferencesFromVersion1() {
migrateAppInfoStringMap(LauncherPreferences.apps().keys().customNames()) migrateAppInfoStringMap(LauncherPreferences.apps().keys().customNames())
LauncherPreferences.internal().versionCode(2) LauncherPreferences.internal().versionCode(2)
migratePreferencesFromVersion2() migratePreferencesFromVersion2(context)
} }

View file

@ -1,5 +1,6 @@
package de.jrpie.android.launcher.preferences.legacy package de.jrpie.android.launcher.preferences.legacy
import android.content.Context
import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.actions.LauncherAction
@ -11,10 +12,10 @@ import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION
* Migrate preferences from version 2 (used until version 0.0.21) to the current format * Migrate preferences from version 2 (used until version 0.0.21) to the current format
* (see [PREFERENCE_VERSION]) * (see [PREFERENCE_VERSION])
*/ */
fun migratePreferencesFromVersion2() { fun migratePreferencesFromVersion2(context: Context) {
assert(LauncherPreferences.internal().versionCode() == 2) assert(LauncherPreferences.internal().versionCode() == 2)
// previously there was no setting for this // previously there was no setting for this
Action.setActionForGesture(Gesture.BACK, LauncherAction.CHOOSE) Action.setActionForGesture(Gesture.BACK, LauncherAction.CHOOSE)
LauncherPreferences.internal().versionCode(3) LauncherPreferences.internal().versionCode(3)
migratePreferencesFromVersion3() migratePreferencesFromVersion3(context)
} }

View file

@ -1,17 +1,17 @@
package de.jrpie.android.launcher.preferences.legacy package de.jrpie.android.launcher.preferences.legacy
import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.SharedPreferences.Editor import android.content.SharedPreferences.Editor
import de.jrpie.android.launcher.apps.AppInfo import androidx.core.content.edit
import de.jrpie.android.launcher.apps.AbstractAppInfo import de.jrpie.android.launcher.apps.AbstractAppInfo
import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION import de.jrpie.android.launcher.preferences.PREFERENCE_VERSION
import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer
import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json 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 * Migrate preferences from version 3 (used until version 0.0.23) to the current format
@ -70,8 +70,7 @@ private fun migrateMapAppInfoString(key: String, preferences: SharedPreferences,
} }
} }
fun migratePreferencesFromVersion3() { fun migratePreferencesFromVersion3(context: Context) {
assert(PREFERENCE_VERSION == 4)
assert(LauncherPreferences.internal().versionCode() == 3) assert(LauncherPreferences.internal().versionCode() == 3)
val preferences = LauncherPreferences.getSharedPreferences() val preferences = LauncherPreferences.getSharedPreferences()
@ -82,4 +81,5 @@ fun migratePreferencesFromVersion3() {
} }
LauncherPreferences.internal().versionCode(4) LauncherPreferences.internal().versionCode(4)
migratePreferencesFromVersion4(context)
} }

View file

@ -0,0 +1,27 @@
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 == 5)
assert(LauncherPreferences.internal().versionCode() == 4)
LauncherPreferences.widgets().widgets(
setOf(
ClockWidget(
(context.applicationContext as Application).appWidgetHost.allocateAppWidgetId(),
WidgetPosition(1, 3, 10, 4),
WidgetPanel.HOME.id
)
)
)
LauncherPreferences.internal().versionCode(5)
}

View file

@ -3,10 +3,10 @@ package de.jrpie.android.launcher.preferences.legacy
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log import android.util.Log
import androidx.core.content.edit
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.theme.Background import de.jrpie.android.launcher.preferences.theme.Background
import de.jrpie.android.launcher.preferences.theme.ColorTheme import de.jrpie.android.launcher.preferences.theme.ColorTheme
import androidx.core.content.edit
private fun migrateStringPreference( private fun migrateStringPreference(
@ -392,5 +392,5 @@ fun migratePreferencesFromVersionUnknown(context: Context) {
LauncherPreferences.internal().versionCode(1) LauncherPreferences.internal().versionCode(1)
Log.i(TAG, "migrated preferences to version 1.") Log.i(TAG, "migrated preferences to version 1.")
migratePreferencesFromVersion1() migratePreferencesFromVersion1(context)
} }

View file

@ -4,6 +4,8 @@ package de.jrpie.android.launcher.preferences.serialization
import de.jrpie.android.launcher.apps.AbstractAppInfo import de.jrpie.android.launcher.apps.AbstractAppInfo
import de.jrpie.android.launcher.apps.PinnedShortcutInfo 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.PreferenceSerializationException
import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializer import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -28,6 +30,40 @@ class SetAbstractAppInfoPreferenceSerializer :
} }
} }
@Suppress("UNCHECKED_CAST")
class SetWidgetSerializer :
PreferenceSerializer<java.util.Set<Widget>?, java.util.Set<java.lang.String>?> {
@Throws(PreferenceSerializationException::class)
override fun serialize(value: java.util.Set<Widget>?): java.util.Set<java.lang.String>? {
return value?.map(Widget::serialize)
?.toHashSet() as? java.util.Set<java.lang.String>
}
@Throws(PreferenceSerializationException::class)
override fun deserialize(value: java.util.Set<java.lang.String>?): java.util.Set<Widget>? {
return value?.map(java.lang.String::toString)?.map(Widget::deserialize)
?.toHashSet() as? java.util.Set<Widget>
}
}
@Suppress("UNCHECKED_CAST")
class SetWidgetPanelSerializer :
PreferenceSerializer<java.util.Set<WidgetPanel>?, java.util.Set<java.lang.String>?> {
@Throws(PreferenceSerializationException::class)
override fun serialize(value: java.util.Set<WidgetPanel>?): java.util.Set<java.lang.String>? {
return value?.map(WidgetPanel::serialize)
?.toHashSet() as? java.util.Set<java.lang.String>
}
@Throws(PreferenceSerializationException::class)
override fun deserialize(value: java.util.Set<java.lang.String>?): java.util.Set<WidgetPanel>? {
return value?.map(java.lang.String::toString)?.map(WidgetPanel::deserialize)
?.toHashSet() as? java.util.Set<WidgetPanel>
}
}
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
class SetPinnedShortcutInfoPreferenceSerializer : class SetPinnedShortcutInfoPreferenceSerializer :
PreferenceSerializer<java.util.Set<PinnedShortcutInfo>?, java.util.Set<java.lang.String>?> { PreferenceSerializer<java.util.Set<PinnedShortcutInfo>?, java.util.Set<java.lang.String>?> {

View file

@ -1,5 +1,6 @@
package de.jrpie.android.launcher.ui package de.jrpie.android.launcher.ui
import android.app.Activity
import android.content.Context import android.content.Context
import android.graphics.ColorMatrix import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter import android.graphics.ColorMatrixColorFilter
@ -38,10 +39,17 @@ fun ImageView.transformGrayscale(grayscale: Boolean) {
} }
// Taken from https://stackoverflow.com/a/50743764/12787264 // Taken from https://stackoverflow.com/a/50743764
fun View.openSoftKeyboard(context: Context) { fun View.openSoftKeyboard(context: Context) {
this.requestFocus() this.requestFocus()
// open the soft keyboard (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
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 )
}
} }

View file

@ -1,6 +1,7 @@
package de.jrpie.android.launcher.ui package de.jrpie.android.launcher.ui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
@ -10,8 +11,7 @@ import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.window.OnBackInvokedDispatcher import android.window.OnBackInvokedDispatcher
import androidx.appcompat.app.AppCompatActivity import de.jrpie.android.launcher.Application
import androidx.core.view.isVisible
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
@ -20,7 +20,6 @@ import de.jrpie.android.launcher.databinding.HomeBinding
import de.jrpie.android.launcher.openTutorial import de.jrpie.android.launcher.openTutorial
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
import java.util.Locale
/** /**
* [HomeActivity] is the actual application Launcher, * [HomeActivity] is the actual application Launcher,
@ -34,10 +33,10 @@ import java.util.Locale
* - Setting global variables (preferences etc.) * - Setting global variables (preferences etc.)
* - Opening the [TutorialActivity] on new installations * - Opening the [TutorialActivity] on new installations
*/ */
class HomeActivity : UIObject, AppCompatActivity() { class HomeActivity : UIObject, Activity() {
private lateinit var binding: HomeBinding private lateinit var binding: HomeBinding
private lateinit var touchGestureDetector: TouchGestureDetector private var touchGestureDetector: TouchGestureDetector? = null
private var sharedPreferencesListener = private var sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey -> SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
@ -45,40 +44,26 @@ class HomeActivity : UIObject, AppCompatActivity() {
prefKey?.startsWith("display.") == true prefKey?.startsWith("display.") == true
) { ) {
recreate() 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?) { override fun onCreate(savedInstanceState: Bundle?) {
super<AppCompatActivity>.onCreate(savedInstanceState) super<Activity>.onCreate(savedInstanceState)
super<UIObject>.onCreate() super<UIObject>.onCreate()
touchGestureDetector = TouchGestureDetector(
this, 0, 0,
LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
)
touchGestureDetector.updateScreenSize(windowManager)
// Initialise layout // Initialise layout
binding = HomeBinding.inflate(layoutInflater) binding = HomeBinding.inflate(layoutInflater)
setContentView(binding.root) 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() // Handle back key / gesture on Android 13+, cf. onKeyDown()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
onBackInvokedDispatcher.registerOnBackInvokedCallback( onBackInvokedDispatcher.registerOnBackInvokedCallback(
@ -94,12 +79,11 @@ class HomeActivity : UIObject, AppCompatActivity() {
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
touchGestureDetector.updateScreenSize(windowManager) touchGestureDetector?.updateScreenSize(windowManager)
} }
override fun onStart() { override fun onStart() {
super<AppCompatActivity>.onStart() super<Activity>.onStart()
super<UIObject>.onStart() super<UIObject>.onStart()
// If the tutorial was not finished, start it // If the tutorial was not finished, start it
@ -110,6 +94,15 @@ class HomeActivity : UIObject, AppCompatActivity() {
LauncherPreferences.getSharedPreferences() LauncherPreferences.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener) .registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
(application as Application).appWidgetHost.startListening()
}
override fun onStop() {
(application as Application).appWidgetHost.stopListening()
super.onStop()
} }
override fun onWindowFocusChanged(hasFocus: Boolean) { override fun onWindowFocusChanged(hasFocus: Boolean) {
@ -135,44 +128,6 @@ class HomeActivity : UIObject, AppCompatActivity() {
} }
} }
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 { override fun getTheme(): Resources.Theme {
val mTheme = modifyTheme(super.getTheme()) val mTheme = modifyTheme(super.getTheme())
mTheme.applyStyle(R.style.backgroundWallpaper, true) mTheme.applyStyle(R.style.backgroundWallpaper, true)
@ -188,11 +143,33 @@ class HomeActivity : UIObject, AppCompatActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
touchGestureDetector.edgeWidth = /* 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,
LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
).also {
it.updateScreenSize(windowManager)
}
initClock() 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
}
}
updateSettingsFallbackButtonVisibility() updateSettingsFallbackButtonVisibility()
binding.homeWidgetContainer.updateWidgets(this@HomeActivity,
LauncherPreferences.widgets().widgets()
)
} }
override fun onDestroy() { override fun onDestroy() {
@ -230,30 +207,10 @@ class HomeActivity : UIObject, AppCompatActivity() {
} }
override fun onTouchEvent(event: MotionEvent): Boolean { override fun onTouchEvent(event: MotionEvent): Boolean {
touchGestureDetector.onTouchEvent(event) touchGestureDetector?.onTouchEvent(event)
return true 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() { private fun handleBack() {
Gesture.BACK(this) Gesture.BACK(this)
} }

View file

@ -49,7 +49,21 @@ class PinShortcutActivity : AppCompatActivity(), UIObject {
val request = launcherApps.getPinItemRequest(intent) val request = launcherApps.getPinItemRequest(intent)
this.request = request this.request = request
if (request == null || request.requestType != PinItemRequest.REQUEST_TYPE_SHORTCUT) { 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) {
finish() finish()
return return
} }

View file

@ -11,13 +11,16 @@ import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.apps.AppFilter import de.jrpie.android.launcher.apps.AppFilter
import de.jrpie.android.launcher.databinding.ListAppsBinding import de.jrpie.android.launcher.databinding.ListAppsBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.UIObject 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.list.ListActivity
import de.jrpie.android.launcher.ui.openSoftKeyboard import de.jrpie.android.launcher.ui.openSoftKeyboard
import kotlin.math.absoluteValue
/** /**
@ -90,6 +93,20 @@ class ListFragmentApps : Fragment(), UIObject {
} }
} }
adapter = appsRecyclerAdapter 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 : binding.listAppsSearchview.setOnQueryTextListener(object :

View file

@ -11,6 +11,7 @@ import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.actions.LauncherAction
import de.jrpie.android.launcher.actions.WidgetPanelAction
import de.jrpie.android.launcher.ui.list.ListActivity import de.jrpie.android.launcher.ui.list.ListActivity
/** /**
@ -23,8 +24,10 @@ import de.jrpie.android.launcher.ui.list.ListActivity
class OtherRecyclerAdapter(val activity: Activity) : class OtherRecyclerAdapter(val activity: Activity) :
RecyclerView.Adapter<OtherRecyclerAdapter.ViewHolder>() { RecyclerView.Adapter<OtherRecyclerAdapter.ViewHolder>() {
private val othersList: Array<LauncherAction> = private val othersList: Array<Action> =
LauncherAction.entries.filter { it.isAvailable(activity) }.toTypedArray() LauncherAction.entries.filter { it.isAvailable(activity) }
.plus(WidgetPanelAction(-1))
.toTypedArray()
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener { View.OnClickListener {
@ -36,10 +39,12 @@ class OtherRecyclerAdapter(val activity: Activity) :
val pos = bindingAdapterPosition val pos = bindingAdapterPosition
val content = othersList[pos] val content = othersList[pos]
activity.finish()
val gestureId = (activity as? ListActivity)?.forGesture ?: return val gestureId = (activity as? ListActivity)?.forGesture ?: return
val gesture = Gesture.byId(gestureId) ?: return val gesture = Gesture.byId(gestureId) ?: return
Action.setActionForGesture(gesture, content) content.showConfigurationDialog(activity) { configuredAction ->
Action.setActionForGesture(gesture, configuredAction)
activity.finish()
}
} }
init { init {
@ -48,11 +53,11 @@ class OtherRecyclerAdapter(val activity: Activity) :
} }
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
val otherLabel = activity.getString(othersList[i].label) val otherLabel = othersList[i].label(activity)
val icon = othersList[i].icon val icon = othersList[i].getIcon(activity)
viewHolder.textView.text = otherLabel viewHolder.textView.text = otherLabel
viewHolder.iconView.setImageResource(icon) viewHolder.iconView.setImageDrawable(icon)
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {

View file

@ -109,7 +109,7 @@ class SettingsActivity : AppCompatActivity(), UIObject {
} }
private val TAB_TITLES = arrayOf( private val TAB_TITLES = arrayOf(
R.string.settings_tab_app, R.string.settings_tab_actions,
R.string.settings_tab_launcher, R.string.settings_tab_launcher,
R.string.settings_tab_meta R.string.settings_tab_meta
) )

View file

@ -11,6 +11,8 @@ import de.jrpie.android.launcher.actions.openAppsList
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.theme.ColorTheme import de.jrpie.android.launcher.preferences.theme.ColorTheme
import de.jrpie.android.launcher.setDefaultHomeScreen import de.jrpie.android.launcher.setDefaultHomeScreen
import de.jrpie.android.launcher.ui.widgets.manage.ManageWidgetPanelsActivity
import de.jrpie.android.launcher.ui.widgets.manage.ManageWidgetsActivity
/** /**
@ -81,6 +83,22 @@ class SettingsFragmentLauncher : PreferenceFragmentCompat() {
true true
} }
val manageWidgets = findPreference<androidx.preference.Preference>(
LauncherPreferences.widgets().keys().widgets()
)
manageWidgets?.setOnPreferenceClickListener {
startActivity(Intent(requireActivity(), ManageWidgetsActivity::class.java))
true
}
val manageWidgetPanels = findPreference<androidx.preference.Preference>(
LauncherPreferences.widgets().keys().customPanels()
)
manageWidgetPanels?.setOnPreferenceClickListener {
startActivity(Intent(requireActivity(), ManageWidgetPanelsActivity::class.java))
true
}
val hiddenApps = findPreference<androidx.preference.Preference>( val hiddenApps = findPreference<androidx.preference.Preference>(
LauncherPreferences.apps().keys().hidden() LauncherPreferences.apps().keys().hidden()
) )

View file

@ -0,0 +1,80 @@
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)
}
}
}
}

View file

@ -0,0 +1,144 @@
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<Int, View>()
open fun updateWidgets(activity: Activity, widgets: Collection<Widget>?) {
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.put(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..<size).map { getChildAt(it) }.forEach {
val position = (it.layoutParams as LayoutParams).position.getAbsoluteRect(mWidth, mHeight)
it.measure(makeMeasureSpec(position.width(), MeasureSpec.EXACTLY), makeMeasureSpec(position.height(), MeasureSpec.EXACTLY))
}
// Find rightmost and bottom-most child
(0..<size).map { getChildAt(it) }.filter { it.visibility != GONE }.forEach {
val position = (it.layoutParams as LayoutParams).position.getAbsoluteRect(mWidth, mHeight)
maxWidth = max(maxWidth, position.left + it.measuredWidth)
maxHeight = max(maxHeight, position.top + it.measuredHeight)
}
setMeasuredDimension(
resolveSizeAndState(maxWidth.toInt(), widthMeasureSpec, 0),
resolveSizeAndState(maxHeight.toInt(), heightMeasureSpec, 0)
)
}
/**
* Returns a set of layout parameters with a width of
* [ViewGroup.LayoutParams.WRAP_CONTENT],
* a height of [ViewGroup.LayoutParams.WRAP_CONTENT]
* and with the coordinates (0, 0).
*/
override fun generateDefaultLayoutParams(): ViewGroup.LayoutParams {
return LayoutParams(WidgetPosition(0,0,1,1))
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
for (i in 0..<size) {
val child = getChildAt(i)
val lp = child.layoutParams as LayoutParams
val position = lp.position.getAbsoluteRect(r - l, b - t)
child.layout(position.left, position.top, position.right, position.bottom)
child.layoutParams.width = position.width()
child.layoutParams.height = position.height()
}
}
override fun generateLayoutParams(attrs: AttributeSet?): ViewGroup.LayoutParams {
return LayoutParams(context, attrs)
}
// Override to allow type-checking of LayoutParams.
override fun checkLayoutParams(p: ViewGroup.LayoutParams?): Boolean {
return p is LayoutParams
}
override fun generateLayoutParams(p: ViewGroup.LayoutParams?): ViewGroup.LayoutParams {
return LayoutParams(p)
}
override fun shouldDelayChildPressedState(): Boolean {
return false
}
companion object {
class LayoutParams : ViewGroup.LayoutParams {
var position = WidgetPosition(0,0,4,4)
constructor(position: WidgetPosition) : super(WRAP_CONTENT, WRAP_CONTENT) {
this.position = position
}
constructor(c: Context, attrs: AttributeSet?) : super(c, attrs)
constructor(source: ViewGroup.LayoutParams?) : super(source)
}
}
}

View file

@ -0,0 +1,50 @@
package de.jrpie.android.launcher.ui.widgets
import android.app.Activity
import android.content.res.Resources
import android.os.Bundle
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.databinding.ActivityWidgetPanelBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.widgets.manage.EXTRA_PANEL_ID
import de.jrpie.android.launcher.widgets.WidgetPanel
class WidgetPanelActivity : Activity(), UIObject {
lateinit var binding: ActivityWidgetPanelBinding
var widgetPanelId: Int = WidgetPanel.Companion.HOME.id
override fun onCreate(savedInstanceState: Bundle?) {
super<Activity>.onCreate(savedInstanceState)
super<UIObject>.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<Activity>.onStart()
super<UIObject>.onStart()
}
override fun isHomeScreen(): Boolean {
return true
}
}

View file

@ -0,0 +1,104 @@
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<AppCompatActivity>.onCreate(savedInstanceState)
super<UIObject>.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 {
// improve performance (since content changes don't change the layout size)
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<EditText>(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<EditText>(R.id.dialog_create_widget_panel_edit_text)
?.setText(
getString(
R.string.widget_panel_default_name,
WidgetPanel.allocateId()
)
)
}
true
}
}
override fun onStart() {
super<AppCompatActivity>.onStart()
super<UIObject>.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() }
}
}

View file

@ -0,0 +1,185 @@
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 {
var panelId: Int = WidgetPanel.HOME.id
private var sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
if (prefKey == LauncherPreferences.widgets().keys().widgets()) {
// We can't observe the livedata because this is not an AppCompatActivity
findViewById<WidgetContainerView>(R.id.manage_widgets_container).updateWidgets(this,
LauncherPreferences.widgets().widgets()
)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super<Activity>.onCreate(savedInstanceState)
super<UIObject>.onCreate()
setContentView(R.layout.activity_manage_widgets)
panelId = intent.extras?.getInt(EXTRA_PANEL_ID, WidgetPanel.HOME.id) ?: WidgetPanel.HOME.id
findViewById<FloatingActionButton>(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<WidgetContainerView>(R.id.manage_widgets_container).let {
it.widgetPanelId = panelId
it.updateWidgets(this, (application as Application).widgets.value)
}
}
override fun onStart() {
super<Activity>.onStart()
super<UIObject>.onStart()
LauncherPreferences.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
}
override fun onResume() {
super.onResume()
findViewById<WidgetContainerView>(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
}
}

View file

@ -0,0 +1,172 @@
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<AppCompatActivity>.onStart()
super<UIObject>.onStart()
}
override fun onCreate(savedInstanceState: Bundle?) {
super<AppCompatActivity>.onCreate(savedInstanceState)
super<UIObject>.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<SelectWidgetRecyclerAdapter.ViewHolder>() {
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)
}
}
}

View file

@ -0,0 +1,175 @@
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 androidx.core.view.children
import de.jrpie.android.launcher.ui.widgets.WidgetContainerView
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
import kotlin.math.max
import kotlin.math.min
/**
* 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
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, rect: Rect) -> Rect) {
MOVE({ dx, dy, rect ->
Rect(rect.left + dx, rect.top + dy, rect.right + dx, rect.bottom + dy)
}),
TOP({ dx, dy, rect ->
Rect(rect.left, min(rect.top + dy, rect.bottom - 200), rect.right, rect.bottom)
}),
BOTTOM({ dx, dy, rect ->
Rect(rect.left, rect.top, rect.right, max(rect.top + 200, rect.bottom + dy))
}),
LEFT({ dx, dy, rect ->
Rect(min(rect.left + dx, rect.right - 200), rect.top, rect.right, rect.bottom)
}),
RIGHT({ dx, dy, rect ->
Rect(rect.left, rect.top, max(rect.left + 200, rect.right + dx), rect.bottom)
}),
}
var selectedWidgetOverlayView: WidgetOverlayView? = null
var selectedWidgetView: View? = null
var currentGestureStart: Point? = null
var startWidgetPosition: Rect? = null
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 = children.mapNotNull { it as? WidgetOverlayView }.firstOrNull {
RectF(it.x, it.y, it.x + it.width, it.y + it.height).toRect().contains(start) == true
} ?: return false
val position = (view.layoutParams as Companion.LayoutParams).position.getAbsoluteRect(width, height)
selectedWidgetOverlayView = view
selectedWidgetView = widgetViewById.get(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?.resize(
distanceX.toInt(),
distanceY.toInt(),
start
) ?: return true
val newPosition = WidgetPosition.fromAbsoluteRect(
absoluteNewPosition, width, height
)
if (newPosition != 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<Widget>?) {
super.updateWidgets(activity, widgets)
if (widgets == null) {
return
}
children.mapNotNull { it as? WidgetOverlayView }.forEach { removeView(it) }
widgets.filter { it.panelId == widgetPanelId }.forEach { widget ->
WidgetOverlayView(activity).let {
addView(it)
it.widgetId = widget.id
(it.layoutParams as Companion.LayoutParams).position = widget.position
}
}
}
}

View file

@ -0,0 +1,132 @@
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<Handle> {
return listOf<Handle>(
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)
}
}

View file

@ -0,0 +1,98 @@
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<WidgetPanelsRecyclerAdapter.ViewHolder>() {
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<EditText>(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<EditText>(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
}
}

View file

@ -0,0 +1,126 @@
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<View>): 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
)
}
}

View file

@ -0,0 +1,42 @@
package de.jrpie.android.launcher.widgets
import android.app.Activity
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.View
import de.jrpie.android.launcher.ui.widgets.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<View>): 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) { }
}

View file

@ -0,0 +1,58 @@
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)
}
}

View file

@ -0,0 +1,65 @@
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>): 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? {
return (context.applicationContext as Application).widgets.value?.firstOrNull {
it.id == id
}
}
}
}

View file

@ -0,0 +1,58 @@
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)
}
}
}

View file

@ -0,0 +1,58 @@
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
)
}
}
}

View file

@ -0,0 +1,97 @@
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<LauncherWidgetProvider> {
val list = mutableListOf<LauncherWidgetProvider>(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
}

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z" />
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
<path
android:fillColor="?android:textColor"
android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z" />
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z" />
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M13,13v8h8v-8h-8zM3,21h8v-8L3,13v8zM3,3v8h8L11,3L3,3zM16.66,1.69L11,7.34 16.66,13l5.66,-5.66 -5.66,-5.65z" />
</vector>

View file

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.widgets.manage.ManageWidgetPanelsActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/manage_widget_panels_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
app:elevation="0dp"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/manage_widget_panels_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="?actionBarSize"
android:padding="@dimen/appbar_padding"
android:text="@string/widget_panels_title"
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/manage_widget_panels_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:gravity="center"
android:includeFontPadding="true"
android:paddingLeft="16sp"
android:paddingRight="16sp"
android:src="@drawable/baseline_close_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/manage_widget_panels_recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/manage_widget_panels_appbar" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/manage_widget_panels_add_panel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/baseline_add_24"
app:layout_anchor="@+id/manage_widget_panels_recycler"
app:layout_anchorGravity="end|bottom"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.widgets.manage.ManageWidgetsActivity">
<de.jrpie.android.launcher.ui.widgets.manage.WidgetManagerView
android:id="@+id/manage_widgets_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/manage_widgets_button_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/baseline_add_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/select_widget_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.widgets.manage.SelectWidgetActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/select_widget_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@null"
app:elevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/select_widget_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="?actionBarSize"
android:padding="@dimen/appbar_padding"
android:text="@string/select_widget_title"
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
android:textSize="30sp"
app:layout_constraintEnd_toStartOf="@id/select_widget_close"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/select_widget_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:gravity="center"
android:includeFontPadding="true"
android:paddingLeft="16sp"
android:paddingRight="16sp"
android:src="@drawable/baseline_close_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/select_widget_recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/select_widget_appbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/home_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:longClickable="false"
tools:context=".ui.widgets.WidgetPanelActivity">
<de.jrpie.android.launcher.ui.widgets.WidgetContainerView
android:id="@+id/widget_panel_widget_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:longClickable="false"
android:fitsSystemWindows="true"
tools:context=".ui.widgets.ClockView">
<TextClock
android:id="@+id/clock_upper_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start|center_vertical"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="2024-12-24" />
<TextClock
android:id="@+id/clock_lower_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start|center_vertical"
android:textSize="18sp"
tools:text="18:00:00"
app:layout_constraintTop_toBottomOf="@+id/clock_upper_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/AlertDialogCustom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/dialog_create_widget_panel_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:importantForAutofill="no"
android:inputType="text"
tools:ignore="LabelFor" />
</LinearLayout>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/AlertDialogCustom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/dialog_rename_widget_panel_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:importantForAutofill="no"
android:inputType="text"
tools:ignore="LabelFor" />
</LinearLayout>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/dialog_select_widget_panel_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dialog_select_widget_panel_info_no_panels"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dialog_select_widget_panel_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_weight="1" />
</LinearLayout>

View file

@ -10,29 +10,10 @@
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context=".ui.HomeActivity"> tools:context=".ui.HomeActivity">
<TextClock <de.jrpie.android.launcher.ui.widgets.WidgetContainerView
android:id="@+id/home_upper_view" android:id="@+id/home_widget_container"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent" />
android:gravity="start|center_vertical"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45"
tools:text="2024-12-24" />
<TextClock
android:id="@+id/home_lower_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start|center_vertical"
android:textSize="18sp"
tools:text="18:00:00"
app:layout_constraintTop_toBottomOf="@+id/home_upper_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- only shown when µLauncher settings can't be reached by a gesture --> <!-- only shown when µLauncher settings can't be reached by a gesture -->
<ImageView <ImageView

View file

@ -27,6 +27,8 @@
android:text="" android:text=""
android:textSize="11sp" android:textSize="11sp"
tools:text="@string/app_name" tools:text="@string/app_name"
android:ellipsize="end"
android:lines="1"
app:layout_constraintTop_toBottomOf="@id/list_apps_row_icon" app:layout_constraintTop_toBottomOf="@id/list_apps_row_icon"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/list_widget_panels_row_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15sp">
<TextView
android:id="@+id/list_widget_panels_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60sp"
android:layout_marginEnd="5dp"
android:gravity="start"
android:text=""
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list_apps_row_container"
android:background="@color/cardview_dark_background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15sp">
<ImageView
android:id="@+id/list_widgets_header_icon"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:src="@mipmap/ic_launcher_round"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/list_widgets_header_app_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20sp"
android:gravity="start"
android:text=""
android:textSize="20sp"
tools:text="some widget"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/list_widgets_header_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list_apps_row_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15sp">
<ImageView
android:id="@+id/list_widgets_row_icon"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:src="@mipmap/ic_launcher_round"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/list_widgets_row_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10sp"
android:layout_marginEnd="10sp"
android:gravity="start"
android:text=""
android:textSize="20sp"
tools:text="some widget"
app:layout_constraintStart_toEndOf="@id/list_widgets_row_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/list_widgets_row_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10sp"
android:gravity="start"
android:text=""
android:textSize="12sp"
app:layout_constraintStart_toStartOf="@+id/list_widgets_row_name"
app:layout_constraintTop_toBottomOf="@+id/list_widgets_row_name"
tools:text="a longer description of the widget" />
<ImageView
android:id="@+id/list_widgets_row_preview"
android:layout_width="0dp"
android:maxHeight="100dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:layout_height="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/list_widgets_row_description"
tools:src="@mipmap/ic_launcher_round"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -43,13 +43,15 @@
android:id="@+id/settings_actions_row_button_choose" android:id="@+id/settings_actions_row_button_choose"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:maxWidth="100dp"
android:text="@string/settings_apps_choose" android:text="@string/settings_apps_choose"
android:textAllCaps="false" android:textAllCaps="false"
android:visibility="invisible" android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
/>
<ImageView <ImageView
android:id="@+id/settings_actions_row_icon_img" android:id="@+id/settings_actions_row_icon_img"

View file

@ -0,0 +1,264 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="alert_cant_open_title">لا يمكن فتح التطبيق</string>
<string name="alert_cant_open_message">هل تريد تعديل اعداداته؟</string>
<string name="toast_cant_open_message">افتح الاعدادات لاختيار أمر لهذه الإيماءة</string>
<string name="settings_title">الاعدادات</string>
<string name="settings_tab_actions">الأوامر</string>
<string name="settings_tab_launcher">المشغل</string>
<string name="settings_tab_meta">بيانات</string>
<string name="settings_gesture_back">رجوع</string>
<string name="settings_gesture_up">أعلى</string>
<string name="settings_gesture_double_up">لأعلى بأصبعين</string>
<string name="settings_gesture_description_double_up">اسحب لأعلى بأصبعين</string>
<string name="settings_gesture_description_tap_up">أنقر ثم اسحب لأعلى</string>
<string name="settings_gesture_description_back">اضغط على زر الرجوع</string>
<string name="settings_gesture_description_up">اسحب لأعلى</string>
<string name="settings_gesture_tap_up">نقرة + أعلى</string>
<string name="settings_gesture_down">أسفل</string>
<string name="settings_gesture_description_down">اسحب لأسفل</string>
<string name="settings_gesture_tap_down">نقرة + لأسفل</string>
<string name="settings_gesture_double_down">لأسفل بأصبعين</string>
<string name="settings_gesture_left">يسار</string>
<string name="settings_gesture_description_left">اسحب من اليسار</string>
<string name="settings_gesture_tap_left">نقرة + يسار</string>
<string name="settings_gesture_description_tap_left">أنقر ثم اسحب إلى اليسار</string>
<string name="settings_gesture_double_left">يسار بأصبعين</string>
<string name="settings_gesture_right">يمين</string>
<string name="settings_gesture_description_right">اسحب إلى اليمين</string>
<string name="settings_gesture_tap_right">نقرة + يمين</string>
<string name="settings_gesture_description_tap_right">أنقر ثم اسحب إلى اليمين</string>
<string name="settings_gesture_double_right">يمين بأصبعين</string>
<string name="settings_gesture_description_double_right">اسحب إلى اليمين بأصبعين</string>
<string name="settings_gesture_right_top_edge">يمين (في الأعلى)</string>
<string name="settings_gesture_right_bottom_edge">يمين (في الأسفل)</string>
<string name="settings_gesture_description_right_bottom_edge">اسحب إلى اليمين من أسفل الشاشة</string>
<string name="settings_gesture_left_top_edge">يسار (في الأعلى)</string>
<string name="settings_gesture_description_left_top_edge">اسحب إلى اليسار من أعلى الشاشة</string>
<string name="settings_gesture_up_left_edge">أعلى (الحافة اليسرى)</string>
<string name="settings_gesture_description_up_left_edge">اسحب إلى الأعلى من حافة الشاشة اليسرى</string>
<string name="settings_gesture_up_right_edge">أعلى (الحافة اليمنى)</string>
<string name="settings_gesture_down_left_edge">أسفل (الحافة اليسرى)</string>
<string name="settings_gesture_description_down_left_edge">اسحب إلى الأسفل من حافة الشاشة اليسرى</string>
<string name="settings_gesture_down_right_edge">أسفل (الحافة اليمنى)</string>
<string name="settings_gesture_description_swipe_larger">أعلى اليسار -&gt; وسط اليمين -&gt; أسفل اليسار</string>
<string name="settings_gesture_description_swipe_larger_reverse">أسفل اليسار -&gt; وسط اليمين -&gt; أعلى اليسار</string>
<string name="settings_gesture_description_swipe_smaller">أعلى اليمين -&gt; وسط اليسار -&gt; أسفل اليمين</string>
<string name="settings_gesture_description_swipe_v">أعلى اليسار -&gt; الأسفل الوسط -&gt; أعلى اليمين</string>
<string name="settings_gesture_swipe_v_reverse">V (معكوس)</string>
<string name="settings_gesture_description_swipe_v_reverse">أعلى اليمين -&gt; الأسفل الوسط -&gt; أعلى اليسار</string>
<string name="settings_gesture_description_swipe_lambda">أسفل اليسار -&gt; أعلى الوسط -&gt; أسفل اليمين</string>
<string name="settings_gesture_swipe_lambda_reverse">Λ (معكوس)</string>
<string name="settings_gesture_vol_up">زر رفع الصوت</string>
<string name="settings_gesture_description_vol_up">اضغط على زر رفع الصوت</string>
<string name="settings_gesture_vol_down">زر خفض الصوت</string>
<string name="settings_gesture_description_vol_down">اضغط على زر خفض الصوت</string>
<string name="settings_gesture_double_click">نقرة مزدوجة</string>
<string name="settings_gesture_long_click">نقرة مطولة</string>
<string name="settings_gesture_description_long_click">أنقر مطولًا في مكان فارغ على الشاشة</string>
<string name="settings_gesture_date">التاريخ</string>
<string name="settings_gesture_description_date">أنقر على التاريخ</string>
<string name="settings_gesture_time">الوقت</string>
<string name="settings_gesture_description_time">أنقر على الوقت</string>
<string name="settings_apps_choose">اختر تطبيق</string>
<string name="settings_apps_install">ثبت تطبيقات</string>
<string name="settings_launcher_section_appearance">المظهر</string>
<string name="settings_theme_color_theme">السمة</string>
<string name="settings_gesture_swipe_larger"><![CDATA[>]]></string>
<string name="settings_gesture_swipe_larger_reverse"><![CDATA[> (معكوس)]]></string>
<string name="settings_gesture_swipe_smaller"><![CDATA[<]]></string>
<string name="settings_gesture_swipe_smaller_reverse"><![CDATA[< (Reverse)]]></string>
<string name="settings_gesture_swipe_v">V</string>
<string name="settings_gesture_swipe_lambda">Λ</string>
<string name="settings_theme_color_theme_item_dark">داكن</string>
<string name="settings_theme_color_theme_item_light">فاتح</string>
<string name="settings_theme_color_theme_item_dynamic">متغير</string>
<string name="settings_theme_text_shadow">ظل النص</string>
<string name="settings_theme_background_item_transparent">شفاف</string>
<string name="settings_theme_background_item_dim">مظلل</string>
<string name="settings_theme_background_item_blur">مُموه</string>
<string name="settings_theme_background_item_solid">لون ثابت</string>
<string name="settings_theme_font">الخط</string>
<string name="settings_theme_font_item_system_default">خط النظام</string>
<string name="settings_theme_font_item_sans_serif">بدون تذييل</string>
<string name="settings_theme_font_item_serif">مذيل</string>
<string name="settings_theme_font_item_monospace">أحادي المسافة</string>
<string name="settings_theme_monochrome_icons">أيقونات تطبيقات أحادية اللون</string>
<string name="settings_clock_color">اللون</string>
<string name="settings_clock_time_visible">أظهر الوقت</string>
<string name="settings_clock_date_visible">أظهر التاريخ</string>
<string name="settings_clock_localized">استخدم تنسيق التاريخ المحلي</string>
<string name="settings_clock_flip_date_time">إقلب مكان التاريخ مع الوقت</string>
<string name="settings_theme_wallpaper">اختر خلفية</string>
<string name="settings_launcher_section_display">العرض</string>
<string name="settings_display_screen_timeout_disabled">حافظ على بقاء الشاشة قيد التشغيل</string>
<string name="settings_display_hide_status_bar">إخفِ شريط الحالة</string>
<string name="settings_display_rotate_screen">تدوير الشاشة</string>
<string name="settings_launcher_section_functionality">الوظائف</string>
<string name="settings_enabled_gestures_double_swipe">أوامر السحب بأصبعين</string>
<string name="settings_enabled_gestures_double_swipe_summary">اسحب باستخدام أصبعين</string>
<string name="settings_enabled_gestures_edge_swipe">أوامر السحب من الحواف</string>
<string name="settings_enabled_gestures_edge_swipe_edge_width">عرض الحواف</string>
<string name="settings_functionality_auto_launch">إظهار نتائج البحث</string>
<string name="settings_functionality_auto_launch_summary">اضغط مسافة لتعطيل هذه الميزة مؤقتًا</string>
<string name="settings_functionality_search_web">ابحث في الويب</string>
<string name="settings_functionality_auto_keyboard">أظهر لوحة المفاتيح عند البحث</string>
<string name="settings_launcher_sensitivity">الحساسية</string>
<string name="settings_launcher_section_apps">التطبيقات</string>
<string name="settings_apps_hidden">التطبيقات المخفية</string>
<string name="settings_launcher_section_date_time"><![CDATA[Date & time]]></string>
<string name="settings_apps_hide_private_space_apps">إخفِ المساحة الخاصة من قائمة التطبيقات</string>
<string name="settings_list_layout">تخطيط قائمة التطبيقات</string>
<string name="settings_list_layout_item_default">الافتراضي</string>
<string name="settings_list_layout_item_text">نص</string>
<string name="settings_list_layout_item_grid">شبكة</string>
<string name="settings_general_choose_home_screen">تعيين μauncher كشاشة المنزل</string>
<string name="settings_meta_cant_select_launcher">معلومات التطبيق</string>
<string name="settings_meta_reset">إعادة تعيين الإعدادات</string>
<string name="settings_meta_reset_confirm">أنت على وشك تجاهل كل تفضيلاتك، هل تريد الإكمال؟</string>
<string name="settings_meta_view_code">عرض شيفرة المصدر</string>
<string name="settings_meta_report_bug">الإبلاغ عن خطأ</string>
<string name="dialog_report_bug_button_clipboard">النسخ إلى الحافظة</string>
<string name="dialog_report_bug_security_info">يرجى عدم الإبلاغ عن الثغرات الأمنية علنًا على Github ، استخدم ما يلي بدلاً من ذلك:</string>
<string name="dialog_report_bug_button_security">الإبلاغ عن ثغرة أمنية</string>
<string name="dialog_report_bug_create_report">إنشاء تقرير</string>
<string name="settings_meta_fork_contact">اتصل بمطور النسخة</string>
<string name="settings_meta_join_chat">انضم إلى دردشة μauncher</string>
<string name="settings_meta_donate">تبرع</string>
<string name="settings_meta_privacy">سياسة الخصوصية</string>
<string name="list_title_view">كل التطبيقات</string>
<string name="list_title_favorite">التطبيقات المفضلة</string>
<string name="list_title_hidden">التطبيقات المخفية</string>
<string name="list_title_private_space">المساحة الخاصة</string>
<string name="list_title_pick">اختر تطبيق</string>
<string name="list_tab_app">التطبيقات</string>
<string name="list_tab_other">أخرى</string>
<string name="list_app_delete">إلغاء التثبيت</string>
<string name="list_app_favorite_remove">إزالة من المفضلة</string>
<string name="list_app_hidden_add">إخفِ</string>
<string name="list_app_hidden_remove">أظهر</string>
<string name="list_app_rename">إعادة التسمية</string>
<string name="list_apps_search_hint">بحث</string>
<string name="list_apps_search_hint_no_auto_launch">بحث (بدون تشغيل تلقائي)</string>
<string name="list_other_settings">اعدادات التطبيق</string>
<string name="list_other_list">درج التطبيقات</string>
<string name="list_other_list_private_space">المساحة الخاصة</string>
<string name="list_other_toggle_private_space_lock">تبديل قفل المساحة الخاصة</string>
<string name="list_other_volume_up">ارفع الصوت</string>
<string name="settings_meta_discord">إنضم إلى مجموعة discord!</string>
<string name="list_other_volume_adjust">ضبط مستوى الصوت</string>
<string name="list_other_track_previous">الموسيقى: السابق</string>
<string name="list_other_track_play_pause">الموسيقى: تشغيل / ايقاف مؤقت</string>
<string name="list_other_recent_apps">التطبيقات الحديثة</string>
<string name="list_other_nop">لا تفعل شيئًا</string>
<string name="list_other_lock_screen">قفل الشاشة</string>
<string name="list_other_torch">تبديل الفلاش</string>
<string name="list_other_launch_other_launcher">شغل شاشة منزل أخرى</string>
<string name="pin_shortcut_title">أضف اختصارًا</string>
<string name="pin_shortcut_button_bind">اربط بإيماءة</string>
<string name="tutorial_title">درس تعليمي</string>
<string name="tutorial_start_text">👋\n\nخذ بضع ثوان لمعرفة كيفية استخدام هذا المشغل!</string>
<string name="tutorial_concept_title">المفهوم</string>
<string name="tutorial_concept_text_2">إنه برنامج مجاني (ترخيص MIT)!\nتأكد من مراجعة المستودع!</string>
<string name="tutorial_concept_label_version">النسخة</string>
<string name="tutorial_usage_title">الاستخدام</string>
<string name="tutorial_usage_text">تحتوي شاشتك الرئيسية على التاريخ والوقت المحليين. لا الهاء.</string>
<string name="tutorial_app_list_title">كل التطبيقات</string>
<string name="tutorial_app_list_text_2">بمجرد تطابق تطبيق واحد فقط، يتم تشغيله تلقائيًا.\nيمكن تعطيل ذلك عن طريق اضافة مساحة في بداية استعلام.</string>
<string name="tutorial_setup_title">الإعداد</string>
<string name="tutorial_setup_text">اخترنا بعض التطبيقات الافتراضية لك. يمكنك تغييرها الآن إذا كنت تريد:</string>
<string name="tutorial_setup_text_2">يمكنك أيضًا تغيير اختيارك لاحقًا.</string>
<string name="tutorial_finish_title">لنبدأ!</string>
<string name="tutorial_finish_button">ابدأ</string>
<string name="settings">الإعدادات</string>
<string name="ic_menu_alt">المزيد من الخيارات</string>
<string name="alert_requires_android_m">هذه الوظيفة تتطلب أندرويد 6 أو أحدث.</string>
<string name="alert_requires_android_v">هذه الوظيفة تتطلب أندرويد 15 أو أحدث.</string>
<string name="undo">تراجع</string>
<string name="snackbar_app_hidden">تم إخفاء التطبيق. يمكنك جعله مرئيًا مرة أخرى في الإعدادات.</string>
<string name="list_other_expand_settings_panel">الاعدادات السريعة</string>
<string name="toast_device_admin_not_enabled">يجب أن يكون μlauncher مسؤولًا من أجل قفل الشاشة.</string>
<string name="device_admin_explanation">هذا مطلوب لإجراء شاشة القفل.</string>
<string name="device_admin_description">تمكين إجراء شاشة القفل</string>
<string name="alert_no_torch_found">لم يتم اكتشاف كاميرا مع فلاش.</string>
<string name="alert_torch_access_exception">خطأ: لا يمكن الوصول إلى الفلاش.</string>
<string name="alert_recent_apps_failed">خطأ: فشل في إظهار التطبيقات الحديثة. (إذا قمت للتو بترقية التطبيق ، فحاول تعطيل خدمة الوصول وإعادة تمكينها في إعدادات الهاتف)</string>
<string name="alert_enable_accessibility_failed">خطأ: فشل في تمكين خدمة الوصول.</string>
<string name="toast_accessibility_service_not_enabled">لم يتم تمكين خدمة الوصول إلى μlauncher. يرجى تمكينه في الإعدادات</string>
<string name="toast_private_space_locked">المساحة الخاصة مقفلة</string>
<string name="toast_private_space_unlocked">المساحة الخاصة مفتوحة</string>
<string name="toast_private_space_not_available">المساحة الخاصة غير متوافرة</string>
<string name="tooltip_lock_private_space">قفل المساحة الخاصة</string>
<string name="tooltip_unlock_private_space">فتح المساحة الخاصة</string>
<string name="accessibility_service_name">μLauncher</string>
<string name="screen_lock_method_dialog_title">اختر طريقة القفل</string>
<string name="screen_lock_method_use_accessibility">استخدام خدمة إمكانية الوصول</string>
<string name="screen_lock_method_use_device_admin">استخدم مسؤول الجهاز</string>
<string name="settings_actions_lock_method">اختر طريقة لقفل الشاشة</string>
<string name="dialog_rename_title">اعادة تسمية %1$s</string>
<string name="dialog_select_color_red">أحمر</string>
<string name="dialog_select_color_alpha">شفافية</string>
<string name="dialog_select_color_blue">أزرق</string>
<string name="dialog_select_color_green">أخضر</string>
<string name="dialog_select_color_color_hex">اللون</string>
<string name="dialog_choose_color_title">اختر لونًا</string>
<string name="dialog_consent_accessibility_privileges">أدرك أن هذا سيمنح أذونات كثيرة لـμauncher.</string>
<string name="dialog_consent_accessibility_other_options">أدرك وجود خيارات أخرى (باستخدام أذونات مسؤول الجهاز أو زر الطاقة).</string>
<string name="dialog_consent_accessibility_consent">أوافق لـμlauncher باستخدام خدمة إمكانية الوصول لتوفير الوظائف ليس لها صلة بإمكانية الوصول.</string>
<string name="dialog_consent_accessibility_data_collection">أوافق على أن μlauncher لا يجمع أي بيانات.</string>
<string name="dialog_consent_accessibility_title">يتم تفعيل خدمة إمكانية الوصول</string>
<string name="dialog_consent_accessibility_ok">تفعيل خدمة إمكانية الوصول</string>
<string name="dialog_cancel">إلغاء</string>
<string name="settings_meta_licenses">تراخيص المصادر المفتوحة</string>
<string name="legal_info_title">تراخيص المصادر المفتوحة</string>
<string name="toast_activity_not_found_search_web">لم يتم العثور على تطبيق للتعامل مع البحث.</string>
<string name="toast_activity_not_found_browser">لا يمكن فتح عنوان URL: لم يتم العثور على متصفح.</string>
<string name="dialog_consent_accessibility_text"><![CDATA[أنت على وشك تنشيط خدمة إمكانية الوصول. سيمنح هذا <strong> أذونات كثيرة </strong> إلى التطبيق:
<ul>
<li>قفل الشاشة</li>
<li>التطبيقات الحديثة</li>
</ul>
<strong> لن يقومμlauncher أبدًا بجمع أي بيانات </strong>. على وجه الخصوص ، لا يستخدم μlauncher خدمة إمكانية الوصول لجمع أي بيانات.]]></string>
<string name="settings_gesture_description_tap_down">أنقر ثم اسحب لأسفل</string>
<string name="settings_theme_color_theme_item_default">الافتراضي</string>
<string name="pin_shortcut_switch_visible">أظهر في قائمة التطبيقات</string>
<string name="settings_gesture_description_double_down">اسحب لأسفل بأصبعين</string>
<string name="settings_clock_show_seconds">أظهر الثواني</string>
<string name="dialog_report_bug_title">الإبلاغ عن خطأ</string>
<string name="settings_gesture_description_double_left">اسحب إلى اليسار بأصبعين</string>
<string name="settings_gesture_description_double_click">أنقر مرتين في مكان فارغ على الشاشة</string>
<string name="settings_functionality_search_web_summary">اضغط على زر الرجوع أثناء البحث في قائمة التطبيقات لإظهار البحث على الويب</string>
<string name="settings_gesture_description_right_top_edge">اسحب إلى اليمين من أعلى الشاشة</string>
<string name="settings_gesture_left_bottom_edge">يسار (في الأسفل)</string>
<string name="settings_gesture_description_up_right_edge">اسحب إلى الأعلى من حافة الشاشة اليمنى</string>
<string name="settings_gesture_description_swipe_lambda_reverse">أسفل اليمين -&gt; أعلى الوسط -&gt; أسفل اليسار</string>
<string name="settings_apps_hide_bound_apps">لا تظهر التطبيقات المرتبطة بإيماءة في قائمة التطبيقات</string>
<string name="list_other_list_favorites">درج التطبيقات المفضلة</string>
<string name="list_other_track_next">الموسيقى: التالي</string>
<string name="tutorial_concept_text">تم تصميم μlauncher ليكون فعال، وخالي من الهاء.\n\nلا يحتوي على أي إعلانات ولا يجمع أي بيانات.</string>
<string name="tutorial_finish_text">أنت مستعد للبدء!\n\nآمل أن يكون هذا ذا قيمة كبيرة بالنسبة لك!\n\n- المطورين</string>
<string name="toast_private_space_default_home_screen">يجب أن يكون μlauncher الشاشة الرئيسية الافتراضية للوصول إلى مساحة خاصة.</string>
<string name="settings_gesture_description_left_bottom_edge">اسحب إلى اليسار من أسفل الشاشة</string>
<string name="settings_gesture_description_swipe_smaller_reverse">أسفل اليمين -&gt; وسط اليسار -&gt; أعلى اليمين</string>
<string name="settings_apps_toast_store_not_found">لم يتم العثور على تطبيق المتجر</string>
<string name="settings_display_hide_navigation_bar">إخفِ شريط التنقل</string>
<string name="list_app_info">معلومات التطبيق</string>
<string name="list_app_favorite_add">أضف إلى المفضلة</string>
<string name="list_other_expand_notifications_panel">توسيع لوحة الاشعارات</string>
<string name="tutorial_app_list_text">يمكنك البحث بسرعة من خلال جميع التطبيقات في قائمة التطبيقات.\n\nاسحب لأعلى لفتح القائمة، أو ربطها بإيماءة ما.</string>
<string name="alert_lock_screen_failed">خطأ: فشل في قفل الشاشة. (إذا قمت للتو بترقية التطبيق ، فحاول تعطيل خدمة الوصول وإعادة تمكينها في إعدادات الهاتف)</string>
<string name="settings_gesture_description_down_right_edge">اسحب إلى الأسفل من حافة الشاشة اليمنى</string>
<string name="settings_theme_font_item_serif_monospace">أحادي المسافة مذيل</string>
<string name="settings_list_reverse_layout">عكس قائمة التطبيقات</string>
<string name="alert_cant_expand_status_bar_panel">خطأ: لا يمكن توسيع شريط الحالة. يستخدم هذا الإجراء وظيفة ليست جزءًا من نظام أندرويد. لسوء الحظ ، لا يبدو أنه يعمل على جهازك.</string>
<string name="settings_theme_background">خلفية القوائم</string>
<string name="settings_apps_hide_paused_apps">إخفِ التطبيقات المتوقفة</string>
<string name="settings_meta_show_tutorial">أظهر العرض التعليمي للتطبيق</string>
<string name="dialog_report_bug_info">شكرا لك على المساعدة في تحسين μLauncher!\nيرجى إضافة المعلومات التالية إلى تقرير الأخطاء الخاص بك:</string>
<string name="settings_meta_contact">اتصل بالمطور الأصلي</string>
<string name="list_other_volume_down">اخفض الصوت</string>
<string name="tutorial_usage_text_2">يمكنك تشغيل أهم تطبيقاتك بوسطة إيماءات اللمس أو الضغط على الأزرار.</string>
<string name="settings_enabled_gestures_edge_swipe_summary">اسحب من حواف الشاشة</string>
<string name="toast_lock_screen_not_supported">خطأ: قفل الشاشة باستخدام إمكانية الوصول غير مدعوم على هذا الجهاز. الرجاء استخدام طريقة مسؤول الجهاز بدلاً من ذلك.</string>
<string name="accessibility_service_description">يتيح تعيين μlauncher كخدمة إمكانية الوصول قفل الشاشة وفتح قائمة التطبيقات الحديثة. يرجى ملاحظة أنه يتطلب كمية كبيرة من الأذونات. يجب ألا تمنح مثل هذه الأذونات باستخفاف لأي تطبيق. سوف يستخدم μlauncher خدمة إمكانية الوصول فقط لأداء الإجراءات التالية عند طلب المستخدم: * قفل شاشة * فتح التطبيقات الحديثة μlauncher لن يستخدم أبدًا خدمة إمكانية الوصول لجمع البيانات. يمكنك التحقق من شيفرة المصدر للتأكد. يرجى ملاحظة أنه يمكنك قفل الشاشة من خلال منح أذونات مسؤول الجهاز، لكنها لا تعمل مع بصمات الأصابع وفتح الوجه.</string>
</resources>

View file

@ -14,7 +14,7 @@
- -
--> -->
<string name="settings_title">Einstellungen</string> <string name="settings_title">Einstellungen</string>
<string name="settings_tab_app">Apps</string> <string name="settings_tab_actions">Aktionen</string>
<string name="settings_tab_launcher">Launcher</string> <string name="settings_tab_launcher">Launcher</string>
<string name="settings_tab_meta">Meta</string> <string name="settings_tab_meta">Meta</string>
<!-- <!--
@ -54,9 +54,9 @@
<string name="settings_gesture_description_down_left_edge">An der linken Kante nach unten wischen</string> <string name="settings_gesture_description_down_left_edge">An der linken Kante nach unten wischen</string>
<string name="settings_gesture_down_right_edge">Abwärts (rechts)</string> <string name="settings_gesture_down_right_edge">Abwärts (rechts)</string>
<string name="settings_gesture_description_down_right_edge">An der rechten Kanten nach unten wischen</string> <string name="settings_gesture_description_down_right_edge">An der rechten Kanten nach unten wischen</string>
<string name="settings_gesture_vol_up">Lautstärke +</string> <string name="settings_gesture_vol_up">Lauter-Taste</string>
<string name="settings_gesture_description_vol_up">Die Taste \"Lauter\" drücken</string> <string name="settings_gesture_description_vol_up">Die Taste \"Lauter\" drücken</string>
<string name="settings_gesture_vol_down">Lautstärke -</string> <string name="settings_gesture_vol_down">Leiser-Taste</string>
<string name="settings_gesture_description_vol_down">Die Taste \"Leiser\" drücken</string> <string name="settings_gesture_description_vol_down">Die Taste \"Leiser\" drücken</string>
<string name="settings_gesture_double_click">Doppelklick</string> <string name="settings_gesture_double_click">Doppelklick</string>
<string name="settings_gesture_description_double_click">In einem leeren Bereich doppelt klicken</string> <string name="settings_gesture_description_double_click">In einem leeren Bereich doppelt klicken</string>

View file

@ -16,14 +16,13 @@
--> -->
<string name="alert_cant_open_title">No se pudo abrir la aplicación</string> <string name="alert_cant_open_title">No se pudo abrir la aplicación</string>
<string name="alert_cant_open_message">¿Desea cambiar la configuración?</string> <string name="alert_cant_open_message">¿Desea cambiar la configuración?</string>
<string name="toast_cant_open_message">Abra la configuración para elegir una aplicación para esta acción</string> <string name="toast_cant_open_message">Abra la configuración para elegir una acción para este gesto</string>
<!-- <!--
- -
- Settings - Settings
- -
--> -->
<string name="settings_title">Configuración</string> <string name="settings_title">Configuración</string>
<string name="settings_tab_app">Aplicaciones</string>
<string name="settings_tab_launcher">Launcher</string> <string name="settings_tab_launcher">Launcher</string>
<string name="settings_tab_meta">Meta</string> <string name="settings_tab_meta">Meta</string>
<!-- <!--
@ -31,20 +30,20 @@
- Settings : Apps - Settings : Apps
- -
--> -->
<string name="settings_gesture_up">Deslizar Arriba</string> <string name="settings_gesture_up">Arriba</string>
<string name="settings_gesture_double_up">Doble Arriba</string> <string name="settings_gesture_double_up">Doble Arriba</string>
<string name="settings_gesture_down">Deslizar Abajo</string> <string name="settings_gesture_down">Abajo</string>
<string name="settings_gesture_double_down">Doble Abajo</string> <string name="settings_gesture_double_down">Doble Abajo</string>
<string name="settings_gesture_left">Deslizar Izquierda</string> <string name="settings_gesture_left">Izquierda</string>
<string name="settings_gesture_double_left">Doble Izquierda</string> <string name="settings_gesture_double_left">Doble Izquierda</string>
<string name="settings_gesture_right">Deslizar Derecha</string> <string name="settings_gesture_right">Derecha</string>
<string name="settings_gesture_double_right">Doble Derecha</string> <string name="settings_gesture_double_right">Doble Derecha</string>
<string name="settings_gesture_vol_up">Subir Volumen</string> <string name="settings_gesture_vol_up">Tecla para subir el volumen</string>
<string name="settings_gesture_vol_down">Bajar Volumen</string> <string name="settings_gesture_vol_down">Tecla para bajar el volumen</string>
<string name="settings_gesture_double_click">Doble Click</string> <string name="settings_gesture_double_click">Doble Click</string>
<string name="settings_gesture_long_click">Click Largo</string> <string name="settings_gesture_long_click">Click Largo</string>
<string name="settings_gesture_date">Toca la fecha</string> <string name="settings_gesture_date">Fecha</string>
<string name="settings_gesture_time">Toca el reloj</string> <string name="settings_gesture_time">reloj</string>
<string name="settings_apps_choose">Elegir Aplicación</string> <string name="settings_apps_choose">Elegir Aplicación</string>
<string name="settings_apps_install">Instalar aplicaciones</string> <string name="settings_apps_install">Instalar aplicaciones</string>
<string name="settings_apps_toast_store_not_found">No se encontró la Store</string> <string name="settings_apps_toast_store_not_found">No se encontró la Store</string>
@ -73,7 +72,7 @@
--> -->
<string name="settings_general_choose_home_screen">Seleccionar Launcher</string> <string name="settings_general_choose_home_screen">Seleccionar Launcher</string>
<string name="settings_meta_cant_select_launcher">Información de la aplicación</string> <string name="settings_meta_cant_select_launcher">Información de la aplicación</string>
<string name="settings_meta_show_tutorial">Ver tutorial de Launcher</string> <string name="settings_meta_show_tutorial">Ver el tutorial de µLauncher</string>
<string name="settings_meta_reset">Configuración por defecto</string> <string name="settings_meta_reset">Configuración por defecto</string>
<string name="settings_meta_reset_confirm">Todas sus preferencias se eliminarán. Desea continuar?</string> <string name="settings_meta_reset_confirm">Todas sus preferencias se eliminarán. Desea continuar?</string>
<string name="settings_meta_report_bug">Reportar un error</string> <string name="settings_meta_report_bug">Reportar un error</string>
@ -92,11 +91,11 @@
<string name="list_tab_other">Otros</string> <string name="list_tab_other">Otros</string>
<string name="list_app_delete">Desinstalar</string> <string name="list_app_delete">Desinstalar</string>
<string name="list_app_info">Información</string> <string name="list_app_info">Información</string>
<string name="list_apps_search_hint">Buscar Aplicaciones</string> <string name="list_apps_search_hint">Buscar</string>
<string name="list_other_settings">Configuración de Launcher</string> <string name="list_other_settings">Configuración de μLauncher</string>
<string name="list_other_list">Aplicaciones</string> <string name="list_other_list">Aplicaciones</string>
<string name="list_other_volume_up">Música: Subir</string> <string name="list_other_volume_up">Subir el volumen</string>
<string name="list_other_volume_down">Música: Bajar</string> <string name="list_other_volume_down">Bajar volumen</string>
<string name="list_other_track_next">Música: Siguiente</string> <string name="list_other_track_next">Música: Siguiente</string>
<string name="list_other_track_previous">Música: Anterior</string> <string name="list_other_track_previous">Música: Anterior</string>
<string name="list_other_nop">Nada</string> <string name="list_other_nop">Nada</string>
@ -106,19 +105,214 @@
- -
--> -->
<string name="tutorial_title">Tutorial</string> <string name="tutorial_title">Tutorial</string>
<string name="tutorial_start_text">Tómate unos segundos para aprender a usar este launcher</string> <string name="tutorial_start_text">👋\n\n¡Tómate unos segundos para aprender a utilizar este Launcher!</string>
<string name="tutorial_concept_title">Concepto</string> <string name="tutorial_concept_title">Concepto</string>
<string name="tutorial_concept_text">Launcher está diseñado para ser minimalista, eficiente y libre de distracciones.\n\nEs gratis y libre de anuncios y servicios de rastreo.</string> <string name="tutorial_concept_text">μLauncher está diseñado para ser mínimo, eficiente y libre de distracciones.\n\nNo contiene anuncios ni recopila datos.</string>
<string name="tutorial_concept_text_2">La aplicación es de código abierto (licencia MIT) y está disponible en GitHub!\n\nNo olvides echarle un vistazo al repositorio!</string> <string name="tutorial_concept_text_2">¡Es software libre (licencia MIT)!\n¡No olvides visitar el repositorio!</string>
<string name="tutorial_usage_title">Uso</string> <string name="tutorial_usage_title">Uso</string>
<string name="tutorial_usage_text">Tu pantalla de inicio contiene la fecha y hora local. Sin distracciones.</string> <string name="tutorial_usage_text">Tu pantalla de inicio contiene la fecha y hora local. Sin distracciones.</string>
<string name="tutorial_usage_text_2">Puedes iniciar tus aplicaciones con solo presionar o deslizar una vez. Elige algunas en la siguiente pantalla.</string> <string name="tutorial_usage_text_2">Puede iniciar sus aplicaciones más importantes con gestos táctiles o presionando botones.</string>
<string name="tutorial_setup_title">Puesta a punto</string> <string name="tutorial_setup_title">Puesta a punto</string>
<string name="tutorial_setup_text">Elegimos algunas aplicaciones por defecto para ti, si lo deseas puedes cambiarlas ahora.</string> <string name="tutorial_setup_text">Elegimos algunas aplicaciones predeterminadas para ti. Puedes cambiarlos ahora si lo deseas:</string>
<string name="tutorial_setup_text_2">También puedes cambiar tu selección más tarde.</string> <string name="tutorial_setup_text_2">También puedes cambiar tu selección más tarde.</string>
<string name="tutorial_finish_title">Vamos!</string> <string name="tutorial_finish_title">Vamos!</string>
<string name="tutorial_finish_text">Estás listo para iniciar!\n\n Esperamos que esto te sea de gran ayuda!\n\n- Finn M Glas\n(el desarrollador)</string> <string name="tutorial_finish_text">¡Estás listo para comenzar!\n\n¡Espero que esto sea de gran valor para ti!\n\n- Finn (quien creó Launcher) y Josia (quien hizo algunas mejoras y mantiene la bifurcación μLauncher)</string>
<string name="tutorial_finish_button">Iniciar</string> <string name="tutorial_finish_button">Iniciar</string>
<string name="settings">Configuración</string> <string name="settings">Configuración</string>
<string name="ic_menu_alt">Más opciones</string> <string name="ic_menu_alt">Más opciones</string>
<string name="settings_gesture_back">atrás</string>
<string name="settings_gesture_description_tap_right">Toca + Derecha Toca y desliza hacia la derecha</string>
<string name="settings_gesture_description_left_bottom_edge">Desliza el dedo hacia la izquierda en la parte inferior de la pantalla</string>
<string name="settings_gesture_description_down_right_edge">Desliza hacia abajo en el borde derecho de la pantalla</string>
<string name="settings_gesture_description_back">Botón de retroceso / gesto de retroceso</string>
<string name="settings_gesture_description_up_left_edge">Desliza el dedo hacia arriba en el borde izquierdo de la pantalla</string>
<string name="settings_gesture_description_up_right_edge">Desliza el dedo hacia arriba en el borde derecho de la pantalla</string>
<string name="settings_gesture_description_down_left_edge">Desliza el dedo hacia abajo en el borde izquierdo de la pantalla</string>
<string name="settings_theme_color_theme_item_dynamic">Dinámico</string>
<string name="settings_clock_color">Color</string>
<string name="settings_gesture_description_tap_up">Toca y desliza hacia arriba</string>
<string name="settings_gesture_tap_left">Toque + Izquierda</string>
<string name="settings_gesture_description_right_bottom_edge">Desliza el dedo hacia la derecha en la parte inferior de la pantalla</string>
<string name="settings_gesture_description_left_top_edge">Desliza el dedo hacia la izquierda en la parte superior de la pantalla</string>
<string name="settings_gesture_down_left_edge">Abajo (borde izquierdo)</string>
<string name="settings_gesture_description_vol_up">Presione el botón para subir el volumen</string>
<string name="settings_functionality_auto_launch_summary">Presione la barra espaciadora para desactivar esta función temporalmente.</string>
<string name="settings_launcher_section_apps">Aplicaciones</string>
<string name="settings_gesture_description_swipe_v">Arriba a la izquierda -&gt; Abajo en el medio -&gt; Arriba a la derecha</string>
<string name="settings_functionality_search_web_summary">Presione regresar mientras busca en la lista de aplicaciones para iniciar una búsqueda web.</string>
<string name="alert_torch_access_exception">Error: No se puede acceder a la antorcha.</string>
<string name="settings_theme_background">Fondo (lista de aplicaciones y configuración)</string>
<string name="settings_theme_color_theme">Tema de color</string>
<string name="settings_theme_font">Fuente</string>
<string name="settings_theme_monochrome_icons">Iconos de aplicaciones monocromáticos</string>
<string name="settings_gesture_right_top_edge">Derecha (arriba)</string>
<string name="settings_gesture_right_bottom_edge">Derecha (Abajo)</string>
<string name="settings_gesture_left_top_edge">Izquierda (arriba)</string>
<string name="dialog_consent_accessibility_text"><![CDATA[Está a punto de activar el servicio de accesibilidad. Esto otorgará privilegios de amplio alcance a μLauncher. μLauncher utilizará estos privilegios solo para bloquear la pantalla. μLauncher <strong>nunca recopilará ningún dato</strong>. En particular, μLauncher no utiliza el servicio de accesibilidad para recopilar ningún dato.]]></string>
<string name="accessibility_service_description">Configurar μLauncher como un servicio de accesibilidad le permite bloquear la pantalla. Tenga en cuenta que se requieren permisos excesivos. Nunca debe otorgar dichos permisos a la ligera a ninguna aplicación. μLauncher utilizará el servicio de accesibilidad solo para bloquear la pantalla. Puedes consultar el código fuente para asegurarte. Tenga en cuenta que también se puede bloquear la pantalla otorgando permisos de administrador del dispositivo μLauncher. Sin embargo, ese método no funciona con el desbloqueo mediante huellas dactilares y rostro.</string>
<string name="settings_apps_hide_private_space_apps">Ocultar el espacio privado de la lista de aplicaciones</string>
<string name="settings_list_layout">Diseño de la lista de aplicaciones</string>
<string name="list_title_private_space">Espacio privado</string>
<string name="alert_no_torch_found">No se detectó ninguna cámara con linterna.</string>
<string name="list_other_toggle_private_space_lock">Activar o desactivar el bloqueo del espacio privado</string>
<string name="list_other_torch">Activar o desactivar la antorcha</string>
<string name="settings_apps_hide_paused_apps">Ocultar aplicaciones pausadas</string>
<string name="settings_apps_hidden">Aplicaciones ocultas</string>
<string name="dialog_rename_title">Cambiar el nombre de %1$s</string>
<string name="dialog_cancel">Cancelar</string>
<string name="settings_gesture_swipe_v">V</string>
<string name="dialog_report_bug_title">Informar un error</string>
<string name="list_app_hidden_remove">mostrar</string>
<string name="toast_private_space_default_home_screen">μLauncher debe ser la pantalla de inicio predeterminada para acceder al espacio privado.</string>
<string name="dialog_report_bug_security_info">No informe vulnerabilidades de seguridad públicamente en GitHub, sino utilice lo siguiente:</string>
<string name="dialog_report_bug_button_security">Informar sobre una vulnerabilidad de seguridad</string>
<string name="dialog_report_bug_create_report">Crear informe</string>
<string name="settings_meta_join_chat">Únete al chat de μLauncher</string>
<string name="settings_meta_donate">Donar</string>
<string name="list_other_volume_adjust">Ajustar el volumen</string>
<string name="list_other_expand_notifications_panel">Expandir el panel de notificaciones</string>
<string name="toast_private_space_not_available">El espacio privado no está disponible</string>
<string name="settings_gesture_description_up">Desliza hacia arriba</string>
<string name="settings_gesture_description_double_click">Haga doble clic en un área vacía</string>
<string name="settings_gesture_description_vol_down">Presione el botón para bajar el volumen</string>
<string name="settings_gesture_description_long_click">Haga clic largo en un área vacía</string>
<string name="settings_gesture_description_date">Haga clic en la fecha</string>
<string name="settings_gesture_description_time">Haga clic en el reloj</string>
<string name="settings_clock_time_visible">Mostrar la hora</string>
<string name="settings_theme_text_shadow">Sombra de texto</string>
<string name="settings_display_hide_status_bar">Ocultar la barra de estado</string>
<string name="settings_display_hide_navigation_bar">Ocultar la barra de navegación</string>
<string name="settings_enabled_gestures_double_swipe_summary">Deslizar con dos dedos</string>
<string name="settings_list_layout_item_default">predeterminado</string>
<string name="list_title_favorite">Aplicaciones favoritas</string>
<string name="list_title_hidden">Aplicaciones ocultas</string>
<string name="undo">Deshacer</string>
<string name="dialog_consent_accessibility_consent">Doy mi consentimiento para que μLauncher utilice el servicio de accesibilidad para proporcionar una funcionalidad no relacionada con la accesibilidad.</string>
<string name="list_apps_search_hint_no_auto_launch">Buscar (sin inicio automático)</string>
<string name="dialog_consent_accessibility_privileges">Soy consciente de que esto otorgará privilegios de gran alcance a μLauncher.</string>
<string name="dialog_consent_accessibility_other_options">Soy consciente de que existen otras opciones (utilizando privilegios de administrador del dispositivo o el botón de encendido).</string>
<string name="settings_meta_licenses">Licencias de código abierto</string>
<string name="legal_info_title">Licencias de código abierto</string>
<string name="tutorial_concept_label_version">versión</string>
<string name="tutorial_app_list_title">Todas las aplicaciones</string>
<string name="screen_lock_method_dialog_title">Elija el método para bloquear</string>
<string name="screen_lock_method_dialog_text"><![CDATA[
Elegir método de bloqueo
Hay dos métodos para bloquear la pantalla.
Desafortunadamente, ambos tienen desventajas:<br/><br/>
Administrador del dispositivo
No funciona con desbloqueo por huella dactilar ni reconocimiento facial.
<br/>
<br/>
Servicio de Accesibilidad
Requiere privilegios excesivos.
μLauncher utilizará esos privilegios solo para bloquear la pantalla.
<br/>
(Realmente no deberías confiar en una aplicación aleatoria que acabas de descargar con tal afirmación, pero puedes consultar el <a href=\"https://github.com/jrpie/Launcher\">código fuente</a>).
<br/>
En algunos dispositivos, el PIN de inicio ya no se utilizará para cifrar datos después de activar un servicio de accesibilidad.
Esto se puede <a href="https://issuetracker.google.com/issues/37010136#comment36">reactivar</a> posteriormente.
<br/><br/><br/><br/>
Puede cambiar su selección más tarde en la configuración.
]]></string>
<string name="screen_lock_method_use_accessibility">Utilice el servicio de accesibilidad</string>
<string name="screen_lock_method_use_device_admin">Usar el administrador del dispositivo</string>
<string name="settings_actions_lock_method">Elija el método para bloquear la pantalla</string>
<string name="dialog_select_color_red">Rojo</string>
<string name="dialog_select_color_alpha">alfa</string>
<string name="dialog_select_color_blue">Azul</string>
<string name="dialog_select_color_green">Verde</string>
<string name="settings_theme_font_item_sans_serif">Sans serif</string>
<string name="settings_theme_font_item_serif">Serif</string>
<string name="settings_theme_font_item_monospace">Monoespaciado</string>
<string name="settings_theme_font_item_serif_monospace">Serif monoespaciado</string>
<string name="settings_clock_date_visible">Mostrar la fecha</string>
<string name="settings_clock_localized">Utilice el formato de fecha localizado</string>
<string name="settings_clock_show_seconds">Mostrar segundos</string>
<string name="settings_clock_flip_date_time">Cambiar fecha y hora</string>
<string name="settings_display_rotate_screen">Girar la pantalla</string>
<string name="settings_enabled_gestures_edge_swipe">Acciones de deslizamiento de borde</string>
<string name="settings_enabled_gestures_edge_swipe_summary">Desliza el dedo por el borde de la pantalla</string>
<string name="settings_enabled_gestures_edge_swipe_edge_width">Ancho del borde</string>
<string name="settings_apps_hide_bound_apps">No mostrar aplicaciones que estén vinculadas a un gesto en la lista de aplicaciones</string>
<string name="settings_meta_view_code">Ver el código fuente</string>
<string name="dialog_report_bug_info">¡Gracias por ayudarnos a mejorar μLauncher!\nConsidere agregar la siguiente información a su informe de error:</string>
<string name="dialog_report_bug_button_clipboard">Copiar al portapapeles</string>
<string name="list_app_favorite_add">Añadir a favoritos</string>
<string name="list_app_favorite_remove">Eliminar de favoritos</string>
<string name="list_app_hidden_add">Esconder</string>
<string name="list_app_rename">Renombrar</string>
<string name="list_other_list_favorites">Aplicaciones favoritas</string>
<string name="list_other_list_private_space">Espacio privado</string>
<string name="tutorial_app_list_text">Puede buscar rápidamente entre todas las aplicaciones en la lista de aplicaciones.\n\nDesliza hacia arriba para abrirlo o asigne un gesto diferente.</string>
<string name="tutorial_app_list_text_2">Una vez que sólo coincide una aplicación, se inicia automáticamente.\nEsto se puede desactivar anteponiendo un espacio a la consulta.</string>
<string name="alert_cant_expand_status_bar_panel">Error: No se puede expandir la barra de estado. Esta acción utiliza una funcionalidad que no forma parte de la API de Android publicada. Lamentablemente, no parece funcionar en su dispositivo.</string>
<string name="alert_requires_android_m">Esta funcionalidad requiere Android 6 o posterior.</string>
<string name="alert_requires_android_v">Esta funcionalidad requiere Android 15 o posterior.</string>
<string name="snackbar_app_hidden">Aplicación oculta. Puedes hacerlo visible nuevamente en la configuración.</string>
<string name="list_other_expand_settings_panel">Configuración rápida</string>
<string name="toast_device_admin_not_enabled">μLauncher debe ser administrador del dispositivo para poder bloquear la pantalla.</string>
<string name="device_admin_explanation">Esto es necesario para la acción de la pantalla de bloqueo.</string>
<string name="device_admin_description">Habilitar la acción de bloqueo de pantalla</string>
<string name="alert_lock_screen_failed">Error: Error al bloquear la pantalla. (Si acaba de actualizar la aplicación, intente deshabilitar y volver a habilitar el servicio de accesibilidad en la configuración del teléfono)</string>
<string name="toast_accessibility_service_not_enabled">El servicio de accesibilidad de μLauncher no está habilitado. Por favor, habilítelo en la configuración</string>
<string name="toast_private_space_locked">Espacio privado bloqueado</string>
<string name="toast_private_space_unlocked">Espacio privado desbloqueado</string>
<string name="tooltip_lock_private_space">Bloquear el espacio privado</string>
<string name="tooltip_unlock_private_space">Desbloquear espacio privado</string>
<string name="toast_lock_screen_not_supported">Error: El bloqueo de la pantalla mediante accesibilidad no es compatible con este dispositivo. En su lugar, utilice el administrador del dispositivo.</string>
<string name="accessibility_service_name">μLauncher - pantalla de bloqueo</string>
<string name="dialog_select_color_color_hex">Color</string>
<string name="dialog_choose_color_title">Elige el color</string>
<string name="dialog_consent_accessibility_data_collection">Doy mi consentimiento para que μLauncher no recopile ningún dato.</string>
<string name="dialog_consent_accessibility_title">Activación del servicio de accesibilidad</string>
<string name="dialog_consent_accessibility_ok">Activar el servicio de accesibilidad</string>
<string name="toast_activity_not_found_search_web">No se encontró ninguna aplicación para gestionar la búsqueda.</string>
<string name="toast_activity_not_found_browser">No se puede abrir la URL: no se encontró ningún navegador.</string>
<string name="settings_tab_actions">Acciones</string>
<string name="settings_gesture_tap_up">Toca + Arriba</string>
<string name="settings_gesture_description_double_up">Desliza hacia arriba con dos dedos</string>
<string name="settings_gesture_description_down">Desliza hacia abajo</string>
<string name="settings_gesture_tap_down">Toque + Abajo</string>
<string name="settings_gesture_description_tap_down">Toca y desliza hacia abajo</string>
<string name="settings_gesture_description_double_down">Desliza hacia abajo con dos dedos</string>
<string name="settings_gesture_description_left">Desliza hacia la izquierda</string>
<string name="settings_gesture_description_tap_left">Toca y desliza hacia la izquierda</string>
<string name="settings_gesture_description_double_left">Desliza dos dedos hacia la izquierda</string>
<string name="settings_gesture_description_right">Desliza hacia la derecha</string>
<string name="settings_gesture_tap_right">Toque + Derecha</string>
<string name="settings_gesture_description_double_right">Desliza con dos dedos hacia la derecha</string>
<string name="settings_gesture_description_right_top_edge">Desliza el dedo hacia la derecha en la parte superior de la pantalla</string>
<string name="settings_gesture_left_bottom_edge">Izquierda (Abajo)</string>
<string name="settings_gesture_up_left_edge">Arriba (borde izquierdo)</string>
<string name="settings_gesture_up_right_edge">Arriba (borde derecho)</string>
<string name="settings_gesture_down_right_edge">Abajo (borde derecho)</string>
<string name="settings_gesture_description_swipe_larger">Arriba a la izquierda -&gt; centro a la derecha -&gt; abajo a la izquierda</string>
<string name="settings_gesture_description_swipe_larger_reverse">Abajo a la izquierda -&gt; centro a la derecha -&gt; arriba a la izquierda</string>
<string name="settings_gesture_description_swipe_smaller">Arriba a la derecha -&gt; centro a la izquierda -&gt; abajo a la derecha</string>
<string name="settings_gesture_description_swipe_smaller_reverse">Abajo a la derecha -&gt; centro a la izquierda -&gt; arriba a la derecha</string>
<string name="settings_gesture_swipe_v_reverse">V (Reversa)</string>
<string name="settings_gesture_description_swipe_v_reverse">Arriba a la derecha -&gt; Abajo en el medio -&gt; Arriba a la izquierda</string>
<string name="settings_gesture_swipe_lambda">Λ</string>
<string name="settings_gesture_description_swipe_lambda">Abajo a la izquierda -&gt; arriba en el medio -&gt; abajo a la derecha</string>
<string name="settings_gesture_swipe_lambda_reverse">Λ (Inverso)</string>
<string name="settings_gesture_description_swipe_lambda_reverse">Abajo a la derecha -&gt; arriba en el medio -&gt; abajo a la izquierda</string>
<string name="settings_theme_background_item_dim">Atenuación</string>
<string name="settings_theme_background_item_solid">Sólido</string>
<string name="settings_theme_font_item_system_default">Valor predeterminado del sistema</string>
<string name="settings_theme_background_item_transparent">Transparente</string>
<string name="settings_theme_background_item_blur">Difuminar</string>
<string name="settings_functionality_search_web">Buscar en la web</string>
<string name="settings_list_layout_item_text">texto</string>
<string name="settings_list_layout_item_grid">Red</string>
<string name="list_other_track_play_pause">Música: Reproducir / Pausa</string>
<string name="list_other_lock_screen">Pantalla de bloqueo</string>
<string name="pin_shortcut_title">Agregar acceso directo</string>
<string name="pin_shortcut_button_bind">Vincular al gesto</string>
<string name="pin_shortcut_switch_visible">Mostrar en la lista de aplicaciones</string>
<string name="settings_list_reverse_layout">Invertir la lista de aplicaciones</string>
</resources> </resources>

View file

@ -14,7 +14,6 @@
- -
--> -->
<string name="settings_title">Réglages</string> <string name="settings_title">Réglages</string>
<string name="settings_tab_app">Applications</string>
<string name="settings_tab_launcher">Launcher</string> <string name="settings_tab_launcher">Launcher</string>
<string name="settings_tab_meta">Meta</string> <string name="settings_tab_meta">Meta</string>
<!-- <!--

View file

@ -2,7 +2,7 @@
<resources> <resources>
<string name="settings_gesture_description_right_bottom_edge">Scorri verso destra sul bordo inferiore dello schermo</string> <string name="settings_gesture_description_right_bottom_edge">Scorri verso destra sul bordo inferiore dello schermo</string>
<string name="settings_launcher_section_appearance">Aspetto</string> <string name="settings_launcher_section_appearance">Aspetto</string>
<string name="settings_apps_choose">Scegliere l\'applicazione</string> <string name="settings_apps_choose">Scegliere</string>
<string name="settings_theme_color_theme">Tema</string> <string name="settings_theme_color_theme">Tema</string>
<string name="tutorial_concept_text">Questo launcher è progettato per essere minimale, efficiente e privo di distrazioni. Non contiene pagamenti, pubblicità o servizi di tracciamento.</string> <string name="tutorial_concept_text">Questo launcher è progettato per essere minimale, efficiente e privo di distrazioni. Non contiene pagamenti, pubblicità o servizi di tracciamento.</string>
<string name="settings_theme_color_theme_item_default">Predefinito</string> <string name="settings_theme_color_theme_item_default">Predefinito</string>
@ -38,7 +38,6 @@
<string name="alert_cant_open_message">Desideri modificare le impostazioni?</string> <string name="alert_cant_open_message">Desideri modificare le impostazioni?</string>
<string name="toast_cant_open_message">Apri le impostazioni per abbinare un\'azione a questo gesto</string> <string name="toast_cant_open_message">Apri le impostazioni per abbinare un\'azione a questo gesto</string>
<string name="settings_title">Impostazioni</string> <string name="settings_title">Impostazioni</string>
<string name="settings_tab_app">Applicazioni</string>
<string name="settings_tab_launcher">Launcher</string> <string name="settings_tab_launcher">Launcher</string>
<string name="settings_tab_meta">Meta</string> <string name="settings_tab_meta">Meta</string>
<string name="settings_gesture_description_double_down">Scorri verso il basso con due dita</string> <string name="settings_gesture_description_double_down">Scorri verso il basso con due dita</string>

View file

@ -3,7 +3,6 @@
<string name="alert_cant_open_title">アプリを開けません</string> <string name="alert_cant_open_title">アプリを開けません</string>
<string name="alert_cant_open_message">設定を変更しますか?</string> <string name="alert_cant_open_message">設定を変更しますか?</string>
<string name="settings_title">設定</string> <string name="settings_title">設定</string>
<string name="settings_tab_app">アプリ</string>
<string name="settings_tab_launcher">ランチャー</string> <string name="settings_tab_launcher">ランチャー</string>
<string name="settings_tab_meta">その他</string> <string name="settings_tab_meta">その他</string>
<string name="toast_cant_open_message">このジェスチャのアクションを選択するには設定を開きます</string> <string name="toast_cant_open_message">このジェスチャのアクションを選択するには設定を開きます</string>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="alert_cant_open_message">Norite pakeisti nustatymus?</string>
<string name="settings_title">Nustatymai</string>
<string name="settings_tab_actions">Veiksmai</string>
<string name="settings_tab_launcher">Paleidimo programėlė</string>
<string name="settings_tab_meta">Apie</string>
<string name="settings_gesture_back">Atgal</string>
<string name="settings_gesture_description_back">Grįžimo mygtukas / grįžimo gestas</string>
<string name="settings_gesture_description_up">Perbraukimas aukštyn</string>
<string name="settings_gesture_tap_up">Bakstelėkite + aukštyn</string>
<string name="alert_cant_open_title">Nepavyksta paleisti programėlės</string>
<string name="toast_cant_open_message">Atidarykite nustatymus norėdami pasirinkti šio gesto veiksmą</string>
<string name="settings_gesture_up">Aukštyn</string>
<string name="settings_gesture_description_tap_up">Bakstelėjimas ir perbraukimas aukštyn</string>
</resources>

View file

@ -14,7 +14,6 @@
- -
--> -->
<string name="settings_title">Configurações</string> <string name="settings_title">Configurações</string>
<string name="settings_tab_app">Apps</string>
<string name="settings_tab_launcher">Launcher</string> <string name="settings_tab_launcher">Launcher</string>
<string name="settings_tab_meta">Meta</string> <string name="settings_tab_meta">Meta</string>
<!-- <!--
@ -38,8 +37,8 @@
<string name="settings_gesture_up_right_edge">Para cima (borda direita)</string> <string name="settings_gesture_up_right_edge">Para cima (borda direita)</string>
<string name="settings_gesture_down_left_edge">Para baixo (borda esquerda)</string> <string name="settings_gesture_down_left_edge">Para baixo (borda esquerda)</string>
<string name="settings_gesture_down_right_edge">Para baixo (borda direita)</string> <string name="settings_gesture_down_right_edge">Para baixo (borda direita)</string>
<string name="settings_gesture_vol_up">Aumento de volume</string> <string name="settings_gesture_vol_up">Botão de aumentar volume</string>
<string name="settings_gesture_vol_down">Diminuição de volume</string> <string name="settings_gesture_vol_down">Botão de diminuir volume</string>
<string name="settings_gesture_double_click">Toque duplo</string> <string name="settings_gesture_double_click">Toque duplo</string>
<string name="settings_gesture_long_click">Toque longo</string> <string name="settings_gesture_long_click">Toque longo</string>
<string name="settings_gesture_date">Data</string> <string name="settings_gesture_date">Data</string>
@ -77,7 +76,7 @@
--> -->
<string name="settings_general_choose_home_screen">Definir o μLauncher como tela inicial</string> <string name="settings_general_choose_home_screen">Definir o μLauncher como tela inicial</string>
<string name="settings_meta_cant_select_launcher">Informações do aplicativo</string> <string name="settings_meta_cant_select_launcher">Informações do aplicativo</string>
<string name="settings_meta_show_tutorial">Ver tutorial do launcher</string> <string name="settings_meta_show_tutorial">Ver tutorial do µLauncher</string>
<string name="settings_meta_reset">Redefinir configuraçãos</string> <string name="settings_meta_reset">Redefinir configuraçãos</string>
<string name="settings_meta_reset_confirm">Você vai descartar todas as suas preferências. Continuar?</string> <string name="settings_meta_reset_confirm">Você vai descartar todas as suas preferências. Continuar?</string>
<string name="settings_meta_report_bug">Reportar um bug</string> <string name="settings_meta_report_bug">Reportar um bug</string>
@ -97,10 +96,10 @@
<string name="list_app_delete">Desinstalar</string> <string name="list_app_delete">Desinstalar</string>
<string name="list_app_info">Informações do aplicativo</string> <string name="list_app_info">Informações do aplicativo</string>
<string name="list_apps_search_hint">Busque</string> <string name="list_apps_search_hint">Busque</string>
<string name="list_other_settings">Configurações do µLauncher</string> <string name="list_other_settings">Configurações do μLauncher</string>
<string name="list_other_list">Todos os apps</string> <string name="list_other_list">Todos os apps</string>
<string name="list_other_volume_up">Música: Mais alto</string> <string name="list_other_volume_up">Aumentar volume</string>
<string name="list_other_volume_down">Música: Mais silencioso</string> <string name="list_other_volume_down">Diminuir volume</string>
<string name="list_other_track_next">Música: Próximo</string> <string name="list_other_track_next">Música: Próximo</string>
<string name="list_other_track_previous">Música: Anterior</string> <string name="list_other_track_previous">Música: Anterior</string>
<string name="list_other_nop">Não faça nada</string> <string name="list_other_nop">Não faça nada</string>
@ -110,18 +109,18 @@
- -
--> -->
<string name="tutorial_title">Tutorial</string> <string name="tutorial_title">Tutorial</string>
<string name="tutorial_start_text">Tire alguns segundos para aprender a usar este Launcher!</string> <string name="tutorial_start_text">👋\n\nTire alguns segundos para aprender a usar este Launcher!</string>
<string name="tutorial_concept_title">Conceito</string> <string name="tutorial_concept_title">Conceito</string>
<string name="tutorial_concept_text">O Launcher foi criado para ser minimalista, eficiente e livre de distrações. Ele é livre de pagamentos, anúncios e serviços de rastreamento.</string> <string name="tutorial_concept_text">O μLauncher foi criado para ser minimalista, eficiente e livre de distrações. \n\n\nNão contém anúncios e não coleta dados.</string>
<string name="tutorial_concept_text_2">O app é de código aberto (licença MIT) e está disponível no GitHub! Não deixe de conferir o repositório!</string> <string name="tutorial_concept_text_2">É um software livre (sob licença MIT)!\nNão deixe de conferir o repositório!</string>
<string name="tutorial_usage_title">Uso</string> <string name="tutorial_usage_title">Uso</string>
<string name="tutorial_usage_text">Sua tela inicial contém a data e hora local. Sem distrações.</string> <string name="tutorial_usage_text">Sua tela inicial contém a data e hora local. Sem distrações.</string>
<string name="tutorial_usage_text_2">Você pode iniciar seus aplicativos com um gesto único ou apertando um botão. Escolha algumas ações no próximo slide.</string> <string name="tutorial_usage_text_2">Você pode iniciar seus aplicativos com gestos de toque ou apertando um botão.</string>
<string name="tutorial_setup_title">Configurar</string> <string name="tutorial_setup_title">Configurar</string>
<string name="tutorial_setup_text">Selecionamos alguns aplicativos padrão para você. Se quiser, você pode alterá-los agora:</string> <string name="tutorial_setup_text">Selecionamos alguns aplicativos padrão para você. Se quiser, você pode alterá-los agora:</string>
<string name="tutorial_setup_text_2">Você pode alterar suas escolhas mais tarde.</string> <string name="tutorial_setup_text_2">Você pode alterar suas escolhas mais tarde.</string>
<string name="tutorial_finish_title">Vamos lá!</string> <string name="tutorial_finish_title">Vamos lá!</string>
<string name="tutorial_finish_text">Tá todo pronto para começar! Espero que isso seja de grande valor para você! - Finn (que criou o Launcher) \te Josia (que fez algumas melhorias e tb mantém o fork do μLauncher)</string> <string name="tutorial_finish_text">Tá todo pronto para começar!\n\nEspero que isso seja de grande valor para você!\n\n- Finn (que criou o Launcher) e Josia (que fez algumas melhorias e tb mantém o fork do μLauncher)</string>
<string name="tutorial_finish_button">Começar</string> <string name="tutorial_finish_button">Começar</string>
<string name="settings">Configurações</string> <string name="settings">Configurações</string>
<string name="ic_menu_alt">Mais opções</string> <string name="ic_menu_alt">Mais opções</string>
@ -148,11 +147,11 @@
<string name="alert_lock_screen_failed">Erro: Falha ao bloquear a tela. (Se você acabou de atualizar o app, tente desativar e reativar o Serviço de acessibilidade em configurações do aparelho)</string> <string name="alert_lock_screen_failed">Erro: Falha ao bloquear a tela. (Se você acabou de atualizar o app, tente desativar e reativar o Serviço de acessibilidade em configurações do aparelho)</string>
<string name="toast_accessibility_service_not_enabled">O Serviço de acessibilidade do μLauncher não está ativado. Entre em configurações para ativar</string> <string name="toast_accessibility_service_not_enabled">O Serviço de acessibilidade do μLauncher não está ativado. Entre em configurações para ativar</string>
<string name="settings_apps_hide_bound_apps">Não mostrar apps com um gesto atribuído na lista de aplicativos</string> <string name="settings_apps_hide_bound_apps">Não mostrar apps com um gesto atribuído na lista de aplicativos</string>
<string name="toast_device_admin_not_enabled">O µLauncher precisa tornar-se o Administrador do dispositivo para poder bloquear a tela.</string> <string name="toast_device_admin_not_enabled">O μLauncher precisa virar um Administrador do dispositivo para poder bloquear a tela.</string>
<string name="device_admin_explanation">Isto é necessário para realizar a ação de bloqueio da tela.</string> <string name="device_admin_explanation">Isto é necessário para realizar a ação de bloqueio da tela.</string>
<string name="device_admin_description">Permitir a ação de bloqueio da tela</string> <string name="device_admin_description">Permitir a ação de bloqueio da tela</string>
<string name="alert_torch_access_exception">Erro: Não é possível acessar a lanterna.</string> <string name="alert_torch_access_exception">Erro: Não é possível acessar a lanterna.</string>
<string name="accessibility_service_name">µLauncher - bloqueio da tela</string> <string name="accessibility_service_name">μLauncher</string>
<string name="screen_lock_method_use_accessibility">Usar o Serviço de acessibilidade</string> <string name="screen_lock_method_use_accessibility">Usar o Serviço de acessibilidade</string>
<string name="screen_lock_method_use_device_admin">Usar o Administrador do dispositivo</string> <string name="screen_lock_method_use_device_admin">Usar o Administrador do dispositivo</string>
<string name="screen_lock_method_dialog_title">Escolha um método de bloqueio</string> <string name="screen_lock_method_dialog_title">Escolha um método de bloqueio</string>
@ -161,7 +160,7 @@
<string name="alert_requires_android_m">Essa funcionalidade requer o Android 6 ou mais recente.</string> <string name="alert_requires_android_m">Essa funcionalidade requer o Android 6 ou mais recente.</string>
<string name="alert_no_torch_found">Nenhuma câmera com lanterna detectada.</string> <string name="alert_no_torch_found">Nenhuma câmera com lanterna detectada.</string>
<string name="toast_lock_screen_not_supported">Erro: O bloqueio da tela via Serviço de acessibilidade não é compatível com este aparelho. Tente usar Administrador do dispositivo como método alternativo.</string> <string name="toast_lock_screen_not_supported">Erro: O bloqueio da tela via Serviço de acessibilidade não é compatível com este aparelho. Tente usar Administrador do dispositivo como método alternativo.</string>
<string name="accessibility_service_description">Definindo µLauncher como Serviço de acessibilidade permite a ele bloquear a tela. Considere que é necessário conceder as permissões elevadas. Você nunca deveria autorizar essas permissões a qualquer aplicativo sem avaliação. O µLauncher usará o Serviço de acessibilidade somente para bloquear a tela. Você pode verificar o código-fonte para ter certeza. O bloqueio da tela também pode ser realizado dando ao µLauncher permissões de Administrador do dispositivo. Apesar de que esse método não funciona com impressão digital e desbloqueio facial.</string> <string name="accessibility_service_description">Definindo o μLauncher como Serviço de acessibilidade permite bloquear a tela e abrir o menu de apps recentes. Considere que é necessário conceder as permissões elevadas. Você nunca deveria autorizar essas permissões a qualquer aplicativo sem avaliação. O μLauncher usará o Serviço de acessibilidade somente para executar as seguintes ações quando solicitado pelo usuário: * bloquear a tela * abrir aplicativos recentes μLauncher nunca usará o Serviço de acessibilidade para coletar os dados. Você pode verificar o código-fonte para ter certeza. O bloqueio da tela também pode ser realizado dando ao μLauncher permissões de Administrador do dispositivo. Apesar de que esse método não funciona com impressão digital e desbloqueio facial.</string>
<string name="screen_lock_method_dialog_text"><![CDATA[ <string name="screen_lock_method_dialog_text"><![CDATA[
<h1>Escolha um método de bloqueio</h1> <h1>Escolha um método de bloqueio</h1>
Há dois métodos para bloquear a tela. Há dois métodos para bloquear a tela.
@ -175,9 +174,9 @@
<h3>Serviço de acessibilidade</h3> <h3>Serviço de acessibilidade</h3>
Exige permissões elevadas. Exige permissões elevadas.
O µLauncher usará essas permissões apenas para bloquear a tela. O μLauncher usará essas permissões apenas para bloquear a tela.
<br/> <br/>
(Você realmente não deveria confiar num app aleatório que você baixou que tá pedindo estas permissões, mas pode verificar o <a href=\"https://github.com/jrpie/Launcher\">código-fonte</a>.) (Você realmente não deveria confiar num app aleatório que você baixou e tá pedindo estas permissões, mas pode verificar o <a href=\"https://github.com/jrpie/Launcher\">código-fonte</a>.)
<br/> <br/>
Em alguns aparelhos após ativação do Serviço de acessibilidade não será mais exigido o PIN para acessar dados criptografados, na inicialização do celular. Em alguns aparelhos após ativação do Serviço de acessibilidade não será mais exigido o PIN para acessar dados criptografados, na inicialização do celular.
Isto pode ser <a href="https://issuetracker.google.com/issues/37010136#comment36">reativado</a> depois. Isto pode ser <a href="https://issuetracker.google.com/issues/37010136#comment36">reativado</a> depois.
@ -211,7 +210,7 @@
<string name="settings_enabled_gestures_edge_swipe_summary">Deslize na borda da tela</string> <string name="settings_enabled_gestures_edge_swipe_summary">Deslize na borda da tela</string>
<string name="settings_enabled_gestures_edge_swipe_edge_width">Largura da borda</string> <string name="settings_enabled_gestures_edge_swipe_edge_width">Largura da borda</string>
<string name="settings_meta_view_code">Ver código-fonte</string> <string name="settings_meta_view_code">Ver código-fonte</string>
<string name="settings_meta_join_chat">Entre no chat do µLauncher</string> <string name="settings_meta_join_chat">Entre no chat do μLauncher</string>
<string name="list_other_lock_screen">Bloquear a tela</string> <string name="list_other_lock_screen">Bloquear a tela</string>
<string name="settings_theme_text_shadow">Sombra no texto</string> <string name="settings_theme_text_shadow">Sombra no texto</string>
<string name="settings_theme_background_item_transparent">Transparente</string> <string name="settings_theme_background_item_transparent">Transparente</string>
@ -237,13 +236,18 @@
<string name="dialog_select_color_green">Verde</string> <string name="dialog_select_color_green">Verde</string>
<string name="dialog_select_color_color_hex">Cor</string> <string name="dialog_select_color_color_hex">Cor</string>
<string name="dialog_choose_color_title">Escola a cor</string> <string name="dialog_choose_color_title">Escola a cor</string>
<string name="dialog_consent_accessibility_consent">Autorizo a utilização do Serviço de acessibilidade para disponibilizar funcionalidades não relacionadas com a acessibilidade.</string> <string name="dialog_consent_accessibility_consent">Autorizo o μLauncher a usar Serviço de acessibilidade para acessar funcionalidades não relacionadas com a acessibilidade.</string>
<string name="dialog_consent_accessibility_data_collection">Não autorizo ao µLauncher a coleta de quaisquer dados.</string> <string name="dialog_consent_accessibility_data_collection">Não autorizo ao μLauncher coletar quaisquer dados.</string>
<string name="dialog_consent_accessibility_title">Ativação do Serviço de acessibilidade</string> <string name="dialog_consent_accessibility_title">Ativação do Serviço de acessibilidade</string>
<string name="dialog_consent_accessibility_ok">Ativar o Serviço de acessibilidade</string> <string name="dialog_consent_accessibility_ok">Ativar o Serviço de acessibilidade</string>
<string name="dialog_cancel">Cancelar</string> <string name="dialog_cancel">Cancelar</string>
<string name="dialog_consent_accessibility_text"><![CDATA[Você está prestes a ativar o Serviço de acessibilidade. Isto concederá <strong>permissões elevadas</strong> ao µLauncher.<br/>µLauncher usará estas permissões <strong>apenas para bloquear a tela</strong>. µLauncher <strong>nunca coletará nenhum dado</strong>. Sobretudo, o µLauncher não implementa o Serviço de acessibilidade para coletar dados.]]></string> <string name="dialog_consent_accessibility_text"><![CDATA[Você está prestes a ativar o Serviço de acessibilidade. Isto concederá <strong>permissões elevadas</strong> ao μLauncher.<br/>μLauncher usará estas permissões <strong>apenas</strong> para executar as seguintes ações:
<string name="dialog_consent_accessibility_privileges">Estou ciente de que isto concederá permissões elevadas ao µLauncher.</string> <ul>
<li>Bloquear a tela</li>
<li>Apps recentes</li>
</ul>
μLauncher<strong>nunca coletará nenhum dado</strong>. Sobretudo, o μLauncher não implementa o Serviço de acessibilidade para coletar os dados.]]></string>
<string name="dialog_consent_accessibility_privileges">Estou ciente de que isto concederá permissões elevadas ao μLauncher.</string>
<string name="dialog_consent_accessibility_other_options">Estou ciente de que existem outras opções (permissões de Administrador do aparelho ou o botão de ligar).</string> <string name="dialog_consent_accessibility_other_options">Estou ciente de que existem outras opções (permissões de Administrador do aparelho ou o botão de ligar).</string>
<string name="settings_functionality_search_web">Pesquise na internet</string> <string name="settings_functionality_search_web">Pesquise na internet</string>
<string name="settings_functionality_search_web_summary">Ao buscar na lista de apps toque no Enter para iniciar uma pesquisa na internet.</string> <string name="settings_functionality_search_web_summary">Ao buscar na lista de apps toque no Enter para iniciar uma pesquisa na internet.</string>
@ -256,13 +260,13 @@
<string name="toast_private_space_locked">Espaço privado trancado</string> <string name="toast_private_space_locked">Espaço privado trancado</string>
<string name="toast_private_space_unlocked">Espaço privado liberado</string> <string name="toast_private_space_unlocked">Espaço privado liberado</string>
<string name="toast_private_space_not_available">Espaço privado indisponível</string> <string name="toast_private_space_not_available">Espaço privado indisponível</string>
<string name="toast_private_space_default_home_screen">O µLauncher precisa ser definido como a tela inicial padrão para poder usar Espaço privado.</string> <string name="toast_private_space_default_home_screen">O μLauncher precisa ser definido como a tela inicial padrão para poder usar Espaço privado.</string>
<string name="dialog_report_bug_button_clipboard">Copiar para memória</string> <string name="dialog_report_bug_button_clipboard">Copiar para memória</string>
<string name="dialog_report_bug_security_info">Não relate vulnerabilidades de segurança publicamente no GitHub, use o seguinte:</string> <string name="dialog_report_bug_security_info">Não relate vulnerabilidades de segurança publicamente no GitHub, use o seguinte:</string>
<string name="dialog_report_bug_button_security">Relatar vulnerabilidade de segurança</string> <string name="dialog_report_bug_button_security">Relatar vulnerabilidade de segurança</string>
<string name="dialog_report_bug_create_report">Criar relatório</string> <string name="dialog_report_bug_create_report">Criar relatório</string>
<string name="dialog_report_bug_title">Relatar um bug</string> <string name="dialog_report_bug_title">Relatar um bug</string>
<string name="dialog_report_bug_info">Obrigado por ajudar a melhorar o µLauncher!\nConsidere adicionar as seguintes informações ao relatório de bug:</string> <string name="dialog_report_bug_info">Obrigado por ajudar a melhorar o μLauncher!\nConsidere adicionar as seguintes informações ao relatório dos bugs:</string>
<string name="settings_functionality_auto_launch_summary">Toque no espaço para temporariamente desativar esta funcionalidade.</string> <string name="settings_functionality_auto_launch_summary">Toque no espaço para temporariamente desativar esta funcionalidade.</string>
<string name="toast_activity_not_found_browser">Não foi possível abrir a URL: nenhum navegador encontrado.</string> <string name="toast_activity_not_found_browser">Não foi possível abrir a URL: nenhum navegador encontrado.</string>
<string name="toast_activity_not_found_search_web">Nenhum app encontrado para efetuar a pesquisa.</string> <string name="toast_activity_not_found_search_web">Nenhum app encontrado para efetuar a pesquisa.</string>
@ -301,5 +305,18 @@
<string name="list_other_track_play_pause">Música: Reproduzir / Pausar</string> <string name="list_other_track_play_pause">Música: Reproduzir / Pausar</string>
<string name="settings_gesture_description_swipe_smaller_reverse">Canto inferior direito -&gt; centro esquerdo -&gt; canto superior direito</string> <string name="settings_gesture_description_swipe_smaller_reverse">Canto inferior direito -&gt; centro esquerdo -&gt; canto superior direito</string>
<string name="settings_gesture_description_swipe_lambda_reverse">Inferior direito -&gt; superior médio -&gt; inferior esquerdo</string> <string name="settings_gesture_description_swipe_lambda_reverse">Inferior direito -&gt; superior médio -&gt; inferior esquerdo</string>
<string name="settings_list_reverse_layout">Lista de apps inversa</string> <string name="settings_list_reverse_layout">Inverter a lista de apps</string>
<string name="settings_meta_donate">Doar</string>
<string name="list_other_volume_adjust">Ajustar volume</string>
<string name="settings_display_hide_status_bar">Ocultar barra de status</string>
<string name="settings_display_hide_navigation_bar">Ocultar barra de navegação</string>
<string name="tutorial_concept_label_version">Versão</string>
<string name="tutorial_app_list_title">Todos apps</string>
<string name="tutorial_app_list_text">Você pode encontrar rápido todos os apps na lista de aplicativos.\n\nDeslize para cima para abrir ou definir um gesto específico.</string>
<string name="tutorial_app_list_text_2">Quando apenas um aplicativo corresponde, vai ser iniciado automaticamente.\nIsso pode ser desativado acrescentando um espaço durante a busca.</string>
<string name="settings_tab_actions">Ações</string>
<string name="list_other_recent_apps">Apps recentes</string>
<string name="alert_enable_accessibility_failed">Erro: Falha ao ativar o Serviço de acessibilidade.</string>
<string name="list_other_launch_other_launcher">Usar outro iniciador</string>
<string name="alert_recent_apps_failed">Erro: Falha ao mostrar apps recentes. (Se você acabou de atualizar o app, tente desativar e reativar o Serviço de acessibilidade em configurações do Android)</string>
</resources> </resources>

View file

@ -52,7 +52,6 @@
<string name="alert_cant_open_message">Ayarlarını değiştirmek ister misiniz?</string> <string name="alert_cant_open_message">Ayarlarını değiştirmek ister misiniz?</string>
<string name="toast_cant_open_message">Bu harekete bir eylem atamak için ayarlarıın</string> <string name="toast_cant_open_message">Bu harekete bir eylem atamak için ayarlarıın</string>
<string name="settings_title">Ayarlar</string> <string name="settings_title">Ayarlar</string>
<string name="settings_tab_app">Uygulamalar</string>
<string name="settings_tab_launcher">Başlatıcı</string> <string name="settings_tab_launcher">Başlatıcı</string>
<string name="settings_tab_meta">Daha Fazlası</string> <string name="settings_tab_meta">Daha Fazlası</string>
<string name="settings_gesture_up">Yukarı</string> <string name="settings_gesture_up">Yukarı</string>

View file

@ -5,37 +5,36 @@
<string name="ic_menu_alt">更多选项</string> <string name="ic_menu_alt">更多选项</string>
<string name="settings_title">设置</string> <string name="settings_title">设置</string>
<string name="settings_launcher_section_appearance">外观</string> <string name="settings_launcher_section_appearance">外观</string>
<string name="settings_theme_color_theme">主题风格</string> <string name="settings_theme_color_theme">色调风格</string>
<string name="settings_launcher_section_display">显示</string> <string name="settings_launcher_section_display">显示</string>
<string name="list_tab_other">其他</string> <string name="list_tab_other">其他</string>
<string name="settings_gesture_up"></string> <string name="settings_gesture_up"></string>
<string name="settings_gesture_down"></string> <string name="settings_gesture_down"></string>
<string name="alert_cant_open_title">无法打开应用</string> <string name="alert_cant_open_title">无法打开应用</string>
<string name="alert_cant_open_message">要更改其设置吗?</string> <string name="alert_cant_open_message">要更改其设置吗?</string>
<string name="toast_cant_open_message">打开设置,为该手势绑定一个应用程序</string> <string name="toast_cant_open_message">打开设置,为该手势绑定一个应用程序</string>
<string name="settings_tab_app">应用程序</string>
<string name="settings_tab_launcher">启动器</string> <string name="settings_tab_launcher">启动器</string>
<string name="settings_tab_meta">杂项</string> <string name="settings_tab_meta">杂项</string>
<string name="settings_gesture_left"></string> <string name="settings_gesture_left"></string>
<string name="settings_gesture_double_left">左滑两次</string> <string name="settings_gesture_double_left">双指左滑</string>
<string name="settings_gesture_double_up">上滑两次</string> <string name="settings_gesture_double_up">双指上滑</string>
<string name="settings_gesture_double_down">下滑两次</string> <string name="settings_gesture_double_down">双指下滑</string>
<string name="settings_gesture_right"></string> <string name="settings_gesture_right"></string>
<string name="settings_gesture_double_right">右滑两次</string> <string name="settings_gesture_double_right">双指右滑</string>
<string name="settings_gesture_right_top_edge">右(顶部)</string> <string name="settings_gesture_right_top_edge">(顶部)</string>
<string name="settings_gesture_right_bottom_edge">右(底部)</string> <string name="settings_gesture_right_bottom_edge">(底部)</string>
<string name="settings_gesture_left_bottom_edge">左(底部)</string> <string name="settings_gesture_left_bottom_edge">(底部)</string>
<string name="settings_gesture_left_top_edge">左(顶部)</string> <string name="settings_gesture_left_top_edge">(顶部)</string>
<string name="settings_gesture_up_left_edge">上(左边缘)</string> <string name="settings_gesture_up_left_edge">(左边缘)</string>
<string name="settings_gesture_up_right_edge">上(右边缘)</string> <string name="settings_gesture_up_right_edge">(右边缘)</string>
<string name="settings_gesture_down_left_edge">下(左边缘)</string> <string name="settings_gesture_down_left_edge">(左边缘)</string>
<string name="settings_gesture_down_right_edge">下(右边缘)</string> <string name="settings_gesture_down_right_edge">(右边缘)</string>
<string name="settings_gesture_vol_up">音量</string> <string name="settings_gesture_vol_up">音量增加键</string>
<string name="settings_gesture_vol_down">音量</string> <string name="settings_gesture_vol_down">音量降低键</string>
<string name="settings_gesture_double_click">双击</string> <string name="settings_gesture_double_click">双击</string>
<string name="settings_gesture_long_click">长按</string> <string name="settings_gesture_long_click">长按</string>
<string name="settings_gesture_date">日期</string> <string name="settings_gesture_date">桌面日期</string>
<string name="settings_gesture_time">时间</string> <string name="settings_gesture_time">桌面时钟</string>
<string name="settings_apps_choose">选择应用</string> <string name="settings_apps_choose">选择应用</string>
<string name="settings_apps_install">安装应用</string> <string name="settings_apps_install">安装应用</string>
<string name="settings_apps_toast_store_not_found">没有找到应用市场</string> <string name="settings_apps_toast_store_not_found">没有找到应用市场</string>
@ -43,9 +42,9 @@
<string name="settings_theme_wallpaper">选择壁纸</string> <string name="settings_theme_wallpaper">选择壁纸</string>
<string name="settings_display_screen_timeout_disabled">保持屏幕常亮</string> <string name="settings_display_screen_timeout_disabled">保持屏幕常亮</string>
<string name="settings_launcher_section_functionality">功能</string> <string name="settings_launcher_section_functionality">功能</string>
<string name="settings_enabled_gestures_edge_swipe">边缘滑动动作</string> <string name="settings_enabled_gestures_edge_swipe">边缘滑动手势</string>
<string name="settings_functionality_auto_launch">启动搜索匹配项</string> <string name="settings_functionality_auto_launch">自动启动搜索匹配项</string>
<string name="settings_functionality_auto_keyboard">搜索时呼出键盘</string> <string name="settings_functionality_auto_keyboard">自动激活搜索</string>
<string name="settings_launcher_sensitivity">灵敏度</string> <string name="settings_launcher_sensitivity">灵敏度</string>
<string name="settings_meta_cant_select_launcher">应用信息</string> <string name="settings_meta_cant_select_launcher">应用信息</string>
<string name="settings_meta_show_tutorial">查看 µLauncher 的使用教程</string> <string name="settings_meta_show_tutorial">查看 µLauncher 的使用教程</string>
@ -62,10 +61,10 @@
<string name="tutorial_concept_title">概念</string> <string name="tutorial_concept_title">概念</string>
<string name="tutorial_concept_text_2">这是一款自由软件(遵循 MIT 许可)!\n欢迎查看项目仓库</string> <string name="tutorial_concept_text_2">这是一款自由软件(遵循 MIT 许可)!\n欢迎查看项目仓库</string>
<string name="tutorial_usage_title">使用方法</string> <string name="tutorial_usage_title">使用方法</string>
<string name="tutorial_usage_text">您的主屏幕仅包含本地日期和时间,没有多余项目。</string> <string name="tutorial_usage_text">您的桌面仅包含本地日期和时间,没有多余的项目。</string>
<string name="tutorial_setup_title">设置</string> <string name="tutorial_setup_title">设置</string>
<string name="tutorial_setup_text">我们为您选择了一些默认应用。如果您希望进行更改,现在就可以</string> <string name="tutorial_setup_text">我们为您预设了一些快捷操作。如果您不满意,现在就试试点击右侧图标</string>
<string name="tutorial_setup_text_2">您也可以稍后对您的选择进行更改</string> <string name="tutorial_setup_text_2">您也可以稍后更改您的选择</string>
<string name="tutorial_finish_title">开始!</string> <string name="tutorial_finish_title">开始!</string>
<string name="list_tab_app">应用</string> <string name="list_tab_app">应用</string>
<string name="list_app_delete">卸载</string> <string name="list_app_delete">卸载</string>
@ -77,18 +76,18 @@
<string name="list_other_volume_down">降低音量</string> <string name="list_other_volume_down">降低音量</string>
<string name="list_other_track_previous">音乐:上一首</string> <string name="list_other_track_previous">音乐:上一首</string>
<string name="list_other_track_next">音乐:下一首</string> <string name="list_other_track_next">音乐:下一首</string>
<string name="list_other_nop">啥也不干</string> <string name="list_other_nop">不做任何设置</string>
<string name="tutorial_title">教程</string> <string name="tutorial_title">教程</string>
<string name="tutorial_concept_text">μLauncher 的设计理念是简约、高效,无干扰。\n\n不含广告、且不收集任何数据。</string> <string name="tutorial_concept_text">μLauncher 的设计理念是简约、高效,无干扰。\n\n不含广告、且不收集任何数据。</string>
<string name="tutorial_usage_text_2">您可以通过手势或按键来启动最重要的应用程序。</string> <string name="tutorial_usage_text_2">您可以通过手势或按键来启动对您来说最重要的应用程序。</string>
<string name="settings_general_choose_home_screen">将 μLauncher 设为默认桌面</string> <string name="settings_general_choose_home_screen">将 μLauncher 设为默认启动器</string>
<string name="tutorial_finish_text">您已经准备好开始使用本启动器了!\n\n希望这对你有帮助!\n\n- FinnLauncher 的作者)和 Josia对 μLauncher 进行了改进和维护)</string> <string name="tutorial_finish_text">您已经准备好开始使用本启动器了!\n\n希望本快捷教程能对您有所帮助!\n\n- FinnLauncher 的作者)和 Josia对 μLauncher 进行了改进和维护)</string>
<string name="settings_enabled_gestures_double_swipe">滑动作</string> <string name="settings_enabled_gestures_double_swipe">指滑动手势</string>
<string name="settings_clock_localized">使用本地日期格式</string> <string name="settings_clock_localized">使用本地日期格式</string>
<string name="settings_clock_time_visible">显示时间</string> <string name="settings_clock_time_visible">显示时间</string>
<string name="settings_clock_date_visible">显示日期</string> <string name="settings_clock_date_visible">显示日期</string>
<string name="settings_clock_flip_date_time">翻转日期和时间</string> <string name="settings_clock_flip_date_time">交换日期和时间位置</string>
<string name="settings_theme_background">背景(应用列表和设置)</string> <string name="settings_theme_background">背景(应用程序列表和设置页面</string>
<string name="settings_theme_font">字体</string> <string name="settings_theme_font">字体</string>
<string name="settings_theme_monochrome_icons">黑白应用图标</string> <string name="settings_theme_monochrome_icons">黑白应用图标</string>
<string name="settings_clock_show_seconds">显示秒</string> <string name="settings_clock_show_seconds">显示秒</string>
@ -101,12 +100,12 @@
<string name="alert_torch_access_exception">错误:无法访问闪光灯。</string> <string name="alert_torch_access_exception">错误:无法访问闪光灯。</string>
<string name="screen_lock_method_dialog_title">选择锁屏方法</string> <string name="screen_lock_method_dialog_title">选择锁屏方法</string>
<string name="settings_actions_lock_method">选择锁屏的方法</string> <string name="settings_actions_lock_method">选择锁屏的方法</string>
<string name="settings_apps_hide_bound_apps">不要在应用抽屉中显示被绑定到手势的应用</string> <string name="settings_apps_hide_bound_apps">不要在应用程序列表中显示已被绑定到手势操作的应用</string>
<string name="alert_requires_android_m">此功能需要 Android 6 或更高版本。</string> <string name="alert_requires_android_m">此功能需要 Android 6 或更高版本。</string>
<string name="snackbar_app_hidden">应用程序已隐藏。您可在设置中让它再次显示。</string> <string name="snackbar_app_hidden">应用程序已隐藏。您可在设置中让它再次显示。</string>
<string name="toast_device_admin_not_enabled">µLauncher 需要获得设备管理员权限才能够锁定屏幕。</string> <string name="toast_device_admin_not_enabled">µLauncher 需要激活“设备管理应用”权限才能够锁定屏幕。</string>
<string name="device_admin_explanation">这是执行锁屏操作所必需的。</string> <string name="device_admin_explanation">这是执行锁屏操作所必需的。</string>
<string name="accessibility_service_name">µLauncher - 锁屏</string> <string name="accessibility_service_name">µLauncher</string>
<string name="list_title_favorite">收藏的应用</string> <string name="list_title_favorite">收藏的应用</string>
<string name="list_app_favorite_add">添加到收藏夹</string> <string name="list_app_favorite_add">添加到收藏夹</string>
<string name="list_app_favorite_remove">从收藏夹中移除</string> <string name="list_app_favorite_remove">从收藏夹中移除</string>
@ -115,34 +114,34 @@
<string name="undo">撤销</string> <string name="undo">撤销</string>
<string name="settings_apps_hidden">隐藏的应用</string> <string name="settings_apps_hidden">隐藏的应用</string>
<string name="list_title_hidden">隐藏的应用</string> <string name="list_title_hidden">隐藏的应用</string>
<string name="settings_gesture_description_up">上滑</string> <string name="settings_gesture_description_up">上滑</string>
<string name="settings_gesture_description_double_up">用双指向上滑动</string> <string name="settings_gesture_description_double_up">使用双指向上滑动</string>
<string name="settings_gesture_description_down">下滑</string> <string name="settings_gesture_description_down">下滑</string>
<string name="settings_gesture_description_double_down">双指向下滑动</string> <string name="settings_gesture_description_double_down">使用双指向下滑动</string>
<string name="settings_gesture_description_left">左滑</string> <string name="settings_gesture_description_left">左滑</string>
<string name="settings_gesture_description_double_left">双指向左滑动</string> <string name="settings_gesture_description_double_left">使用双指向左滑动</string>
<string name="settings_gesture_description_right">右滑</string> <string name="settings_gesture_description_right">右滑</string>
<string name="settings_gesture_description_double_right">双指向右滑动</string> <string name="settings_gesture_description_double_right">使用双指向右滑动</string>
<string name="settings_gesture_description_right_top_edge">屏幕顶部向右滑动</string> <string name="settings_gesture_description_right_top_edge">桌面顶部向右滑动</string>
<string name="settings_gesture_description_right_bottom_edge">屏幕底部向右滑动</string> <string name="settings_gesture_description_right_bottom_edge">桌面底部向右滑动</string>
<string name="settings_gesture_description_left_bottom_edge">屏幕底部向左滑动</string> <string name="settings_gesture_description_left_bottom_edge">桌面底部向左滑动</string>
<string name="settings_gesture_description_left_top_edge">屏幕顶部向左滑动</string> <string name="settings_gesture_description_left_top_edge">桌面顶部向左滑动</string>
<string name="settings_gesture_description_up_left_edge">屏幕左边缘向上滑动</string> <string name="settings_gesture_description_up_left_edge">桌面左边缘向上滑动</string>
<string name="settings_gesture_description_up_right_edge">屏幕右边缘向上滑动</string> <string name="settings_gesture_description_up_right_edge">桌面右边缘向上滑动</string>
<string name="settings_gesture_description_down_left_edge">屏幕左边缘向下滑动</string> <string name="settings_gesture_description_down_left_edge">桌面左边缘向下滑动</string>
<string name="settings_gesture_description_down_right_edge">屏幕右边缘向下滑动</string> <string name="settings_gesture_description_down_right_edge">桌面右边缘向下滑动</string>
<string name="settings_gesture_description_vol_up">按下音量增大按钮</string> <string name="settings_gesture_description_vol_up">按下音量增加键</string>
<string name="settings_gesture_description_vol_down">按下音量降低按钮</string> <string name="settings_gesture_description_vol_down">按下音量降低</string>
<string name="settings_gesture_description_double_click">双击空白区域</string> <string name="settings_gesture_description_double_click">双击空白区域</string>
<string name="settings_gesture_description_long_click">长按空白区域</string> <string name="settings_gesture_description_long_click">长按空白区域</string>
<string name="settings_gesture_description_date">点击日期</string> <string name="settings_gesture_description_date">点击桌面日期</string>
<string name="settings_gesture_description_time">点击时间</string> <string name="settings_gesture_description_time">点击桌面时钟</string>
<string name="settings_meta_view_code">查看源代码</string> <string name="settings_meta_view_code">查看源代码</string>
<string name="settings_meta_join_chat">加入 μLauncher 的聊天群</string> <string name="settings_meta_join_chat">加入 μLauncher 的聊天群</string>
<string name="list_other_list_favorites">收藏的应用</string> <string name="list_other_list_favorites">收藏的应用</string>
<string name="list_other_lock_screen">锁屏</string> <string name="list_other_lock_screen">锁屏</string>
<string name="settings_theme_text_shadow">文本阴影</string> <string name="settings_theme_text_shadow">文本阴影</string>
<string name="settings_enabled_gestures_double_swipe_summary">双指滑动</string> <string name="settings_enabled_gestures_double_swipe_summary">使用双指进行滑动手势操作</string>
<string name="dialog_rename_title">重命名 %1$s</string> <string name="dialog_rename_title">重命名 %1$s</string>
<string name="settings_theme_color_theme_item_default">默认</string> <string name="settings_theme_color_theme_item_default">默认</string>
<string name="settings_theme_color_theme_item_dark">暗色</string> <string name="settings_theme_color_theme_item_dark">暗色</string>
@ -158,17 +157,17 @@
<string name="settings_enabled_gestures_edge_swipe_edge_width">边缘宽度</string> <string name="settings_enabled_gestures_edge_swipe_edge_width">边缘宽度</string>
<string name="list_app_rename">重命名</string> <string name="list_app_rename">重命名</string>
<string name="device_admin_description">启用锁屏动作</string> <string name="device_admin_description">启用锁屏动作</string>
<string name="toast_accessibility_service_not_enabled">μLauncher 的无障碍服务未启用,请在设置中启用它。</string> <string name="toast_accessibility_service_not_enabled">μLauncher 的无障碍服务未启用,请在设置中启用它。</string>
<string name="toast_lock_screen_not_supported">错误:此设备不支持使用无障碍功能锁定屏幕。请改用设备管理员模式</string> <string name="toast_lock_screen_not_supported">错误:此设备不支持使用“无障碍”服务锁定屏幕。请改用激活“设备管理应用”权限</string>
<string name="screen_lock_method_use_accessibility">使用无障碍服务</string> <string name="screen_lock_method_use_accessibility">使用无障碍服务</string>
<string name="screen_lock_method_use_device_admin">使用设备管理员模式</string> <string name="screen_lock_method_use_device_admin">激活“设备管理应用”权限</string>
<string name="dialog_cancel">取消</string> <string name="dialog_cancel">取消</string>
<string name="settings_theme_color_theme_item_light">亮色</string> <string name="settings_theme_color_theme_item_light">亮色</string>
<string name="list_other_expand_settings_panel">快速设置</string> <string name="list_other_expand_settings_panel">启动器设置</string>
<string name="alert_lock_screen_failed">错误:锁定屏幕失败。(如果您刚刚升级了本启动器,请尝试在手机设置中手动禁用并重新启用无障碍服务</string> <string name="alert_lock_screen_failed">错误:锁定屏幕失败。(如果您刚刚升级了本启动器,请尝试在手机设置中手动禁用再重新启用“无障碍”服务。</string>
<string name="settings_enabled_gestures_edge_swipe_summary">屏幕边缘滑动</string> <string name="settings_enabled_gestures_edge_swipe_summary">桌面边缘进行滑动手势操作</string>
<string name="accessibility_service_description">将 µLauncher 设为无障碍服务允许其锁定屏幕。请注意这需要过多的权限。你永远不应该轻易地授予任何应用程序这样的权限。µLauncher 将仅使用无障碍服务功能锁屏。您可以审核源代码。请注意,锁屏也可以通过授予 µLauncher 设备管理员权限来实现,然而,这种方法不适用于以指纹和面部解锁</string> <string name="accessibility_service_description">将 µLauncher 设置为“无障碍”服务以允许其锁定屏幕和展示最近应用屏幕。请注意,这会使 µLauncher 获得额外的权限。你永远不应该轻易地授予任何应用程序这样的权限。μLauncher 仅在被用户要求时才会使用“无障碍”服务权限以实现: * 锁定屏幕 * 展示最近应用屏幕。μLauncher 不会使用“无障碍”服务来收集任何数据。您可以审核我们的源代码。请注意,锁定屏幕也可以通过激活 µLauncher 的“设备管理应用”权限来实现,然而,这种方法无法与于指纹解锁和面部解锁兼容</string>
<string name="settings_gesture_back">返回</string> <string name="settings_gesture_back">返回操作</string>
<string name="dialog_select_color_red">红色</string> <string name="dialog_select_color_red">红色</string>
<string name="dialog_select_color_blue">蓝色</string> <string name="dialog_select_color_blue">蓝色</string>
<string name="dialog_select_color_alpha">透明度</string> <string name="dialog_select_color_alpha">透明度</string>
@ -176,51 +175,51 @@
<string name="settings_theme_color_theme_item_dynamic">动态</string> <string name="settings_theme_color_theme_item_dynamic">动态</string>
<string name="list_title_private_space">私人空间</string> <string name="list_title_private_space">私人空间</string>
<string name="list_other_list_private_space">私人空间</string> <string name="list_other_list_private_space">私人空间</string>
<string name="dialog_choose_color_title">选择颜色</string> <string name="dialog_choose_color_title">设置颜色</string>
<string name="dialog_select_color_color_hex">颜色</string> <string name="dialog_select_color_color_hex">颜色</string>
<string name="dialog_report_bug_title">错误反馈</string> <string name="dialog_report_bug_title">错误反馈</string>
<string name="settings_gesture_swipe_larger"><![CDATA[>]]></string> <string name="settings_gesture_swipe_larger"><![CDATA[>]]></string>
<string name="tooltip_lock_private_space">锁定私人空间</string> <string name="tooltip_lock_private_space">锁定私人空间</string>
<string name="settings_gesture_swipe_v">V</string> <string name="settings_gesture_swipe_v">V</string>
<string name="settings_gesture_swipe_lambda">Λ</string> <string name="settings_gesture_swipe_lambda">Λ</string>
<string name="settings_list_layout_item_text">文本</string> <string name="settings_list_layout_item_text">文本</string>
<string name="settings_list_layout_item_grid">网格</string> <string name="settings_list_layout_item_grid">网格</string>
<string name="dialog_report_bug_create_report">创建报告</string> <string name="dialog_report_bug_create_report">创建报告</string>
<string name="tooltip_unlock_private_space">解锁私人空间</string> <string name="tooltip_unlock_private_space">解锁私人空间</string>
<string name="settings_list_layout_item_default">默认</string> <string name="settings_list_layout_item_default">默认</string>
<string name="settings_clock_color">颜色</string> <string name="settings_clock_color">文本颜色</string>
<string name="settings_gesture_swipe_smaller"><![CDATA[<]]></string> <string name="settings_gesture_swipe_smaller"><![CDATA[<]]></string>
<string name="dialog_report_bug_button_clipboard">复制到剪贴板</string> <string name="dialog_report_bug_button_clipboard">复制到剪贴板</string>
<string name="alert_requires_android_v">此功能需要 Android 15 或更高版本。</string> <string name="alert_requires_android_v">此功能需要 Android 15 或更高版本。</string>
<string name="list_other_toggle_private_space_lock">切换私人空间锁</string> <string name="list_other_toggle_private_space_lock">切换私人空间锁</string>
<string name="dialog_consent_accessibility_ok">激活无障碍服务</string> <string name="dialog_consent_accessibility_ok">激活无障碍服务</string>
<string name="dialog_consent_accessibility_title">正在激活无障碍服务</string> <string name="dialog_consent_accessibility_title">正在激活无障碍服务</string>
<string name="settings_meta_licenses">开源许可证</string> <string name="settings_meta_licenses">开源许可证</string>
<string name="legal_info_title">开源许可证</string> <string name="legal_info_title">开源许可证</string>
<string name="pin_shortcut_switch_visible">在应用列表中显示</string> <string name="pin_shortcut_switch_visible">在应用程序列表中显示</string>
<string name="pin_shortcut_title">添加快捷方式</string> <string name="pin_shortcut_title">添加快捷方式</string>
<string name="toast_private_space_locked">私人空间已锁定</string> <string name="toast_private_space_locked">私人空间已锁定</string>
<string name="toast_private_space_unlocked">私人空间已解锁</string> <string name="toast_private_space_unlocked">私人空间已解锁</string>
<string name="toast_private_space_not_available">私人空间不可用</string> <string name="toast_private_space_not_available">私人空间不可用</string>
<string name="toast_private_space_default_home_screen">µLauncher 需要作为默认主屏幕才能访问私人空间。</string> <string name="toast_private_space_default_home_screen">µLauncher 需要作为默认启动器才能访问私人空间。</string>
<string name="toast_activity_not_found_search_web">没有找到处理搜索的应用。</string> <string name="toast_activity_not_found_search_web">没有找到处理搜索的应用。</string>
<string name="toast_activity_not_found_browser">无法打开 URL找不到浏览器。</string> <string name="toast_activity_not_found_browser">无法打开 URL找不到浏览器。</string>
<string name="dialog_consent_accessibility_privileges">我已知晓,这将赋予 μLauncher 广泛且重要的权限。</string> <string name="dialog_consent_accessibility_privileges">我已知晓,这将赋予 μLauncher 广泛且重要的权限。</string>
<string name="settings_apps_hide_private_space_apps">在应用程序列表中隐藏私人空间</string> <string name="settings_apps_hide_private_space_apps">在应用程序列表中隐藏私人空间</string>
<string name="settings_apps_hide_paused_apps">隐藏已被暂停的应用</string> <string name="settings_apps_hide_paused_apps">隐藏已被暂停的应用</string>
<string name="settings_gesture_description_back">返回按键 / 返回手势</string> <string name="settings_gesture_description_back">返回按键 / 返回手势</string>
<string name="settings_gesture_description_tap_down">先单击然后再下滑</string> <string name="settings_gesture_description_tap_down">先单击然后再下滑</string>
<string name="settings_functionality_search_web">在网络上搜索</string> <string name="settings_functionality_search_web">在网络上搜索</string>
<string name="settings_gesture_description_swipe_smaller">(从)右上 (滑向)中左(滑向)右下</string> <string name="settings_gesture_description_swipe_smaller">(从)右上(滑向)中左(滑向)右下</string>
<string name="settings_functionality_search_web_summary">通过按回车键在应用列表搜索界面激活网络搜索。</string> <string name="settings_functionality_search_web_summary">输入搜索内容后,按回车键直接在应用程序列表界面启动网络搜索。</string>
<string name="settings_gesture_description_swipe_lambda">(从)左下 (滑向)中上(滑向)右下</string> <string name="settings_gesture_description_swipe_lambda">(从)左下(滑向)中上(滑向)右下</string>
<string name="screen_lock_method_dialog_text"><![CDATA[ <string name="screen_lock_method_dialog_text"><![CDATA[
<h1>选择锁定设备的方式</h1> <h1>选择锁定设备的方式</h1>
有2种方式可以用来锁定屏幕。 有2种方式可以用来锁定屏幕。
遗憾的是,两者都有缺点:<br/><br/> 遗憾的是,两者都有缺点:<br/><br/>
<h3>通过设置“设备管理应用”</h3> <h3>通过激活“设备管理应用”权限</h3>
无法和指纹解锁和脸部解锁共同使用。 该方法无法和指纹解锁和脸部解锁共同使用。
<br/> <br/>
<br/> <br/>
@ -229,50 +228,60 @@
需要更多的权限。 需要更多的权限。
μLauncher 将这些权限仅用于锁定屏幕。 μLauncher 将这些权限仅用于锁定屏幕。
<br/> <br/>
(对于任何一个从网上下载的应用所做的类似声明,你都不应该抱持“默认为可信”的态度,你可以并应该检查一下它的<a href=\"https://github.com/jrpie/Launcher\">源代码</a>.) 对于任何一个从网上下载的应用所做的类似声明,你都不应该抱持“默认为可信”的态度,你可以并应该检查一下它的<a href=\"https://github.com/jrpie/Launcher\">源代码</a>.
<br/> <br/>
在某些设备上,激活辅助功能服务后启动PIN码将不再用于加密数据。 在某些设备上,激活“无障碍”服务后,启动 PIN 码将不再用于加密数据。
如果遇到该问题,可以通过<a href="https://issuetracker.google.com/issues/37010136#comment36">该方法</a>重新激活启动PIN码用于数据加密。 如果遇到该问题,可以通过<a href="https://issuetracker.google.com/issues/37010136#comment36">该方法</a>重新激活启动 PIN 码用于数据加密。
<br/><br/><br/><br/> <br/><br/><br/><br/>
你可以在设置中随时更改这个选项。 你可以在设置中随时更改这个选项。
]]></string> ]]></string>
<string name="list_apps_search_hint_no_auto_launch">搜索(不触发自动启动匹配项)</string> <string name="list_apps_search_hint_no_auto_launch">搜索(不触发自动启动匹配项)</string>
<string name="dialog_consent_accessibility_text"><![CDATA[您即将激活“无障碍”服务。这将授予 μLauncher <strong>广泛且重要的权限</strong>。<br/>μLauncher 将这些权限<strong>仅用于锁定屏幕</strong>。µLauncher <strong>绝不会收集任何数据</strong>。尤其是μLauncher 不会使用“无障碍”服务来收集任何数据。]]></string> <string name="dialog_consent_accessibility_text"><![CDATA[您即将激活“无障碍”服务。这将授予 μLauncher <strong>广泛且重要的权限</strong><br/>但 μLauncher <strong></strong>将这些权限用于:
<string name="settings_gesture_description_swipe_larger">(从)左上 (滑向)中右(滑向)左下</string> <ul>
<li>锁定屏幕</li>
<li>展示最近应用屏幕</li>
</ul>
µLauncher <strong>绝不会收集任何数据</strong>。尤其是μLauncher 不会使用“无障碍”服务来收集任何数据。]]></string>
<string name="settings_gesture_description_swipe_larger">(从)左上(滑向)中右(滑向)左下</string>
<string name="settings_gesture_tap_up">单击 + 上滑</string> <string name="settings_gesture_tap_up">单击 + 上滑</string>
<string name="settings_gesture_tap_down">单击 + 下滑</string> <string name="settings_gesture_tap_down">单击 + 下滑</string>
<string name="settings_gesture_tap_left">单击 + 左滑</string> <string name="settings_gesture_tap_left">单击 + 左滑</string>
<string name="settings_gesture_description_tap_left">先单击然后再左滑</string> <string name="settings_gesture_description_tap_left">先单击然后再左滑</string>
<string name="settings_gesture_description_tap_up">先单击然后再上滑</string> <string name="settings_gesture_description_tap_up">先单击然后再上滑</string>
<string name="settings_gesture_tap_right">单击 + 右滑</string> <string name="settings_gesture_tap_right">单击 + 右滑</string>
<string name="settings_gesture_description_tap_right">先单击然后再右滑</string> <string name="settings_gesture_description_tap_right">先单击然后再右滑</string>
<string name="settings_gesture_description_swipe_larger_reverse">(从)左下 (滑向)中右(滑向)左上</string> <string name="settings_gesture_description_swipe_larger_reverse">(从)左下(滑向)中右(滑向)左上</string>
<string name="settings_gesture_description_swipe_smaller_reverse">(从)右下 (滑向)中左(滑向)右上</string> <string name="settings_gesture_description_swipe_smaller_reverse">(从)右下(滑向)中左(滑向)右上</string>
<string name="settings_gesture_description_swipe_v">(从)左上 (滑向)中下(滑向)右上</string> <string name="settings_gesture_description_swipe_v">(从)左上(滑向)中下(滑向)右上</string>
<string name="settings_gesture_description_swipe_v_reverse">(从)右上 (滑向)中下(滑向)左上</string> <string name="settings_gesture_description_swipe_v_reverse">(从)右上(滑向)中下(滑向)左上</string>
<string name="settings_gesture_description_swipe_lambda_reverse">(从)右下 (滑向)中上(滑向)左下</string> <string name="settings_gesture_description_swipe_lambda_reverse">(从)右下(滑向)中上(滑向)左下</string>
<string name="settings_gesture_swipe_lambda_reverse">Λ (反向)</string> <string name="settings_gesture_swipe_lambda_reverse">Λ (反向)</string>
<string name="settings_gesture_swipe_v_reverse">V反向</string> <string name="settings_gesture_swipe_v_reverse">V反向</string>
<string name="settings_gesture_swipe_larger_reverse"><![CDATA[>(反向)]]></string> <string name="settings_gesture_swipe_larger_reverse"><![CDATA[>(反向)]]></string>
<string name="settings_gesture_swipe_smaller_reverse"><![CDATA[<(反向)]]></string> <string name="settings_gesture_swipe_smaller_reverse"><![CDATA[<(反向)]]></string>
<string name="settings_functionality_auto_launch_summary">开启后将直接启动匹配搜索内容的应用,可以通过按空格键临时暂停该功能。</string> <string name="settings_functionality_auto_launch_summary">开启后将直接启动搜索所匹配到的应用,可以通过在搜索内容前添加空格来临时停用该功能。</string>
<string name="settings_list_layout">应用程序列表样式</string> <string name="settings_list_layout">应用程序列表样式</string>
<string name="pin_shortcut_button_bind">绑定到手势</string> <string name="pin_shortcut_button_bind">绑定到手势</string>
<string name="list_other_track_play_pause">音乐:播放 / 暂停</string> <string name="list_other_track_play_pause">音乐:播放 / 暂停</string>
<string name="dialog_report_bug_button_security">报告安全漏洞</string> <string name="dialog_report_bug_button_security">报告安全漏洞</string>
<string name="dialog_report_bug_security_info">请不要在 Github 上以公开的方式报告安全漏洞,请使用以下方式进行报告:</string> <string name="dialog_report_bug_security_info">请不要在 Github 上以公开的方式报告安全漏洞,请使用以下方式进行报告:</string>
<string name="dialog_report_bug_info">感谢您帮助改进 µLauncher\n请考虑在您的应用程序错误反馈中添加以下信息</string> <string name="dialog_report_bug_info">感谢您帮助改进 µLauncher\n请考虑在您的应用程序错误反馈中添加以下信息</string>
<string name="dialog_consent_accessibility_other_options">我已知晓,还有其他替代方法(使用设备管理员模式或电源按键)。</string> <string name="dialog_consent_accessibility_other_options">我已知晓,还有其他替代方法(激活“设备管理应用”权限或通过电源按键)。</string>
<string name="dialog_consent_accessibility_data_collection">我同意 μLauncher 不收集任何数据。</string> <string name="dialog_consent_accessibility_data_collection">我同意 μLauncher 不收集任何数据。</string>
<string name="settings_meta_donate">捐赠</string> <string name="settings_meta_donate">捐赠</string>
<string name="list_other_volume_adjust">调整音量</string> <string name="list_other_volume_adjust">调整音量</string>
<string name="tutorial_concept_label_version">版本</string> <string name="tutorial_concept_label_version">版本</string>
<string name="tutorial_app_list_title">所有应用</string> <string name="tutorial_app_list_title">所有应用</string>
<string name="tutorial_app_list_text">您可以在应用程序列表中快速所搜所有应用。\n\n您可以通过上滑打开应用程序列表也可以通过绑定其他手势操作来打开应用程序列表。</string> <string name="tutorial_app_list_text">您可以在应用程序列表中快速找到已安装的应用程序。\n\n您可以通过上滑打开应用程序列表也可以通过绑定其他手势操作来打开应用程序列表。</string>
<string name="tutorial_app_list_text_2">当匹配到唯一的应用程序后,该应用将自动启动。\n如果你不想触发自动启动在查询内容前加上空格即可禁用。</string> <string name="tutorial_app_list_text_2">您还可以搜索,当匹配到唯一的应用程序后,该应用将自动启动。\n如果你不想触发自动启动可以在搜索内容前加上空格以禁用。</string>
<string name="settings_display_hide_status_bar">隐藏状态栏</string> <string name="settings_display_hide_status_bar">隐藏状态栏</string>
<string name="settings_display_hide_navigation_bar">隐藏导航栏</string> <string name="settings_display_hide_navigation_bar">隐藏导航栏</string>
<string name="settings_list_reverse_layout">倒序排列应用程序</string> <string name="settings_list_reverse_layout">倒序排列应用程序</string>
<string name="dialog_consent_accessibility_consent">我同意 μLauncher 使用无障碍服务来提供与无障碍服务无关的其他功能。</string> <string name="dialog_consent_accessibility_consent">我同意 μLauncher 使用无障碍服务来提供与无障碍服务无关的其他功能。</string>
<string name="settings_tab_actions">快捷操作</string>
<string name="list_other_recent_apps">最近应用屏幕</string>
<string name="alert_enable_accessibility_failed">错误:启用“无障碍”服务失败。</string>
<string name="alert_recent_apps_failed">错误:无法展示最近应用屏幕。(如果您刚刚升级了本启动器,请尝试在手机设置中手动禁用再重新启用“无障碍”服务。)</string>
<string name="list_other_launch_other_launcher">启动其他启动器</string>
</resources> </resources>

View file

@ -11,5 +11,9 @@
<color name="lightTheme_background_color">#fff</color> <color name="lightTheme_background_color">#fff</color>
<color name="lightTheme_accent_color">#9999ff</color> <color name="lightTheme_accent_color">#9999ff</color>
<color name="lightTheme_text_color">#000</color> <color name="lightTheme_text_color">#000</color>
<color name="light_blue_400">#FF29B6F6</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="gray_400">#FFBDBDBD</color>
<color name="gray_600">#FF757575</color>
</resources> </resources>

View file

@ -9,6 +9,8 @@
<string name="settings_internal_started_key" translatable="false">internal.started_before</string> <string name="settings_internal_started_key" translatable="false">internal.started_before</string>
<string name="settings_internal_started_time_key" translatable="false">internal.first_startup</string> <string name="settings_internal_started_time_key" translatable="false">internal.first_startup</string>
<string name="settings_internal_version_code_key" translatable="false">internal.version_code</string> <string name="settings_internal_version_code_key" translatable="false">internal.version_code</string>
<string name="settings_widgets_widgets_key" translatable="false">widgets.widgets</string>
<string name="settings_widgets_custom_panels_key" translatable="false">widgets.custom_panels</string>
<string name="settings_apps_favorites_key" translatable="false">apps.favorites</string> <string name="settings_apps_favorites_key" translatable="false">apps.favorites</string>
<string name="settings_apps_hidden_key" translatable="false">apps.hidden</string> <string name="settings_apps_hidden_key" translatable="false">apps.hidden</string>
<string name="settings_apps_pinned_shortcuts_key" translatable="false">apps.pinned_shortcuts</string> <string name="settings_apps_pinned_shortcuts_key" translatable="false">apps.pinned_shortcuts</string>
@ -147,6 +149,7 @@
<string name="settings_functionality_search_auto_launch_key" translatable="false">functionality.search_auto_launch</string> <string name="settings_functionality_search_auto_launch_key" translatable="false">functionality.search_auto_launch</string>
<string name="settings_functionality_search_web_key" translatable="false">functionality.search_web</string> <string name="settings_functionality_search_web_key" translatable="false">functionality.search_web</string>
<string name="settings_functionality_search_auto_open_keyboard_key" translatable="false">functionality.search_auto_keyboard</string> <string name="settings_functionality_search_auto_open_keyboard_key" translatable="false">functionality.search_auto_keyboard</string>
<string name="settings_functionality_search_auto_close_keyboard_key" translatable="false">functionality.search_auto_close_keyboard</string>
<string name="settings_actions_lock_method_key" translatable="false">settings_action_lock_method</string> <string name="settings_actions_lock_method_key" translatable="false">settings_action_lock_method</string>

View file

@ -16,7 +16,7 @@
--> -->
<string name="settings_title">Settings</string> <string name="settings_title">Settings</string>
<string name="settings_tab_app">Apps</string> <string name="settings_tab_actions">Actions</string>
<string name="settings_tab_launcher">Launcher</string> <string name="settings_tab_launcher">Launcher</string>
<string name="settings_tab_meta">Meta</string> <string name="settings_tab_meta">Meta</string>
@ -85,9 +85,9 @@
<string name="settings_gesture_swipe_lambda_reverse">Λ (Reverse)</string> <string name="settings_gesture_swipe_lambda_reverse">Λ (Reverse)</string>
<string name="settings_gesture_description_swipe_lambda_reverse">Bottom right -> top mid -> bottom left</string> <string name="settings_gesture_description_swipe_lambda_reverse">Bottom right -> top mid -> bottom left</string>
<string name="settings_gesture_vol_up">Volume Up</string> <string name="settings_gesture_vol_up">Volume Up Key</string>
<string name="settings_gesture_description_vol_up">Press the volume up button</string> <string name="settings_gesture_description_vol_up">Press the volume up button</string>
<string name="settings_gesture_vol_down">Volume Down</string> <string name="settings_gesture_vol_down">Volume Down Key</string>
<string name="settings_gesture_description_vol_down">Press the volume down button</string> <string name="settings_gesture_description_vol_down">Press the volume down button</string>
<string name="settings_gesture_double_click">Double Click</string> <string name="settings_gesture_double_click">Double Click</string>
<string name="settings_gesture_description_double_click">Double click an empty area</string> <string name="settings_gesture_description_double_click">Double click an empty area</string>
@ -98,6 +98,9 @@
<string name="settings_gesture_time">Time</string> <string name="settings_gesture_time">Time</string>
<string name="settings_gesture_description_time">Click on time</string> <string name="settings_gesture_description_time">Click on time</string>
<string name="settings_widgets_widgets">Manage widgets</string>
<string name="settings_widgets_custom_panels">Manage widget panels</string>
<string name="settings_apps_choose">Choose App</string> <string name="settings_apps_choose">Choose App</string>
@ -167,6 +170,7 @@
<string name="settings_functionality_search_web">Search the web</string> <string name="settings_functionality_search_web">Search the web</string>
<string name="settings_functionality_search_web_summary">Press return while searching the app list to launch a web search.</string> <string name="settings_functionality_search_web_summary">Press return while searching the app list to launch a web search.</string>
<string name="settings_functionality_auto_keyboard">Start keyboard for search</string> <string name="settings_functionality_auto_keyboard">Start keyboard for search</string>
<string name="settings_functionality_auto_close_keyboard">Close keyboard when scrolling</string>
<string name="settings_launcher_sensitivity">Sensitivity</string> <string name="settings_launcher_sensitivity">Sensitivity</string>
@ -251,10 +255,12 @@
<string name="list_other_track_next">Music: Next</string> <string name="list_other_track_next">Music: Next</string>
<string name="list_other_track_previous">Music: Previous</string> <string name="list_other_track_previous">Music: Previous</string>
<string name="list_other_track_play_pause">Music: Play / Pause</string> <string name="list_other_track_play_pause">Music: Play / Pause</string>
<string name="list_other_expand_notifications_panel">Expand notifications panel</string> <string name="list_other_expand_notifications_panel">Expand Notifications Panel</string>
<string name="list_other_nop">Do nothing</string> <string name="list_other_recent_apps">Recent Apps</string>
<string name="list_other_nop">Do Nothing</string>
<string name="list_other_lock_screen">Lock Screen</string> <string name="list_other_lock_screen">Lock Screen</string>
<string name="list_other_torch">Toggle Torch</string> <string name="list_other_torch">Toggle Torch</string>
<string name="list_other_launch_other_launcher">Launch Other Home Screen</string>
<!-- Pin shortcuts --> <!-- Pin shortcuts -->
<string name="pin_shortcut_title">Add Shortcut</string> <string name="pin_shortcut_title">Add Shortcut</string>
@ -307,6 +313,8 @@
<string name="alert_no_torch_found">No camera with torch detected.</string> <string name="alert_no_torch_found">No camera with torch detected.</string>
<string name="alert_torch_access_exception">Error: Can\'t access torch.</string> <string name="alert_torch_access_exception">Error: Can\'t access torch.</string>
<string name="alert_lock_screen_failed">Error: Failed to lock screen. (If you just upgraded the app, try to disable and re-enable the accessibility service in phone settings)</string> <string name="alert_lock_screen_failed">Error: Failed to lock screen. (If you just upgraded the app, try to disable and re-enable the accessibility service in phone settings)</string>
<string name="alert_recent_apps_failed">Error: Failed to show recent apps. (If you just upgraded the app, try to disable and re-enable the accessibility service in phone settings)</string>
<string name="alert_enable_accessibility_failed">Error: Failed to enable the accessibility service.</string>
<string name="toast_accessibility_service_not_enabled">μLauncher\'s accessibility service is not enabled. Please enable it in settings</string> <string name="toast_accessibility_service_not_enabled">μLauncher\'s accessibility service is not enabled. Please enable it in settings</string>
<string name="toast_private_space_locked">Private space locked</string> <string name="toast_private_space_locked">Private space locked</string>
<string name="toast_private_space_unlocked">Private space unlocked</string> <string name="toast_private_space_unlocked">Private space unlocked</string>
@ -315,12 +323,17 @@
<string name="tooltip_lock_private_space">Lock private space</string> <string name="tooltip_lock_private_space">Lock private space</string>
<string name="tooltip_unlock_private_space">Unlock private space</string> <string name="tooltip_unlock_private_space">Unlock private space</string>
<string name="toast_lock_screen_not_supported">Error: Locking the screen using accessibility is not supported on this device. Please use device admin instead.</string> <string name="toast_lock_screen_not_supported">Error: Locking the screen using accessibility is not supported on this device. Please use device admin instead.</string>
<string name="accessibility_service_name">μLauncher - lock screen</string> <string name="accessibility_service_name">μLauncher</string>
<string name="accessibility_service_description"> <string name="accessibility_service_description">
Setting μLauncher as an accessibility service allows it to lock the screen. Setting μLauncher as an accessibility service allows it to lock the screen and open the recent apps menu.
Note that excessive permissions are required. You should never grant such permissions lightly to any app. Note that excessive permissions are required. You should never grant such permissions lightly to any app.
μLauncher will use the accessibility service only for locking the screen. You can check the source code to make sure. μLauncher will use the accessibility service only for performing the following actions when requested by the user:
* lock screen
* open recent apps
μLauncher will never use the accessibility service to collect data. You can check the source code to make sure.
Note that locking the screen can also be accomplished by granting μLauncher device administrator permissions. However that method doesn\'t work with fingerprint and face unlock. Note that locking the screen can also be accomplished by granting μLauncher device administrator permissions. However that method doesn\'t work with fingerprint and face unlock.
</string> </string>
@ -365,7 +378,12 @@
<string name="dialog_consent_accessibility_other_options">I am aware that other options exist (using device administrator privileges or the power button).</string> <string name="dialog_consent_accessibility_other_options">I am aware that other options exist (using device administrator privileges or the power button).</string>
<string name="dialog_consent_accessibility_consent">I consent to μLauncher using the accessibility service to provide functionality unrelated to accessibility.</string> <string name="dialog_consent_accessibility_consent">I consent to μLauncher using the accessibility service to provide functionality unrelated to accessibility.</string>
<string name="dialog_consent_accessibility_data_collection">I consent to μLauncher not collecting any data.</string> <string name="dialog_consent_accessibility_data_collection">I consent to μLauncher not collecting any data.</string>
<string name="dialog_consent_accessibility_text"><![CDATA[You are about to activate the accessibility service. This will grant <strong>far-reaching privileges</strong> to μLauncher.<br/>μLauncher will use these privileges <strong>only to lock the screen</strong>. μLauncher <strong>will never collect any data</strong>. In particular, μLauncher does not use the accessibility service to collect any data.]]></string> <string name="dialog_consent_accessibility_text"><![CDATA[You are about to activate the accessibility service. This will grant <strong>far-reaching privileges</strong> to μLauncher.<br/>μLauncher will use these privileges <strong>only</strong> to perform the following actions:
<ul>
<li>Lock Screen</li>
<li>Recent Apps</li>
</ul>
μLauncher <strong>will never collect any data</strong>. In particular, μLauncher does not use the accessibility service to collect any data.]]></string>
<string name="dialog_consent_accessibility_title">Activating the Accessibility Service</string> <string name="dialog_consent_accessibility_title">Activating the Accessibility Service</string>
<string name="dialog_consent_accessibility_ok">Activate Accessibility Service</string> <string name="dialog_consent_accessibility_ok">Activate Accessibility Service</string>
<string name="dialog_cancel">Cancel</string> <string name="dialog_cancel">Cancel</string>
@ -373,5 +391,33 @@
<string name="legal_info_title">Open Source Licenses</string> <string name="legal_info_title">Open Source Licenses</string>
<string name="toast_activity_not_found_search_web">No app found to handle search.</string> <string name="toast_activity_not_found_search_web">No app found to handle search.</string>
<string name="toast_activity_not_found_browser">Can\'t open URL: no browser found.</string> <string name="toast_activity_not_found_browser">Can\'t open URL: no browser found.</string>
<string name="select_widget_title">Choose Widget</string>
<string name="widget_menu_remove">Remove</string>
<string name="widget_menu_configure">Configure</string>
<string name="widget_menu_enable_interaction">Enable Interaction</string>
<string name="widget_menu_disable_interaction">Disable Interaction</string>
<string name="widget_clock_label">Clock</string>
<string name="widget_clock_description">The default clock of μLauncher</string>
<string name="manage_widget_panels_delete">Delete</string>
<string name="manage_widget_panels_rename">Rename</string>
<string name="widget_panel_default_name">Widget Panel #%1$d</string>
<plurals name="widget_panel_number_of_widgets">
<item quantity="one">Contains %d widget.</item>
<item quantity="other">Contains %d widgets.</item>
</plurals>
<string name="dialog_ok">Ok</string>
<string name="widget_panels_title">Widget Panels</string>
<string name="dialog_select_widget_panel_title">Select a Widget Panel</string>
<string name="dialog_create_widget_panel_title">Create new widget panel</string>
<string name="dialog_select_widget_panel_info_no_panels"><![CDATA[No widget panels found. You can create widget panels in Settings > Launcher > Manage Widget Panels.]]></string>
<string name="list_other_open_widget_panel">Open Widget Panel</string>
<string name="alert_widget_panel_not_found">This widget panel no longer exists.</string>
<string name="settings_launcher_section_widgets">Widgets</string>
</resources> </resources>

View file

@ -66,12 +66,12 @@
<item name="android:shadowDy">0</item> <item name="android:shadowDy">0</item>
<item name="android:shadowRadius">2</item> <item name="android:shadowRadius">2</item>
</style> </style>
<style name="textShadowLight" parent="textShadow"> <style name="textShadowLight" parent="textShadow">
<item name="android:shadowColor">#aaa</item> <item name="android:shadowColor">#aaa</item>
</style> </style>
<style name="backgroundWallpaper"> <style name="backgroundWallpaper">
<item name="android:statusBarColor">@android:color/transparent</item> <item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item> <item name="android:navigationBarColor">@android:color/transparent</item>
@ -81,26 +81,30 @@
<item name="android:colorBackgroundCacheHint">@null</item> <item name="android:colorBackgroundCacheHint">@null</item>
</style> </style>
<style name="backgroundSolid"> <style name="backgroundSolid"></style>
</style>
<style name="fontSystemDefault"> <style name="fontSystemDefault">
<!--<item name="android:textSize">18sp</item>--> <!--<item name="android:textSize">18sp</item>-->
</style> </style>
<style name="fontHack"> <style name="fontHack">
<item name="android:fontFamily">@font/hack</item> <item name="android:fontFamily">@font/hack</item>
<!--<item name="android:textSize">18sp</item>--> <!--<item name="android:textSize">18sp</item>-->
</style> </style>
<style name="fontMonospace"> <style name="fontMonospace">
<item name="android:fontFamily">monospace</item> <item name="android:fontFamily">monospace</item>
</style> </style>
<style name="fontSerifMonospace"> <style name="fontSerifMonospace">
<item name="android:fontFamily">serif-monospace</item> <item name="android:fontFamily">serif-monospace</item>
</style> </style>
<style name="fontSansSerif"> <style name="fontSansSerif">
<item name="android:fontFamily">sans-serif</item> <item name="android:fontFamily">sans-serif</item>
</style> </style>
<style name="fontSerif" tools:keep="@style/fontSerif"> <style name="fontSerif" tools:keep="@style/fontSerif">
<item name="android:fontFamily">serif</item> <item name="android:fontFamily">serif</item>
</style> </style>

View file

@ -3,10 +3,10 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory <PreferenceCategory
app:allowDividerAbove="false" > <!-- general --> app:allowDividerAbove="false" > <!-- general -->
<Preference <Preference
android:key="@string/settings_general_choose_home_screen_key" android:key="@string/settings_general_choose_home_screen_key"
android:title="@string/settings_general_choose_home_screen"/> android:title="@string/settings_general_choose_home_screen"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
app:allowDividerAbove="false" app:allowDividerAbove="false"
@ -104,6 +104,10 @@
android:key="@string/settings_functionality_search_auto_open_keyboard_key" android:key="@string/settings_functionality_search_auto_open_keyboard_key"
android:defaultValue="true" android:defaultValue="true"
android:title="@string/settings_functionality_auto_keyboard" /> android:title="@string/settings_functionality_auto_keyboard" />
<SwitchPreference
android:key="@string/settings_functionality_search_auto_close_keyboard_key"
android:defaultValue="false"
android:title="@string/settings_functionality_auto_close_keyboard" />
<SwitchPreference <SwitchPreference
android:key="@string/settings_enabled_gestures_double_swipe_key" android:key="@string/settings_enabled_gestures_double_swipe_key"
android:summary="@string/settings_enabled_gestures_double_swipe_summary" android:summary="@string/settings_enabled_gestures_double_swipe_summary"
@ -170,6 +174,16 @@
android:defaultValue="false"/> android:defaultValue="false"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/settings_launcher_section_widgets"
app:allowDividerAbove="false">
<Preference
android:key="@string/settings_widgets_widgets_key"
android:title="@string/settings_widgets_widgets" />
<Preference
android:key="@string/settings_widgets_custom_panels_key"
android:title="@string/settings_widgets_custom_panels" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/settings_launcher_section_display" android:title="@string/settings_launcher_section_display"

View file

@ -2,7 +2,7 @@
buildscript { buildscript {
ext.kotlin_version = '2.0.0' ext.kotlin_version = '2.0.0'
ext.android_plugin_version = '8.9.0' ext.android_plugin_version = '8.9.1'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
@ -10,7 +10,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.9.0' classpath 'com.android.tools.build:gradle:8.9.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.android.tools.build:gradle:$android_plugin_version" classpath "com.android.tools.build:gradle:$android_plugin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"

View file

@ -0,0 +1,11 @@
* New action: Launch other launchers
* New action: Show recent apps (workaround for an Android bug)
* Fixed "Set µLauncher as home screen" button
* Size of "choose app" button was limited
* Added Arabic translation (thank you, letterhaven!)
* Started Lithuanian translation (thank you, IdeallyGrey!)
* Improved Chinese translation (thank you, monkeyotg!)
* Improved Portuguese translation (thank you, "Vossa Excelencia"!)
* Improved Spanish translation (thank you, T!)

View file

@ -1,19 +1,21 @@
µLauncher 是主屏幕启动程序,允许您使用滑动手势和按下按钮来启动其他应用。 µLauncher 是桌面启动器程序,允许您使用各种滑动手势和按下按钮来启动其他应用。
它是<b>最小、高效且无干扰</b> 它是<b>简约、高效且无干扰</b>的
您的主屏幕仅显示日期、时间和壁纸。 您的桌面仅显示日期、时间和壁纸。
按返回或向上滑动(可以配置)打开 按返回按键或向上滑动(可自定义其他手势)即可打开
所有已安装应用的列表,可以高效地搜索。 应用程序列表,且支持高效地搜索。
这是 Finn M Glas 的应用 <a href="https://f-droid.org/packages/com.finnmglas.launcher/">Launcher</a> 的一个 fork 本启动器是基于 Finn M Glas 开发的 <a href="https://f-droid.org/packages/com.finnmglas.launcher/">Launcher 启动器</a> 的一个派生应用程序
显著变化: 功能:
* 边缘手势:可分为屏幕边缘滑动和中心滑动的设置。 * 您可以设定 35 个不同的手势操作。如:
* 与工作配置文件兼容,因此可以使用 Shelter 等应用。 - 启动一个应用程序
* 此应用使用系统壁纸而不是自定义解决方案。 - 打开应用程序列表
* 字体已更改为 Hack。 - 打开收藏的应用程序列表
* Material 图标所取代了 Font Awesome 图标。 - 调整音量
* 移除了主屏幕上的齿轮按钮。按返回按钮会打开应用列表,可以从那里访问应用设置。 - 快速切换 上一首/下一首 音乐
* 搜索算法已修改为优先匹配应用名称开头的内容即当搜索“te”时“termux”会排在“notes”之前。 - 锁定屏幕
* 搜索栏已移动到屏幕底部 - 开启/关闭 手机闪光灯
- 展开通知栏 / 快捷设定栏
* 兼容工作空间配置,因此支持使用 Shelter 等应用。

View file

@ -1 +1 @@
无干扰的最小主屏幕应用启动器。 无干扰的简约风格启动器。