mirror of
https://github.com/jrpie/Launcher.git
synced 2025-07-12 02:14:55 +02:00
Compare commits
104 commits
Author | SHA1 | Date | |
---|---|---|---|
abf57760e9 | |||
b9792e9942 | |||
![]() |
dd3ba74f75 | ||
3a7dcbc201 | |||
98756892f3 | |||
ab86a913c1 | |||
407de3bdce | |||
c676b92036 | |||
2cf8870c5d | |||
ce34e9cfdd | |||
919108bbd0 | |||
ce939111d0 | |||
![]() |
33dd3ef3c2 | ||
![]() |
1d793c485e | ||
04a2b4d248 | |||
15d36eeff4 | |||
3c2efe04de | |||
![]() |
d33f250a56 | ||
23c5973501 | |||
394f66dde9 | |||
8f3a8539cb | |||
059480fad1 | |||
3b70416b66 | |||
![]() |
4f71011b1a | ||
![]() |
e9585fa4dd | ||
85a7ed24ab | |||
dfaec30fac | |||
1d10d65adb | |||
71193a2e50 | |||
580644f9d4 | |||
ea5a4ad7bf | |||
f94c2b5962 | |||
ac1639b77e | |||
e4c7ad0994 | |||
c07ab0e029 | |||
![]() |
a56cc772f7 | ||
7783d26d4c | |||
![]() |
ba3255d9ec | ||
dd3a2e91bd | |||
118efd0b62 | |||
3cfd403b94 | |||
bd7df4f6a0 | |||
31a9049861 | |||
![]() |
013b835ed8 | ||
![]() |
271850f75a | ||
5f847a8d40 | |||
eaece8e334 | |||
91c9952f7c | |||
04330ff407 | |||
![]() |
916a272e8f | ||
![]() |
520e7d5c0d | ||
![]() |
374b688ddf | ||
![]() |
12986c15b3 | ||
![]() |
070d232681 | ||
![]() |
ede651525b | ||
![]() |
435ce32fbd | ||
![]() |
6dfdb09cf6 | ||
7a874ef89f | |||
33ccea8cbc | |||
30e9fcd20f | |||
8173993601 | |||
5f2d0aa426 | |||
22e44ca9f2 | |||
23bc58806c | |||
1ba7479469 | |||
b5b65a4c42 | |||
4d61557a70 | |||
![]() |
6aa95eedf2 | ||
62d69330b0 | |||
d806342a83 | |||
061f3a1e77 | |||
![]() |
37c28e89d8 | ||
![]() |
29e551684e | ||
![]() |
e6625e55c3 | ||
![]() |
e9f32eae3b | ||
![]() |
2ed14e7e56 | ||
![]() |
37362f0b3b | ||
![]() |
284df4ab4d | ||
![]() |
6bb2222c17 | ||
![]() |
271c48e264 | ||
![]() |
3ac1794e14 | ||
![]() |
0f92e6cd98 | ||
![]() |
bcf722ae34 | ||
![]() |
aabc607ed6 | ||
![]() |
68eb59a934 | ||
![]() |
3d4bddbb4c | ||
![]() |
b9fa079048 | ||
![]() |
ba2c117eb5 | ||
![]() |
f5b8953601 | ||
24e90deb62 | |||
08ec3988fd | |||
49785e66f2 | |||
106254664d | |||
![]() |
6d271970fe | ||
![]() |
8f9f8ac928 | ||
![]() |
b2b823446f | ||
![]() |
f615510256 | ||
![]() |
f484228191 | ||
a4fcdf60c7 | |||
ffaaba7abb | |||
e7a06c443d | |||
077bd1ce44 | |||
22633bdac3 | |||
4f795289d5 |
121 changed files with 5663 additions and 455 deletions
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
|
@ -13,7 +13,6 @@ body:
|
|||
label: Describe the Bug
|
||||
description: What happened?
|
||||
placeholder: A clear and concise description of what the bug is.
|
||||
render: markdown
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
@ -21,7 +20,6 @@ body:
|
|||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What did you expect to happen instead?
|
||||
render: markdown
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
|
@ -29,7 +27,6 @@ body:
|
|||
attributes:
|
||||
label: To Reproduce
|
||||
description: What steps are required to reproduce the bug?
|
||||
render: markdown
|
||||
placeholder: |
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
|
@ -45,6 +42,5 @@ body:
|
|||
description: |
|
||||
What device are you using? Adding this information helps to reproduce the bug.
|
||||
You can copy this from µLauncher > Settings > Meta > Report Bug.
|
||||
render: markdown
|
||||
validations:
|
||||
required: false
|
||||
|
|
|
@ -1,9 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script builds all variants of µLauncher to create a release, namely:
|
||||
# - app-release.apk (GitHub release; used by F-Droid for reproducible builds)
|
||||
# - launcher-accrescent.apks (Accrescent)
|
||||
# - app-release.aab (Play Store)
|
||||
|
||||
# This is only intended to work on my (@jrpie) computer.
|
||||
# To use this script for building a fork you need to:
|
||||
# - install bundletool.jar and
|
||||
# - create a keystore and modify the variables below accordingly
|
||||
|
||||
export JAVA_HOME="/usr/lib/jvm/java-21-openjdk/"
|
||||
OUTPUT_DIR="$HOME/launcher-release"
|
||||
BUILD_TOOLS_DIR="$HOME/Android/Sdk/build-tools/35.0.0"
|
||||
|
||||
# keystore for the default release
|
||||
KEYSTORE="$HOME/data/keys/launcher_jrpie.jks"
|
||||
# keystore for the default accrescent release
|
||||
KEYSTORE_ACCRESCENT="$HOME/data/keys/launcher_jrpie_accrescent.jks"
|
||||
|
||||
# keepassxc-password is a custom script to fetch passwords from my password manager
|
||||
KEYSTORE_PASS=$(keepassxc-password "android_keys/launcher")
|
||||
KEYSTORE_ACCRESCENT_PASS=$(keepassxc-password "android_keys/launcher-accrescent")
|
||||
|
||||
|
@ -11,12 +27,11 @@ if [[ $(git status --porcelain) ]]; then
|
|||
echo "There are uncommitted changes."
|
||||
|
||||
read -p "Continue anyway? (y/n) " -n 1 -r
|
||||
echo # (optional) move to a new line
|
||||
echo
|
||||
if ! [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
rm -rf "$OUTPUT_DIR"
|
||||
|
|
|
@ -23,8 +23,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 35
|
||||
compileSdk 35
|
||||
versionCode 44
|
||||
versionName "0.1.4"
|
||||
versionCode 48
|
||||
versionName "0.2.3"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ dependencies {
|
|||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
|
||||
implementation "eu.jonahbauer:android-preference-annotations:1.1.2"
|
||||
implementation 'androidx.activity:activity:1.10.1'
|
||||
annotationProcessor "eu.jonahbauer:android-preference-annotations:1.1.2"
|
||||
annotationProcessor "com.android.databinding:compiler:$android_plugin_version"
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES" />
|
||||
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application
|
||||
android:name=".Application"
|
||||
|
@ -19,6 +20,21 @@
|
|||
android:supportsRtl="true"
|
||||
android:theme="@style/launcherBaseTheme"
|
||||
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:configChanges="orientation|screenSize"
|
||||
android:exported="false"
|
||||
android:theme="@style/launcherHomeTheme" />
|
||||
<activity
|
||||
android:name=".ui.widgets.manage.SelectWidgetActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.PinShortcutActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
|
@ -66,6 +82,9 @@
|
|||
<activity
|
||||
android:name=".ui.LegalInfoActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.ReportCrashActivity"
|
||||
android:exported="false" />
|
||||
|
||||
<receiver
|
||||
android:name=".actions.lock.LauncherDeviceAdmin"
|
||||
|
@ -96,5 +115,4 @@
|
|||
android:resource="@xml/accessibility_service_config" />
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
|
@ -12,6 +12,8 @@ import android.os.Build.VERSION_CODES
|
|||
import android.os.UserHandle
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import android.appwidget.AppWidgetHost
|
||||
import android.appwidget.AppWidgetManager
|
||||
import androidx.preference.PreferenceManager
|
||||
import de.jrpie.android.launcher.actions.TorchManager
|
||||
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||
|
@ -23,10 +25,17 @@ import de.jrpie.android.launcher.preferences.resetPreferences
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
||||
const val APP_WIDGET_HOST_ID = 42
|
||||
|
||||
|
||||
class Application : android.app.Application() {
|
||||
val apps = MutableLiveData<List<AbstractDetailedAppInfo>>()
|
||||
val privateSpaceLocked = MutableLiveData<Boolean>()
|
||||
lateinit var appWidgetHost: AppWidgetHost
|
||||
lateinit var appWidgetManager: AppWidgetManager
|
||||
|
||||
private val profileAvailabilityBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
|
@ -98,15 +107,23 @@ class Application : android.app.Application() {
|
|||
// TODO Error: Invalid resource ID 0x00000000.
|
||||
// DynamicColors.applyToActivitiesIfAvailable(this)
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler { _, throwable ->
|
||||
sendCrashNotification(this@Application, throwable)
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
|
||||
if (Build.VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||
torchManager = TorchManager(this)
|
||||
}
|
||||
|
||||
appWidgetHost = AppWidgetHost(this.applicationContext, APP_WIDGET_HOST_ID)
|
||||
appWidgetManager = AppWidgetManager.getInstance(this.applicationContext)
|
||||
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
LauncherPreferences.init(preferences, this.resources)
|
||||
|
||||
|
||||
// Try to restore old preferences
|
||||
migratePreferencesToNewVersion(this)
|
||||
|
||||
|
@ -144,6 +161,8 @@ class Application : android.app.Application() {
|
|||
removeUnusedShortcuts(this)
|
||||
}
|
||||
loadApps()
|
||||
|
||||
createNotificationChannels(this)
|
||||
}
|
||||
|
||||
fun getCustomAppNames(): HashMap<AbstractAppInfo, String> {
|
||||
|
|
|
@ -223,4 +223,14 @@ fun copyToClipboard(context: Context, text: String) {
|
|||
val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipData = ClipData.newPlainText("Debug Info", text)
|
||||
clipboardManager.setPrimaryClip(clipData)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeEmail(context: Context, to: String, subject: String, text: String) {
|
||||
val intent = Intent(Intent.ACTION_SENDTO)
|
||||
intent.setData("mailto:".toUri())
|
||||
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(to))
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text)
|
||||
context.startActivity(Intent.createChooser(intent, context.getString(R.string.send_email)))
|
||||
}
|
||||
|
||||
|
|
87
app/src/main/java/de/jrpie/android/launcher/Notifications.kt
Normal file
87
app/src/main/java/de/jrpie/android/launcher/Notifications.kt
Normal file
|
@ -0,0 +1,87 @@
|
|||
package de.jrpie.android.launcher
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import de.jrpie.android.launcher.ui.EXTRA_CRASH_LOG
|
||||
import de.jrpie.android.launcher.ui.ReportCrashActivity
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import kotlin.random.Random
|
||||
|
||||
private val NOTIFICATION_CHANNEL_CRASH = "launcher:crash"
|
||||
|
||||
fun createNotificationChannels(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationChannel = NotificationChannel(
|
||||
NOTIFICATION_CHANNEL_CRASH,
|
||||
context.getString(R.string.notification_channel_crash),
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
)
|
||||
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestNotificationPermission(activity: Activity) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
return
|
||||
}
|
||||
|
||||
val permission =
|
||||
(activity.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED)
|
||||
|
||||
if (!permission) {
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
arrayOf( android.Manifest.permission.POST_NOTIFICATIONS ),
|
||||
1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun sendCrashNotification(context: Context, throwable: Throwable) {
|
||||
val stringWriter = StringWriter()
|
||||
val printWriter = PrintWriter(stringWriter)
|
||||
throwable.printStackTrace(printWriter)
|
||||
|
||||
val intent = Intent(context, ReportCrashActivity::class.java)
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
intent.putExtra(EXTRA_CRASH_LOG, stringWriter.toString())
|
||||
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
Random.nextInt(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_CRASH)
|
||||
.setSmallIcon(R.drawable.baseline_bug_report_24)
|
||||
.setContentTitle(context.getString(R.string.notification_crash_title))
|
||||
.setContentText(context.getString(R.string.notification_crash_explanation))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(false)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
|
||||
val notificationManager = NotificationManagerCompat.from(context)
|
||||
try {
|
||||
notificationManager.notify(
|
||||
0,
|
||||
builder.build()
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e("Crash Notification", "Could not send notification")
|
||||
}
|
||||
}
|
|
@ -6,14 +6,18 @@ import android.content.SharedPreferences.Editor
|
|||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.edit
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import androidx.core.content.edit
|
||||
|
||||
|
||||
/**
|
||||
* Represents an action that can be bound to a [Gesture].
|
||||
* There are four types of actions: [AppAction], [ShortcutAction], [LauncherAction] and [WidgetPanelAction]
|
||||
*/
|
||||
@Serializable
|
||||
sealed interface Action {
|
||||
fun invoke(context: Context, rect: Rect? = null): Boolean
|
||||
|
@ -21,6 +25,10 @@ sealed interface Action {
|
|||
fun getIcon(context: Context): Drawable?
|
||||
fun isAvailable(context: Context): Boolean
|
||||
|
||||
fun showConfigurationDialog(context: Context, onSuccess: (Action) -> Unit) {
|
||||
onSuccess(this)
|
||||
}
|
||||
|
||||
// Can the action be used to reach µLauncher settings?
|
||||
fun canReachSettings(): Boolean
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package de.jrpie.android.launcher.actions
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.camera2.CameraAccessException
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.os.Build
|
||||
|
@ -78,7 +77,8 @@ class TorchManager(context: Context) {
|
|||
cameraManager.setTorchMode(camera, !torchEnabled)
|
||||
}
|
||||
|
||||
} catch (e: CameraAccessException) {
|
||||
} catch (e: Exception) {
|
||||
// CameraAccessException, IllegalArgumentException
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.alert_torch_access_exception),
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
package de.jrpie.android.launcher.actions
|
||||
|
||||
import android.app.Activity
|
||||
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 (context is WidgetPanelActivity) {
|
||||
if (context.widgetPanelId == widgetPanelId) {
|
||||
context.finish()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (WidgetPanel.byId(this.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, this.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
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ import android.widget.Button
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import de.jrpie.android.launcher.BuildConfig
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.actions.lock.LauncherAccessibilityService
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
|
||||
|
||||
|
|
|
@ -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.SetAbstractAppInfoPreferenceSerializer;
|
||||
import de.jrpie.android.launcher.preferences.serialization.SetPinnedShortcutInfoPreferenceSerializer;
|
||||
import de.jrpie.android.launcher.preferences.serialization.SetWidgetPanelSerializer;
|
||||
import de.jrpie.android.launcher.preferences.serialization.SetWidgetSerializer;
|
||||
import de.jrpie.android.launcher.preferences.theme.Background;
|
||||
import de.jrpie.android.launcher.preferences.theme.ColorTheme;
|
||||
import de.jrpie.android.launcher.preferences.theme.Font;
|
||||
|
@ -72,6 +74,7 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
|
|||
@Preference(name = "search_auto_launch", type = boolean.class, defaultValue = "true"),
|
||||
@Preference(name = "search_web", type = boolean.class, description = "false"),
|
||||
@Preference(name = "search_auto_open_keyboard", type = boolean.class, defaultValue = "true"),
|
||||
@Preference(name = "search_auto_close_keyboard", type = boolean.class, defaultValue = "false"),
|
||||
}),
|
||||
@PreferenceGroup(name = "enabled_gestures", prefix = "settings_enabled_gestures_", suffix = "_key", value = {
|
||||
@Preference(name = "double_swipe", type = boolean.class, defaultValue = "true"),
|
||||
|
@ -81,5 +84,9 @@ import eu.jonahbauer.android.preference.annotations.Preferences;
|
|||
@PreferenceGroup(name = "actions", prefix = "settings_actions_", suffix = "_key", value = {
|
||||
@Preference(name = "lock_method", type = LockMethod.class, defaultValue = "DEVICE_ADMIN"),
|
||||
}),
|
||||
@PreferenceGroup(name = "widgets", prefix = "settings_widgets_", suffix= "_key", value = {
|
||||
@Preference(name = "widgets", type = Set.class, serializer = SetWidgetSerializer.class),
|
||||
@Preference(name = "custom_panels", type = Set.class, serializer = SetWidgetPanelSerializer.class)
|
||||
}),
|
||||
})
|
||||
public final class LauncherPreferences$Config {}
|
|
@ -4,21 +4,30 @@ import android.content.Context
|
|||
import android.util.Log
|
||||
import de.jrpie.android.launcher.BuildConfig
|
||||
import de.jrpie.android.launcher.actions.Action
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||
import de.jrpie.android.launcher.apps.AbstractAppInfo.Companion.INVALID_USER
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion1
|
||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion100
|
||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion2
|
||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion3
|
||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersion4
|
||||
import de.jrpie.android.launcher.preferences.legacy.migratePreferencesFromVersionUnknown
|
||||
import de.jrpie.android.launcher.sendCrashNotification
|
||||
import de.jrpie.android.launcher.ui.HomeActivity
|
||||
import de.jrpie.android.launcher.widgets.ClockWidget
|
||||
import de.jrpie.android.launcher.widgets.DebugInfoWidget
|
||||
import de.jrpie.android.launcher.widgets.WidgetPanel
|
||||
import de.jrpie.android.launcher.widgets.WidgetPosition
|
||||
import de.jrpie.android.launcher.widgets.generateInternalId
|
||||
import de.jrpie.android.launcher.widgets.getAppWidgetHost
|
||||
|
||||
/* Current version of the structure of preferences.
|
||||
* Increase when breaking changes are introduced and write an appropriate case in
|
||||
* `migratePreferencesToNewVersion`
|
||||
*/
|
||||
const val PREFERENCE_VERSION = 4
|
||||
const val PREFERENCE_VERSION = 101
|
||||
const val UNKNOWN_PREFERENCE_VERSION = -1
|
||||
private const val TAG = "Launcher - Preferences"
|
||||
|
||||
|
@ -40,18 +49,28 @@ fun migratePreferencesToNewVersion(context: Context) {
|
|||
}
|
||||
|
||||
1 -> {
|
||||
migratePreferencesFromVersion1()
|
||||
migratePreferencesFromVersion1(context)
|
||||
Log.i(TAG, "migration of preferences complete (1 -> ${PREFERENCE_VERSION}).")
|
||||
}
|
||||
2 -> {
|
||||
migratePreferencesFromVersion2()
|
||||
migratePreferencesFromVersion2(context)
|
||||
Log.i(TAG, "migration of preferences complete (2 -> ${PREFERENCE_VERSION}).")
|
||||
}
|
||||
3 -> {
|
||||
migratePreferencesFromVersion3()
|
||||
migratePreferencesFromVersion3(context)
|
||||
Log.i(TAG, "migration of preferences complete (3 -> ${PREFERENCE_VERSION}).")
|
||||
}
|
||||
|
||||
// There was a bug where instead of the preference version the app version was written.
|
||||
in 4..99 -> {
|
||||
migratePreferencesFromVersion4(context)
|
||||
Log.i(TAG, "migration of preferences complete (4 -> ${PREFERENCE_VERSION}).")
|
||||
}
|
||||
100 -> {
|
||||
migratePreferencesFromVersion100(context)
|
||||
Log.i(TAG, "migration of preferences complete (100 -> ${PREFERENCE_VERSION}).")
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.w(
|
||||
TAG,
|
||||
|
@ -63,6 +82,7 @@ fun migratePreferencesToNewVersion(context: Context) {
|
|||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to restore preferences:\n${e.stackTrace}")
|
||||
sendCrashNotification(context, e)
|
||||
resetPreferences(context)
|
||||
}
|
||||
}
|
||||
|
@ -71,18 +91,45 @@ fun resetPreferences(context: Context) {
|
|||
Log.i(TAG, "Resetting preferences")
|
||||
LauncherPreferences.clear()
|
||||
LauncherPreferences.internal().versionCode(PREFERENCE_VERSION)
|
||||
context.getAppWidgetHost().deleteHost()
|
||||
|
||||
LauncherPreferences.widgets().widgets(
|
||||
setOf(
|
||||
ClockWidget(
|
||||
generateInternalId(),
|
||||
WidgetPosition(1, 3, 10, 4),
|
||||
WidgetPanel.HOME.id
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
LauncherPreferences.widgets().widgets(
|
||||
LauncherPreferences.widgets().widgets().also {
|
||||
it.add(
|
||||
DebugInfoWidget(
|
||||
generateInternalId(),
|
||||
WidgetPosition(1, 1, 10, 4),
|
||||
WidgetPanel.HOME.id
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val hidden: MutableSet<AbstractAppInfo> = mutableSetOf()
|
||||
val launcher = DetailedAppInfo.fromAppInfo(
|
||||
AppInfo(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
HomeActivity::class.java.name,
|
||||
INVALID_USER
|
||||
), context
|
||||
)
|
||||
launcher?.getRawInfo()?.let { hidden.add(it) }
|
||||
Log.i(TAG,"Hiding ${launcher?.getRawInfo()}")
|
||||
|
||||
if (!BuildConfig.DEBUG) {
|
||||
val launcher = DetailedAppInfo.fromAppInfo(
|
||||
AppInfo(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
HomeActivity::class.java.name,
|
||||
INVALID_USER
|
||||
), context
|
||||
)
|
||||
launcher?.getRawInfo()?.let { hidden.add(it) }
|
||||
Log.i(TAG, "Hiding ${launcher?.getRawInfo()}")
|
||||
}
|
||||
LauncherPreferences.apps().hidden(hidden)
|
||||
|
||||
Action.resetToDefaultActions(context)
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package de.jrpie.android.launcher.preferences.legacy
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import de.jrpie.android.launcher.actions.Action
|
||||
import de.jrpie.android.launcher.actions.AppAction
|
||||
import de.jrpie.android.launcher.actions.Gesture
|
||||
import de.jrpie.android.launcher.actions.LauncherAction
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
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.PREFERENCE_VERSION
|
||||
import kotlinx.serialization.Serializable
|
||||
|
@ -13,7 +15,6 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import androidx.core.content.edit
|
||||
|
||||
|
||||
@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
|
||||
* (see [PREFERENCE_VERSION])
|
||||
*/
|
||||
fun migratePreferencesFromVersion1() {
|
||||
fun migratePreferencesFromVersion1(context: Context) {
|
||||
assert(LauncherPreferences.internal().versionCode() == 1)
|
||||
Gesture.entries.forEach { g -> migrateAction(g.id) }
|
||||
migrateAppInfoSet(LauncherPreferences.apps().keys().hidden())
|
||||
|
@ -137,5 +138,5 @@ fun migratePreferencesFromVersion1() {
|
|||
migrateAppInfoStringMap(LauncherPreferences.apps().keys().customNames())
|
||||
LauncherPreferences.internal().versionCode(2)
|
||||
|
||||
migratePreferencesFromVersion2()
|
||||
migratePreferencesFromVersion2(context)
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
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.DebugInfoWidget
|
||||
import de.jrpie.android.launcher.widgets.generateInternalId
|
||||
import de.jrpie.android.launcher.widgets.updateWidget
|
||||
|
||||
fun migratePreferencesFromVersion100(context: Context) {
|
||||
assert(PREFERENCE_VERSION == 101)
|
||||
assert(LauncherPreferences.internal().versionCode() == 100)
|
||||
|
||||
val widgets = LauncherPreferences.widgets().widgets() ?: setOf()
|
||||
widgets.forEach { widget ->
|
||||
when (widget) {
|
||||
is ClockWidget -> {
|
||||
val id = widget.id
|
||||
val newId = generateInternalId()
|
||||
(context.applicationContext as Application).appWidgetHost.deleteAppWidgetId(id)
|
||||
widget.delete(context)
|
||||
widget.id = newId
|
||||
updateWidget(widget)
|
||||
}
|
||||
is DebugInfoWidget -> {
|
||||
val id = widget.id
|
||||
val newId = generateInternalId()
|
||||
(context.applicationContext as Application).appWidgetHost.deleteAppWidgetId(id)
|
||||
widget.delete(context)
|
||||
widget.id = newId
|
||||
updateWidget(widget)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
LauncherPreferences.internal().versionCode(101)
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package de.jrpie.android.launcher.preferences.legacy
|
||||
|
||||
import android.content.Context
|
||||
import de.jrpie.android.launcher.actions.Action
|
||||
import de.jrpie.android.launcher.actions.Gesture
|
||||
import de.jrpie.android.launcher.actions.LauncherAction
|
||||
|
@ -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
|
||||
* (see [PREFERENCE_VERSION])
|
||||
*/
|
||||
fun migratePreferencesFromVersion2() {
|
||||
fun migratePreferencesFromVersion2(context: Context) {
|
||||
assert(LauncherPreferences.internal().versionCode() == 2)
|
||||
// previously there was no setting for this
|
||||
Action.setActionForGesture(Gesture.BACK, LauncherAction.CHOOSE)
|
||||
LauncherPreferences.internal().versionCode(3)
|
||||
migratePreferencesFromVersion3()
|
||||
migratePreferencesFromVersion3(context)
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
package de.jrpie.android.launcher.preferences.legacy
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.Editor
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
import androidx.core.content.edit
|
||||
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.PREFERENCE_VERSION
|
||||
import de.jrpie.android.launcher.preferences.serialization.MapAbstractAppInfoStringPreferenceSerializer
|
||||
import de.jrpie.android.launcher.preferences.serialization.SetAbstractAppInfoPreferenceSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.util.HashSet
|
||||
import androidx.core.content.edit
|
||||
|
||||
/**
|
||||
* Migrate preferences from version 3 (used until version 0.0.23) to the current format
|
||||
|
@ -70,8 +70,7 @@ private fun migrateMapAppInfoString(key: String, preferences: SharedPreferences,
|
|||
}
|
||||
}
|
||||
|
||||
fun migratePreferencesFromVersion3() {
|
||||
assert(PREFERENCE_VERSION == 4)
|
||||
fun migratePreferencesFromVersion3(context: Context) {
|
||||
assert(LauncherPreferences.internal().versionCode() == 3)
|
||||
|
||||
val preferences = LauncherPreferences.getSharedPreferences()
|
||||
|
@ -82,4 +81,5 @@ fun migratePreferencesFromVersion3() {
|
|||
}
|
||||
|
||||
LauncherPreferences.internal().versionCode(4)
|
||||
migratePreferencesFromVersion4(context)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package de.jrpie.android.launcher.preferences.legacy
|
||||
|
||||
import android.content.Context
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
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.generateInternalId
|
||||
|
||||
fun migratePreferencesFromVersion4(context: Context) {
|
||||
assert(LauncherPreferences.internal().versionCode() < 100)
|
||||
|
||||
LauncherPreferences.widgets().widgets(
|
||||
setOf(
|
||||
ClockWidget(
|
||||
generateInternalId(),
|
||||
WidgetPosition(1, 3, 10, 4),
|
||||
WidgetPanel.HOME.id
|
||||
)
|
||||
)
|
||||
)
|
||||
LauncherPreferences.internal().versionCode(100)
|
||||
migratePreferencesFromVersion100(context)
|
||||
}
|
|
@ -3,10 +3,10 @@ package de.jrpie.android.launcher.preferences.legacy
|
|||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.preferences.theme.Background
|
||||
import de.jrpie.android.launcher.preferences.theme.ColorTheme
|
||||
import androidx.core.content.edit
|
||||
|
||||
|
||||
private fun migrateStringPreference(
|
||||
|
@ -392,5 +392,5 @@ fun migratePreferencesFromVersionUnknown(context: Context) {
|
|||
LauncherPreferences.internal().versionCode(1)
|
||||
Log.i(TAG, "migrated preferences to version 1.")
|
||||
|
||||
migratePreferencesFromVersion1()
|
||||
migratePreferencesFromVersion1(context)
|
||||
}
|
|
@ -4,6 +4,8 @@ package de.jrpie.android.launcher.preferences.serialization
|
|||
|
||||
import de.jrpie.android.launcher.apps.AbstractAppInfo
|
||||
import de.jrpie.android.launcher.apps.PinnedShortcutInfo
|
||||
import de.jrpie.android.launcher.widgets.Widget
|
||||
import de.jrpie.android.launcher.widgets.WidgetPanel
|
||||
import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializationException
|
||||
import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
|
@ -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")
|
||||
class SetPinnedShortcutInfoPreferenceSerializer :
|
||||
PreferenceSerializer<java.util.Set<PinnedShortcutInfo>?, java.util.Set<java.lang.String>?> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package de.jrpie.android.launcher.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.ColorMatrix
|
||||
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) {
|
||||
this.requestFocus()
|
||||
// open the soft keyboard
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
|
||||
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
|
||||
.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 )
|
||||
}
|
||||
}
|
|
@ -1,26 +1,18 @@
|
|||
package de.jrpie.android.launcher.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.window.OnBackInvokedDispatcher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.Application
|
||||
import de.jrpie.android.launcher.actions.Action
|
||||
import de.jrpie.android.launcher.actions.Gesture
|
||||
import de.jrpie.android.launcher.actions.LauncherAction
|
||||
import de.jrpie.android.launcher.databinding.HomeBinding
|
||||
import de.jrpie.android.launcher.databinding.ActivityHomeBinding
|
||||
import de.jrpie.android.launcher.openTutorial
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
|
||||
import java.util.Locale
|
||||
import de.jrpie.android.launcher.ui.util.LauncherGestureActivity
|
||||
|
||||
/**
|
||||
* [HomeActivity] is the actual application Launcher,
|
||||
|
@ -34,10 +26,9 @@ import java.util.Locale
|
|||
* - Setting global variables (preferences etc.)
|
||||
* - Opening the [TutorialActivity] on new installations
|
||||
*/
|
||||
class HomeActivity : UIObject, AppCompatActivity() {
|
||||
class HomeActivity : UIObject, LauncherGestureActivity() {
|
||||
|
||||
private lateinit var binding: HomeBinding
|
||||
private lateinit var touchGestureDetector: TouchGestureDetector
|
||||
private lateinit var binding: ActivityHomeBinding
|
||||
|
||||
private var sharedPreferencesListener =
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
|
||||
|
@ -45,61 +36,32 @@ class HomeActivity : UIObject, AppCompatActivity() {
|
|||
prefKey?.startsWith("display.") == true
|
||||
) {
|
||||
recreate()
|
||||
} else if (prefKey?.startsWith("action.") == true) {
|
||||
updateSettingsFallbackButtonVisibility()
|
||||
} else if (prefKey == LauncherPreferences.widgets().keys().widgets()) {
|
||||
binding.homeWidgetContainer.updateWidgets(this@HomeActivity,
|
||||
LauncherPreferences.widgets().widgets()
|
||||
)
|
||||
}
|
||||
|
||||
if (prefKey?.startsWith("action.") == true) {
|
||||
updateSettingsFallbackButtonVisibility()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super<AppCompatActivity>.onCreate(savedInstanceState)
|
||||
super<LauncherGestureActivity>.onCreate(savedInstanceState)
|
||||
super<UIObject>.onCreate()
|
||||
|
||||
touchGestureDetector = TouchGestureDetector(
|
||||
this, 0, 0,
|
||||
LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
|
||||
)
|
||||
touchGestureDetector.updateScreenSize(windowManager)
|
||||
|
||||
// Initialise layout
|
||||
binding = HomeBinding.inflate(layoutInflater)
|
||||
binding = ActivityHomeBinding.inflate(layoutInflater)
|
||||
|
||||
setContentView(binding.root)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
binding.root.setOnApplyWindowInsetsListener { _, windowInsets ->
|
||||
@Suppress("deprecation") // required to support API 29
|
||||
val insets = windowInsets.systemGestureInsets
|
||||
touchGestureDetector.setSystemGestureInsets(insets)
|
||||
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Handle back key / gesture on Android 13+, cf. onKeyDown()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
onBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_OVERLAY
|
||||
) {
|
||||
handleBack()
|
||||
}
|
||||
}
|
||||
binding.buttonFallbackSettings.setOnClickListener {
|
||||
LauncherAction.SETTINGS.invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
touchGestureDetector.updateScreenSize(windowManager)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super<AppCompatActivity>.onStart()
|
||||
|
||||
super<LauncherGestureActivity>.onStart()
|
||||
super<UIObject>.onStart()
|
||||
|
||||
// If the tutorial was not finished, start it
|
||||
|
@ -120,7 +82,6 @@ class HomeActivity : UIObject, AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateSettingsFallbackButtonVisibility() {
|
||||
// If µLauncher settings can not be reached from any action bound to an enabled gesture,
|
||||
// show the fallback button.
|
||||
|
@ -135,129 +96,46 @@ 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 {
|
||||
return modifyTheme(super.getTheme())
|
||||
}
|
||||
|
||||
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 onPause() {
|
||||
try {
|
||||
(application as Application).appWidgetHost.stopListening()
|
||||
} catch (e: Exception) {
|
||||
// Throws a NullPointerException on Android 12 an earlier, see #172
|
||||
e.printStackTrace()
|
||||
}
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
touchGestureDetector.edgeWidth =
|
||||
LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
|
||||
|
||||
initClock()
|
||||
updateSettingsFallbackButtonVisibility()
|
||||
|
||||
binding.homeWidgetContainer.updateWidgets(this@HomeActivity,
|
||||
LauncherPreferences.widgets().widgets()
|
||||
)
|
||||
|
||||
(application as Application).appWidgetHost.startListening()
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
LauncherPreferences.getSharedPreferences()
|
||||
.unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
@SuppressLint("GestureBackNavigation")
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_BACK -> {
|
||||
// Only used pre Android 13, cf. onBackInvokedDispatcher
|
||||
handleBack()
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||
if (Action.forGesture(Gesture.VOLUME_UP) == LauncherAction.VOLUME_UP) {
|
||||
// Let the OS handle the key event. This works better with some custom ROMs
|
||||
// and apps like Samsung Sound Assistant.
|
||||
return false
|
||||
}
|
||||
Gesture.VOLUME_UP(this)
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||
if (Action.forGesture(Gesture.VOLUME_DOWN) == LauncherAction.VOLUME_DOWN) {
|
||||
// see above
|
||||
return false
|
||||
}
|
||||
Gesture.VOLUME_DOWN(this)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
touchGestureDetector.onTouchEvent(event)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun setOnClicks() {
|
||||
|
||||
binding.homeUpperView.setOnClickListener {
|
||||
if (LauncherPreferences.clock().flipDateTime()) {
|
||||
Gesture.TIME(this)
|
||||
} else {
|
||||
Gesture.DATE(this)
|
||||
}
|
||||
}
|
||||
|
||||
binding.homeLowerView.setOnClickListener {
|
||||
if (LauncherPreferences.clock().flipDateTime()) {
|
||||
Gesture.DATE(this)
|
||||
} else {
|
||||
Gesture.TIME(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun handleBack() {
|
||||
override fun handleBack() {
|
||||
Gesture.BACK(this)
|
||||
}
|
||||
|
||||
override fun getRootView(): View {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun isHomeScreen(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package de.jrpie.android.launcher.ui
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.LauncherApps.PinItemRequest
|
||||
|
@ -45,11 +44,25 @@ class PinShortcutActivity : AppCompatActivity(), UIObject {
|
|||
binding = ActivityPinShortcutBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
val launcherApps = getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val launcherApps = getSystemService(LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
|
||||
val request = launcherApps.getPinItemRequest(intent)
|
||||
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 handle app widgets
|
||||
request.getAppWidgetProviderInfo(this)
|
||||
// startActivity()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
if (request.requestType != PinItemRequest.REQUEST_TYPE_SHORTCUT) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package de.jrpie.android.launcher.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.copyToClipboard
|
||||
import de.jrpie.android.launcher.databinding.ActivityReportCrashBinding
|
||||
import de.jrpie.android.launcher.getDeviceInfo
|
||||
import de.jrpie.android.launcher.openInBrowser
|
||||
import de.jrpie.android.launcher.writeEmail
|
||||
|
||||
const val EXTRA_CRASH_LOG = "crashLog"
|
||||
|
||||
class ReportCrashActivity : AppCompatActivity() {
|
||||
// We don't know what caused the crash, so this Activity should use as little functionality as possible.
|
||||
// In particular it is not a UIObject (and hence looks quite ugly)
|
||||
private lateinit var binding: ActivityReportCrashBinding
|
||||
private var report: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Initialise layout
|
||||
binding = ActivityReportCrashBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setTitle(R.string.report_crash_title)
|
||||
setSupportActionBar(binding.reportCrashAppbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||
|
||||
report = intent.getStringExtra(EXTRA_CRASH_LOG)
|
||||
|
||||
binding.reportCrashButtonCopy.setOnClickListener {
|
||||
copyToClipboard(this,
|
||||
"Device Info:\n${getDeviceInfo()}\n\nCrash Log:\n${report}")
|
||||
}
|
||||
|
||||
binding.reportCrashButtonMail.setOnClickListener {
|
||||
writeEmail(
|
||||
this,
|
||||
getString(R.string.settings_meta_report_bug_mail),
|
||||
"Crash in μLauncher",
|
||||
"Hi!\nUnfortunately, μLauncher crashed:\n" +
|
||||
"\nDevice Info\n\n${getDeviceInfo()}\n\n" +
|
||||
"\nCrash Log\n\n${report}\n" +
|
||||
"\nAdditional Information\n\n" +
|
||||
"[Please add additional information: What did you do when the crash happened? Do you know how to trigger it? ... ]"
|
||||
)
|
||||
}
|
||||
binding.reportCrashButtonReport.setOnClickListener {
|
||||
openInBrowser(
|
||||
getString(R.string.settings_meta_report_bug_link),
|
||||
this
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ import kotlin.math.max
|
|||
import kotlin.math.min
|
||||
import kotlin.math.tan
|
||||
|
||||
@Suppress("PrivatePropertyName")
|
||||
class TouchGestureDetector(
|
||||
private val context: Context,
|
||||
var width: Int,
|
||||
|
@ -34,13 +35,13 @@ class TouchGestureDetector(
|
|||
|
||||
private val MIN_TRIANGLE_HEIGHT = 250
|
||||
|
||||
private val longPressHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var systemGestureInsetTop = 100
|
||||
private var systemGestureInsetBottom = 0
|
||||
private var systemGestureInsetLeft = 0
|
||||
private var systemGestureInsetRight = 0
|
||||
|
||||
private val longPressHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
|
||||
data class Vector(val x: Float, val y: Float) {
|
||||
fun absSquared(): Float {
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.view.WindowInsets
|
|||
import android.view.WindowInsetsController
|
||||
import android.view.WindowManager
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.preferences.theme.Background
|
||||
|
||||
/**
|
||||
* An interface implemented by every [Activity], Fragment etc. in Launcher.
|
||||
|
@ -65,8 +66,14 @@ interface UIObject {
|
|||
theme,
|
||||
LauncherPreferences.theme().textShadow()
|
||||
)
|
||||
LauncherPreferences.theme().background().applyToTheme(theme)
|
||||
LauncherPreferences.theme().font().applyToTheme(theme)
|
||||
|
||||
if (isHomeScreen()) {
|
||||
Background.TRANSPARENT.applyToTheme(theme)
|
||||
LauncherPreferences.clock().font().applyToTheme(theme)
|
||||
} else {
|
||||
LauncherPreferences.theme().background().applyToTheme(theme)
|
||||
LauncherPreferences.theme().font().applyToTheme(theme)
|
||||
}
|
||||
|
||||
return theme
|
||||
}
|
||||
|
|
|
@ -237,9 +237,4 @@ class AppsRecyclerAdapter(
|
|||
appFilter.favoritesVisibility = v
|
||||
updateAppsList()
|
||||
}
|
||||
|
||||
fun setHiddenAppsVisibility(v: AppFilter.Companion.AppSetVisibility) {
|
||||
appFilter.hiddenVisibility = v
|
||||
updateAppsList()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,13 +11,16 @@ import android.widget.Toast
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.apps.AppFilter
|
||||
import de.jrpie.android.launcher.databinding.ListAppsBinding
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.ui.UIObject
|
||||
import de.jrpie.android.launcher.ui.closeSoftKeyboard
|
||||
import de.jrpie.android.launcher.ui.list.ListActivity
|
||||
import de.jrpie.android.launcher.ui.openSoftKeyboard
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
/**
|
||||
|
@ -90,6 +93,19 @@ class ListFragmentApps : Fragment(), UIObject {
|
|||
}
|
||||
}
|
||||
adapter = appsRecyclerAdapter
|
||||
if (LauncherPreferences.functionality().searchAutoCloseKeyboard()) {
|
||||
addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
var totalDy: Int = 0
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
totalDy += dy
|
||||
|
||||
if (totalDy.absoluteValue > 100) {
|
||||
totalDy = 0
|
||||
closeSoftKeyboard(requireActivity())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
binding.listAppsSearchview.setOnQueryTextListener(object :
|
||||
|
|
|
@ -11,6 +11,7 @@ import de.jrpie.android.launcher.R
|
|||
import de.jrpie.android.launcher.actions.Action
|
||||
import de.jrpie.android.launcher.actions.Gesture
|
||||
import de.jrpie.android.launcher.actions.LauncherAction
|
||||
import de.jrpie.android.launcher.actions.WidgetPanelAction
|
||||
import de.jrpie.android.launcher.ui.list.ListActivity
|
||||
|
||||
/**
|
||||
|
@ -23,8 +24,10 @@ import de.jrpie.android.launcher.ui.list.ListActivity
|
|||
class OtherRecyclerAdapter(val activity: Activity) :
|
||||
RecyclerView.Adapter<OtherRecyclerAdapter.ViewHolder>() {
|
||||
|
||||
private val othersList: Array<LauncherAction> =
|
||||
LauncherAction.entries.filter { it.isAvailable(activity) }.toTypedArray()
|
||||
private val othersList: Array<Action> =
|
||||
LauncherAction.entries.filter { it.isAvailable(activity) }
|
||||
.plus(WidgetPanelAction(-1))
|
||||
.toTypedArray()
|
||||
|
||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
|
||||
View.OnClickListener {
|
||||
|
@ -36,10 +39,12 @@ class OtherRecyclerAdapter(val activity: Activity) :
|
|||
val pos = bindingAdapterPosition
|
||||
val content = othersList[pos]
|
||||
|
||||
activity.finish()
|
||||
val gestureId = (activity as? ListActivity)?.forGesture ?: return
|
||||
val gesture = Gesture.byId(gestureId) ?: return
|
||||
Action.setActionForGesture(gesture, content)
|
||||
content.showConfigurationDialog(activity) { configuredAction ->
|
||||
Action.setActionForGesture(gesture, configuredAction)
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -48,11 +53,11 @@ class OtherRecyclerAdapter(val activity: Activity) :
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
|
||||
val otherLabel = activity.getString(othersList[i].label)
|
||||
val icon = othersList[i].icon
|
||||
val otherLabel = othersList[i].label(activity)
|
||||
val icon = othersList[i].getIcon(activity)
|
||||
|
||||
viewHolder.textView.text = otherLabel
|
||||
viewHolder.iconView.setImageResource(icon)
|
||||
viewHolder.iconView.setImageDrawable(icon)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
|
|
|
@ -11,6 +11,8 @@ import de.jrpie.android.launcher.actions.openAppsList
|
|||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.preferences.theme.ColorTheme
|
||||
import de.jrpie.android.launcher.setDefaultHomeScreen
|
||||
import de.jrpie.android.launcher.ui.widgets.manage.ManageWidgetPanelsActivity
|
||||
import de.jrpie.android.launcher.ui.widgets.manage.ManageWidgetsActivity
|
||||
|
||||
|
||||
/**
|
||||
|
@ -81,6 +83,22 @@ class SettingsFragmentLauncher : PreferenceFragmentCompat() {
|
|||
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>(
|
||||
LauncherPreferences.apps().keys().hidden()
|
||||
)
|
||||
|
|
|
@ -79,6 +79,9 @@ class SettingsFragmentMeta : Fragment(), UIObject {
|
|||
// view code
|
||||
bindURL(binding.settingsMetaButtonViewCode, R.string.settings_meta_link_github)
|
||||
|
||||
// view documentation
|
||||
bindURL(binding.settingsMetaButtonViewDocs, R.string.settings_meta_link_docs)
|
||||
|
||||
// report a bug
|
||||
binding.settingsMetaButtonReportBug.setOnClickListener {
|
||||
val deviceInfo = getDeviceInfo()
|
||||
|
@ -132,7 +135,12 @@ class SettingsFragmentMeta : Fragment(), UIObject {
|
|||
startActivity(Intent(this.context, LegalInfoActivity::class.java))
|
||||
}
|
||||
|
||||
// version
|
||||
binding.settingsMetaTextVersion.text = BuildConfig.VERSION_NAME
|
||||
binding.settingsMetaTextVersion.setOnClickListener {
|
||||
val deviceInfo = getDeviceInfo()
|
||||
copyToClipboard(requireContext(), deviceInfo)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import de.jrpie.android.launcher.BuildConfig.VERSION_CODE
|
||||
import de.jrpie.android.launcher.databinding.Tutorial5FinishBinding
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.requestNotificationPermission
|
||||
import de.jrpie.android.launcher.setDefaultHomeScreen
|
||||
import de.jrpie.android.launcher.ui.UIObject
|
||||
|
||||
|
@ -31,8 +31,10 @@ class TutorialFragment5Finish : Fragment(), UIObject {
|
|||
override fun onStart() {
|
||||
super<Fragment>.onStart()
|
||||
super<UIObject>.onStart()
|
||||
requestNotificationPermission(requireActivity())
|
||||
}
|
||||
|
||||
|
||||
override fun setOnClicks() {
|
||||
super.setOnClicks()
|
||||
binding.tutorialFinishButtonStart.setOnClickListener { finishTutorial() }
|
||||
|
@ -42,9 +44,9 @@ class TutorialFragment5Finish : Fragment(), UIObject {
|
|||
if (!LauncherPreferences.internal().started()) {
|
||||
LauncherPreferences.internal().started(true)
|
||||
LauncherPreferences.internal().startedTime(System.currentTimeMillis() / 1000L)
|
||||
LauncherPreferences.internal().versionCode(VERSION_CODE)
|
||||
}
|
||||
context?.let { setDefaultHomeScreen(it, checkDefault = true) }
|
||||
|
||||
activity?.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
package de.jrpie.android.launcher.ui.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.window.OnBackInvokedDispatcher
|
||||
import de.jrpie.android.launcher.actions.Action
|
||||
import de.jrpie.android.launcher.actions.Gesture
|
||||
import de.jrpie.android.launcher.actions.LauncherAction
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.ui.TouchGestureDetector
|
||||
|
||||
/**
|
||||
* An activity with a [TouchGestureDetector] as well as handling of volume and back keys set up.
|
||||
*/
|
||||
abstract class LauncherGestureActivity: Activity() {
|
||||
protected var touchGestureDetector: TouchGestureDetector? = null
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
touchGestureDetector?.onTouchEvent(event)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Handle back key / gesture on Android 13+, cf. onKeyDown()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
onBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_OVERLAY
|
||||
) {
|
||||
handleBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
/* This should be initialized in onCreate()
|
||||
However on some devices there seems to be a bug where the touchGestureDetector
|
||||
is not working properly after resuming the app.
|
||||
Reinitializing the touchGestureDetector every time the app is resumed might help to fix that.
|
||||
(see issue #138)
|
||||
*/
|
||||
touchGestureDetector = TouchGestureDetector(
|
||||
this, 0, 0,
|
||||
LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
|
||||
).also {
|
||||
it.updateScreenSize(windowManager)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
getRootView()?.setOnApplyWindowInsetsListener { _, windowInsets ->
|
||||
@Suppress("deprecation") // required to support API 29
|
||||
val insets = windowInsets.systemGestureInsets
|
||||
touchGestureDetector?.setSystemGestureInsets(insets)
|
||||
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("GestureBackNavigation")
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_BACK -> {
|
||||
// Only used pre Android 13, cf. onBackInvokedDispatcher
|
||||
handleBack()
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||
if (Action.forGesture(Gesture.VOLUME_UP) == LauncherAction.VOLUME_UP) {
|
||||
// Let the OS handle the key event. This works better with some custom ROMs
|
||||
// and apps like Samsung Sound Assistant.
|
||||
return false
|
||||
}
|
||||
Gesture.VOLUME_UP(this)
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||
if (Action.forGesture(Gesture.VOLUME_DOWN) == LauncherAction.VOLUME_DOWN) {
|
||||
// see above
|
||||
return false
|
||||
}
|
||||
Gesture.VOLUME_DOWN(this)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
touchGestureDetector?.updateScreenSize(windowManager)
|
||||
}
|
||||
|
||||
protected abstract fun getRootView(): View?
|
||||
protected abstract fun handleBack()
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
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.WidgetClockBinding
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.widgets.WidgetPanel
|
||||
import java.util.Locale
|
||||
|
||||
class ClockView(context: Context, attrs: AttributeSet? = null, val appWidgetId: Int, val panelId: Int): ConstraintLayout(context, attrs) {
|
||||
constructor(context: Context, attrs: AttributeSet?): this(context, attrs, WidgetPanel.HOME.id, -1)
|
||||
|
||||
val binding: WidgetClockBinding = WidgetClockBinding.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
|
||||
}
|
||||
|
||||
private 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package de.jrpie.android.launcher.ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import de.jrpie.android.launcher.databinding.WidgetDebugInfoBinding
|
||||
import de.jrpie.android.launcher.getDeviceInfo
|
||||
|
||||
class DebugInfoView(context: Context, attrs: AttributeSet? = null, val appWidgetId: Int): ConstraintLayout(context, attrs) {
|
||||
|
||||
val binding: WidgetDebugInfoBinding = WidgetDebugInfoBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
|
||||
init {
|
||||
binding.debugInfoText.text = getDeviceInfo()
|
||||
}
|
||||
}
|
|
@ -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[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(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)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package de.jrpie.android.launcher.ui.widgets
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.ViewCompat
|
||||
import de.jrpie.android.launcher.Application
|
||||
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.util.LauncherGestureActivity
|
||||
import de.jrpie.android.launcher.ui.widgets.manage.EXTRA_PANEL_ID
|
||||
import de.jrpie.android.launcher.widgets.WidgetPanel
|
||||
|
||||
class WidgetPanelActivity : LauncherGestureActivity(), UIObject {
|
||||
var binding: ActivityWidgetPanelBinding? = null
|
||||
|
||||
var widgetPanelId: Int = WidgetPanel.HOME.id
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super<LauncherGestureActivity>.onCreate(savedInstanceState)
|
||||
super<UIObject>.onCreate()
|
||||
val binding = ActivityWidgetPanelBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
widgetPanelId = intent.getIntExtra(EXTRA_PANEL_ID, WidgetPanel.HOME.id)
|
||||
|
||||
// The widget container should extend below the status and navigation bars,
|
||||
// so let's set an empty WindowInsetsListener to prevent it from being moved.
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
|
||||
windowInsets
|
||||
}
|
||||
|
||||
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 onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
|
||||
if (hasFocus && LauncherPreferences.display().hideNavigationBar()) {
|
||||
hideNavigationBar()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super<LauncherGestureActivity>.onStart()
|
||||
super<UIObject>.onStart()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
try {
|
||||
(application as Application).appWidgetHost.stopListening()
|
||||
} catch (e: Exception) {
|
||||
// Throws a NullPointerException on Android 12 an earlier, see #172
|
||||
e.printStackTrace()
|
||||
}
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(application as Application).appWidgetHost.startListening()
|
||||
}
|
||||
|
||||
override fun getRootView(): View? {
|
||||
return binding?.root
|
||||
}
|
||||
|
||||
override fun handleBack() {
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun isHomeScreen(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
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 {
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private val sharedPreferencesListener =
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
|
||||
if (
|
||||
prefKey == LauncherPreferences.widgets().keys().customPanels()
|
||||
|| prefKey == LauncherPreferences.widgets().keys().widgets()
|
||||
) {
|
||||
viewAdapter.widgetPanels =
|
||||
(LauncherPreferences.widgets().customPanels() ?: setOf()).toTypedArray()
|
||||
|
||||
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 {
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
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.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import de.jrpie.android.launcher.Application
|
||||
import de.jrpie.android.launcher.databinding.ActivityManageWidgetsBinding
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.ui.UIObject
|
||||
import de.jrpie.android.launcher.widgets.AppWidget
|
||||
import de.jrpie.android.launcher.widgets.GRID_SIZE
|
||||
import de.jrpie.android.launcher.widgets.WidgetPanel
|
||||
import de.jrpie.android.launcher.widgets.WidgetPosition
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
// 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 : UIObject, Activity() {
|
||||
|
||||
private var panelId: Int = WidgetPanel.HOME.id
|
||||
private lateinit var binding: ActivityManageWidgetsBinding
|
||||
|
||||
private var sharedPreferencesListener =
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
|
||||
if (prefKey == LauncherPreferences.widgets().keys().widgets()) {
|
||||
binding.manageWidgetsContainer.updateWidgets(
|
||||
this,
|
||||
LauncherPreferences.widgets().widgets()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super<Activity>.onCreate(savedInstanceState)
|
||||
super<UIObject>.onCreate()
|
||||
binding = ActivityManageWidgetsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
panelId = intent.extras?.getInt(EXTRA_PANEL_ID, WidgetPanel.HOME.id) ?: WidgetPanel.HOME.id
|
||||
|
||||
binding.manageWidgetsButtonAdd.setOnClickListener {
|
||||
selectWidget()
|
||||
}
|
||||
|
||||
// The widget container should extend below the status and navigation bars,
|
||||
// so let's set an empty WindowInsetsListener to prevent it from being moved.
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
|
||||
windowInsets
|
||||
}
|
||||
|
||||
// The button must not be placed under the navigation bar
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.manageWidgetsButtonAdd) { v, windowInsets ->
|
||||
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
leftMargin = insets.left
|
||||
bottomMargin = insets.bottom
|
||||
rightMargin = insets.right
|
||||
}
|
||||
WindowInsetsCompat.CONSUMED
|
||||
}
|
||||
|
||||
binding.manageWidgetsContainer.let {
|
||||
it.widgetPanelId = panelId
|
||||
it.updateWidgets(this, LauncherPreferences.widgets().widgets())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super<Activity>.onStart()
|
||||
super<UIObject>.onStart()
|
||||
|
||||
LauncherPreferences.getSharedPreferences()
|
||||
.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
|
||||
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
try {
|
||||
(application as Application).appWidgetHost.stopListening()
|
||||
} catch (e: Exception) {
|
||||
// Throws a NullPointerException on Android 12 an earlier, see #172
|
||||
e.printStackTrace()
|
||||
}
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(application as Application).appWidgetHost.startListening()
|
||||
|
||||
binding.manageWidgetsContainer.updateWidgets(
|
||||
this,
|
||||
LauncherPreferences.widgets().widgets()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
|
||||
if (hasFocus && LauncherPreferences.display().hideNavigationBar()) {
|
||||
hideNavigationBar()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTheme(): Resources.Theme {
|
||||
return modifyTheme(super.getTheme())
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
LauncherPreferences.getSharedPreferences()
|
||||
.unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
||||
private fun selectWidget() {
|
||||
startActivityForResult(
|
||||
Intent(this, SelectWidgetActivity::class.java).also {
|
||||
it.putExtra(
|
||||
EXTRA_PANEL_ID,
|
||||
panelId
|
||||
)
|
||||
}, REQUEST_PICK_APPWIDGET
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun createWidget(data: Intent) {
|
||||
Log.i("Launcher", "creating widget")
|
||||
val appWidgetManager = (application as Application).appWidgetManager
|
||||
val appWidgetHost = (application as Application).appWidgetHost
|
||||
val appWidgetId = data.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: return
|
||||
|
||||
val display = windowManager.defaultDisplay
|
||||
|
||||
val widgetInfo = appWidgetManager.getAppWidgetInfo(appWidgetId)
|
||||
if (widgetInfo == null) {
|
||||
Log.w("Launcher", "can't access widget")
|
||||
appWidgetHost.deleteAppWidgetId(appWidgetId)
|
||||
return
|
||||
}
|
||||
|
||||
val position = WidgetPosition.findFreeSpace(
|
||||
WidgetPanel.byId(panelId),
|
||||
max(3, (GRID_SIZE * (widgetInfo.minWidth) / display.width.toFloat()).roundToInt()),
|
||||
max(3, (GRID_SIZE * (widgetInfo.minHeight) / display.height.toFloat()).roundToInt())
|
||||
)
|
||||
|
||||
val widget = AppWidget(appWidgetId, position, panelId, widgetInfo)
|
||||
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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
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.Application
|
||||
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.generateInternalId
|
||||
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 widgetPanelId: Int = WidgetPanel.HOME.id
|
||||
|
||||
private fun tryBindWidget(info: LauncherWidgetProvider) {
|
||||
when (info) {
|
||||
is LauncherAppWidgetProvider -> {
|
||||
val widgetId =
|
||||
(applicationContext as Application).appWidgetHost.allocateAppWidgetId()
|
||||
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(generateInternalId(), 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)
|
||||
|
||||
|
||||
widgetPanelId = intent.getIntExtra(EXTRA_PANEL_ID, WidgetPanel.HOME.id)
|
||||
|
||||
val viewManager = LinearLayoutManager(this)
|
||||
val viewAdapter = SelectWidgetRecyclerAdapter()
|
||||
|
||||
binding.selectWidgetRecycler.apply {
|
||||
setHasFixedSize(false)
|
||||
layoutManager = viewManager
|
||||
adapter = viewAdapter
|
||||
}
|
||||
|
||||
binding.selectWidgetClose.setOnClickListener {
|
||||
setResult(RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
package de.jrpie.android.launcher.ui.widgets.manage
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewConfiguration
|
||||
import androidx.core.graphics.contains
|
||||
import androidx.core.graphics.minus
|
||||
import androidx.core.graphics.toRect
|
||||
import de.jrpie.android.launcher.ui.widgets.WidgetContainerView
|
||||
import de.jrpie.android.launcher.widgets.GRID_SIZE
|
||||
import de.jrpie.android.launcher.widgets.Widget
|
||||
import de.jrpie.android.launcher.widgets.WidgetPanel
|
||||
import de.jrpie.android.launcher.widgets.WidgetPosition
|
||||
import de.jrpie.android.launcher.widgets.updateWidget
|
||||
|
||||
/**
|
||||
* A variant of the [WidgetContainerView] which allows to manage widgets.
|
||||
*/
|
||||
class WidgetManagerView(widgetPanelId: Int, context: Context, attrs: AttributeSet? = null) :
|
||||
WidgetContainerView(widgetPanelId, context, attrs) {
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(WidgetPanel.HOME.id, context, attrs)
|
||||
|
||||
val touchSlop: Int
|
||||
val touchSlopSquare: Int
|
||||
val longPressTimeout: Long
|
||||
|
||||
|
||||
private var overlayViewById = HashMap<Int, WidgetOverlayView>()
|
||||
|
||||
init {
|
||||
val configuration = ViewConfiguration.get(context)
|
||||
touchSlop = configuration.scaledTouchSlop
|
||||
touchSlopSquare = touchSlop * touchSlop
|
||||
|
||||
longPressTimeout = ViewConfiguration.getLongPressTimeout().toLong()
|
||||
}
|
||||
|
||||
|
||||
enum class EditMode(val resize: (dx: Int, dy: Int, screenWidth: Int, screenHeight: Int, rect: Rect) -> Rect) {
|
||||
MOVE({ dx, dy, sw, sh, rect ->
|
||||
val cdx = dx.coerceIn(-rect.left, sw - rect.right)
|
||||
val cdy = dy.coerceIn(-rect.top, sh - rect.bottom)
|
||||
Rect(rect.left + cdx, rect.top + cdy, rect.right + cdx, rect.bottom + cdy)
|
||||
}),
|
||||
TOP({ _, dy, _, sh, rect ->
|
||||
val range = (-rect.top)..(rect.bottom - rect.top - (2 * sh / GRID_SIZE) + 5)
|
||||
if (range.isEmpty()) {
|
||||
rect
|
||||
} else {
|
||||
Rect(rect.left, rect.top + dy.coerceIn(range), rect.right, rect.bottom)
|
||||
}
|
||||
}),
|
||||
BOTTOM({ _, dy, _, sh, rect ->
|
||||
val range = ((2 * sh / GRID_SIZE) + 5 + rect.top - rect.bottom)..(sh - rect.bottom)
|
||||
if (range.isEmpty()) {
|
||||
rect
|
||||
} else {
|
||||
Rect(rect.left, rect.top, rect.right, rect.bottom + dy.coerceIn(range))
|
||||
}
|
||||
}),
|
||||
LEFT({ dx, _, sw, _, rect ->
|
||||
val range = (-rect.left)..(rect.right - rect.left - (2 * sw / GRID_SIZE) + 5)
|
||||
if (range.isEmpty()) {
|
||||
rect
|
||||
} else {
|
||||
Rect(rect.left + dx.coerceIn(range), rect.top, rect.right, rect.bottom)
|
||||
}
|
||||
}),
|
||||
RIGHT({ dx, _, sw, _, rect ->
|
||||
val range = ((2 * sw / GRID_SIZE) + 5 + rect.left - rect.right)..(sw - rect.right)
|
||||
if (range.isEmpty()) {
|
||||
rect
|
||||
} else {
|
||||
Rect(rect.left, rect.top, rect.right + dx.coerceIn(range), rect.bottom)
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
private var selectedWidgetOverlayView: WidgetOverlayView? = null
|
||||
private var selectedWidgetView: View? = null
|
||||
private var currentGestureStart: Point? = null
|
||||
private var startWidgetPosition: Rect? = null
|
||||
private var lastPosition = Rect()
|
||||
|
||||
private val longPressHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
if (event == null) {
|
||||
return false
|
||||
}
|
||||
synchronized(this) {
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
val start = Point(event.x.toInt(), event.y.toInt())
|
||||
currentGestureStart = start
|
||||
val view = overlayViewById.asIterable()
|
||||
.map { it.value }.firstOrNull { overlayView ->
|
||||
RectF(
|
||||
overlayView.x,
|
||||
overlayView.y,
|
||||
overlayView.x + overlayView.width,
|
||||
overlayView.y + overlayView.height
|
||||
)
|
||||
.toRect()
|
||||
.contains(start)
|
||||
} ?: return true
|
||||
|
||||
val position =
|
||||
(view.layoutParams as Companion.LayoutParams).position.getAbsoluteRect(
|
||||
width,
|
||||
height
|
||||
)
|
||||
selectedWidgetOverlayView = view
|
||||
selectedWidgetView = widgetViewById[view.widgetId]
|
||||
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()
|
||||
}
|
||||
}, longPressTimeout)
|
||||
}
|
||||
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 > touchSlopSquare) {
|
||||
longPressHandler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
val view = selectedWidgetOverlayView ?: return true
|
||||
val start = startWidgetPosition ?: return true
|
||||
val absoluteNewPosition = (view.mode ?: return true).resize(
|
||||
distanceX.toInt(),
|
||||
distanceY.toInt(),
|
||||
width, height,
|
||||
start
|
||||
)
|
||||
val newPosition = WidgetPosition.fromAbsoluteRect(
|
||||
absoluteNewPosition, width, height
|
||||
)
|
||||
if (absoluteNewPosition != lastPosition) {
|
||||
lastPosition = absoluteNewPosition
|
||||
(view.layoutParams as Companion.LayoutParams).position = newPosition
|
||||
(selectedWidgetView?.layoutParams as? Companion.LayoutParams)?.position =
|
||||
newPosition
|
||||
requestLayout()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS)
|
||||
}
|
||||
}
|
||||
|
||||
if (event.actionMasked == MotionEvent.ACTION_UP) {
|
||||
val id = selectedWidgetOverlayView?.widgetId ?: return true
|
||||
val widget = Widget.byId(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() {
|
||||
synchronized(this) {
|
||||
longPressHandler.removeCallbacksAndMessages(null)
|
||||
startWidgetPosition = null
|
||||
selectedWidgetOverlayView?.mode = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
endInteraction()
|
||||
super.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
override fun updateWidgets(activity: Activity, widgets: Collection<Widget>?) {
|
||||
super.updateWidgets(activity, widgets)
|
||||
|
||||
synchronized(overlayViewById) {
|
||||
overlayViewById.forEach { removeView(it.value) }
|
||||
overlayViewById.clear()
|
||||
widgets?.filter { it.panelId == widgetPanelId }?.forEach { widget ->
|
||||
WidgetOverlayView(activity).let {
|
||||
it.widgetId = widget.id
|
||||
addView(it)
|
||||
(it.layoutParams as Companion.LayoutParams).position = widget.position
|
||||
overlayViewById[widget.id] = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package de.jrpie.android.launcher.ui.widgets.manage
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
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 : ViewGroup {
|
||||
|
||||
private val paint = Paint()
|
||||
private val handlePaint = Paint()
|
||||
private val selectedHandlePaint = Paint()
|
||||
|
||||
private val popupAnchor = View(context)
|
||||
|
||||
var mode: WidgetManagerView.EditMode? = null
|
||||
|
||||
class Handle(val mode: WidgetManagerView.EditMode, val position: Rect)
|
||||
init {
|
||||
addView(popupAnchor)
|
||||
setWillNotDraw(false)
|
||||
handlePaint.style = Paint.Style.STROKE
|
||||
handlePaint.color = Color.WHITE
|
||||
handlePaint.strokeWidth = 2f
|
||||
handlePaint.setShadowLayer(10f,0f,0f, Color.BLACK)
|
||||
|
||||
selectedHandlePaint.style = Paint.Style.FILL_AND_STROKE
|
||||
selectedHandlePaint.setARGB(100, 255, 255, 255)
|
||||
handlePaint.setShadowLayer(10f,0f,0f, Color.BLACK)
|
||||
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.color = Color.WHITE
|
||||
paint.setShadowLayer(10f,0f,0f, Color.BLACK)
|
||||
}
|
||||
|
||||
private var preview: Drawable? = null
|
||||
var widgetId: Int = -1
|
||||
set(newId) {
|
||||
field = newId
|
||||
preview = Widget.byId(widgetId)?.getPreview(context)
|
||||
}
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyle
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
||||
popupAnchor.layout(0,0,0,0)
|
||||
}
|
||||
|
||||
fun showPopupMenu() {
|
||||
val widget = Widget.byId(widgetId)?: return
|
||||
val menu = PopupMenu(context, popupAnchor)
|
||||
menu.menu.let {
|
||||
it.add(
|
||||
context.getString(R.string.widget_menu_remove)
|
||||
).setOnMenuItemClickListener { _ ->
|
||||
Widget.byId(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(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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
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)
|
||||
var infoView: TextView = itemView.findViewById(R.id.list_widget_panels_info)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
|
||||
viewHolder.labelView.text = widgetPanels[i].label
|
||||
val numWidgets = widgetPanels[i].getWidgets().size
|
||||
viewHolder.infoView.text = context.resources.getQuantityString(
|
||||
R.plurals.widget_panel_number_of_widgets,
|
||||
numWidgets, numWidgets
|
||||
)
|
||||
|
||||
viewHolder.itemView.setOnClickListener {
|
||||
onSelectWidgetPanel(widgetPanels[i])
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
130
app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt
Normal file
130
app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt
Normal file
|
@ -0,0 +1,130 @@
|
|||
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,
|
||||
panelId != WidgetPanel.HOME.id,
|
||||
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
|
||||
/* TODO: if providerInfo is null, the corresponding app was probably uninstalled.
|
||||
There does not seem to be a way to recover the widget when the app is installed again,
|
||||
hence it should be deleted. */
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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 var 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, panelId)
|
||||
}
|
||||
|
||||
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) { }
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package de.jrpie.android.launcher.widgets
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import de.jrpie.android.launcher.ui.widgets.DebugInfoView
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
@Serializable
|
||||
@SerialName("widget:debuginfo")
|
||||
class DebugInfoWidget(
|
||||
override var id: Int,
|
||||
override var position: WidgetPosition,
|
||||
override val panelId: Int,
|
||||
override var allowInteraction: Boolean = true
|
||||
) : Widget() {
|
||||
|
||||
override fun createView(activity: Activity): View {
|
||||
return DebugInfoView(activity, null, id)
|
||||
}
|
||||
|
||||
override fun findView(views: Sequence<View>): DebugInfoView? {
|
||||
return views.mapNotNull { it as? DebugInfoView }.firstOrNull { it.appWidgetId == id }
|
||||
}
|
||||
|
||||
override fun getPreview(context: Context): Drawable? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getIcon(context: Context): Drawable? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun isConfigurable(context: Context): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun configure(activity: Activity, requestCode: Int) { }
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data object 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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
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.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) {
|
||||
if (id >= 0) {
|
||||
context.getAppWidgetHost().deleteAppWidgetId(id)
|
||||
}
|
||||
|
||||
LauncherPreferences.widgets().widgets(
|
||||
LauncherPreferences.widgets().widgets()?.also {
|
||||
it.remove(this)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
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(id: Int): Widget? {
|
||||
// TODO: do some caching
|
||||
return LauncherPreferences.widgets().widgets().firstOrNull {
|
||||
it.id == id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
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) }
|
||||
}
|
||||
|
||||
fun getWidgets(): List<Widget> {
|
||||
return LauncherPreferences.widgets().widgets().filter {
|
||||
it.panelId == this.id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
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) {
|
||||
|
||||
constructor(rect: Rect) : this(
|
||||
rect.left.toShort(),
|
||||
rect.top.toShort(),
|
||||
(rect.right - rect.left).toShort(),
|
||||
(rect.bottom - rect.top).toShort()
|
||||
)
|
||||
|
||||
fun toRect(): Rect {
|
||||
return Rect(x.toInt(), y.toInt(), x + width, y + height)
|
||||
}
|
||||
|
||||
fun getAbsoluteRect(screenWidth: Int, screenHeight: Int): Rect {
|
||||
val gridWidth = screenWidth / GRID_SIZE.toFloat()
|
||||
val gridHeight = screenHeight / GRID_SIZE.toFloat()
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
fun findFreeSpace(
|
||||
widgetPanel: WidgetPanel?,
|
||||
minWidth: Int,
|
||||
minHeight: Int
|
||||
): WidgetPosition {
|
||||
val rect = Rect(0, 0, minWidth, minHeight)
|
||||
if (widgetPanel == null) {
|
||||
return WidgetPosition(rect)
|
||||
}
|
||||
|
||||
val widgets = widgetPanel.getWidgets().map { it.position.toRect() }
|
||||
|
||||
for (x in 0..<GRID_SIZE - minWidth) {
|
||||
rect.left = x
|
||||
rect.right = x + minWidth
|
||||
for (y in 0..<GRID_SIZE - minHeight) {
|
||||
rect.top = y
|
||||
rect.bottom = y + minHeight
|
||||
if (!widgets.any { Rect(it).intersect(rect) }) {
|
||||
return WidgetPosition(rect)
|
||||
}
|
||||
}
|
||||
}
|
||||
return WidgetPosition(0, 0, minWidth.toShort(), minHeight.toShort())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
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
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/**
|
||||
* 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, appWidgetId: Int, requestCode: Int? = null): Boolean {
|
||||
|
||||
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 { profile ->
|
||||
appWidgetManager.getInstalledProvidersForProfile(profile)
|
||||
.map { LauncherAppWidgetProvider(it) }
|
||||
}.flatten()
|
||||
)
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
fun updateWidget(widget: Widget) {
|
||||
LauncherPreferences.widgets().widgets(
|
||||
(LauncherPreferences.widgets().widgets() ?: setOf())
|
||||
.minus(widget)
|
||||
.plus(widget)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// TODO: this needs to be improved
|
||||
fun generateInternalId(): Int {
|
||||
val minId = min(-5,(LauncherPreferences.widgets().widgets() ?: setOf()).minOfOrNull { it.id } ?: 0)
|
||||
return minId -1
|
||||
}
|
||||
|
||||
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
|
||||
}
|
11
app/src/main/res/drawable/baseline_add_24.xml
Normal file
11
app/src/main/res/drawable/baseline_add_24.xml
Normal 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>
|
11
app/src/main/res/drawable/baseline_bug_report_24.xml
Normal file
11
app/src/main/res/drawable/baseline_bug_report_24.xml
Normal 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="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z" />
|
||||
|
||||
</vector>
|
15
app/src/main/res/drawable/baseline_clock_24.xml
Normal file
15
app/src/main/res/drawable/baseline_clock_24.xml
Normal 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>
|
11
app/src/main/res/drawable/baseline_widgets_24.xml
Normal file
11
app/src/main/res/drawable/baseline_widgets_24.xml
Normal 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>
|
32
app/src/main/res/layout/activity_home.xml
Normal file
32
app/src/main/res/layout/activity_home.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?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/home_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:longClickable="false"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ui.HomeActivity">
|
||||
|
||||
<de.jrpie.android.launcher.ui.widgets.WidgetContainerView
|
||||
android:id="@+id/home_widget_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<!-- only shown when µLauncher settings can't be reached by a gesture -->
|
||||
<ImageView
|
||||
android:id="@+id/button_fallback_settings"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/settings"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:padding="20dp"
|
||||
android:alpha="0.4"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:srcCompat="@drawable/baseline_settings_24"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
75
app/src/main/res/layout/activity_manage_widget_panels.xml
Normal file
75
app/src/main/res/layout/activity_manage_widget_panels.xml
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?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:contentDescription="@string/content_description_close"
|
||||
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:contentDescription="@string/content_description_add_widget_panel"
|
||||
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>
|
29
app/src/main/res/layout/activity_manage_widgets.xml
Normal file
29
app/src/main/res/layout/activity_manage_widgets.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?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:contentDescription="@string/content_description_add_widget"
|
||||
android:focusable="true"
|
||||
android:src="@drawable/baseline_add_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -44,6 +44,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="@string/content_description_close"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="true"
|
||||
android:paddingLeft="16sp"
|
||||
|
|
59
app/src/main/res/layout/activity_report_crash.xml
Normal file
59
app/src/main/res/layout/activity_report_crash.xml
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:fitsSystemWindows="true"
|
||||
tools:context=".ui.ReportCrashActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:background="@null"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/report_crash_appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<de.jrpie.android.launcher.ui.util.HtmlTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/crash_info" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/report_crash_button_copy"
|
||||
android:text="@string/report_crash_button_copy"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp" />
|
||||
<Button
|
||||
android:id="@+id/report_crash_button_mail"
|
||||
android:text="@string/report_crash_button_mail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<Button
|
||||
android:id="@+id/report_crash_button_report"
|
||||
android:text="@string/report_crash_button_report"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
73
app/src/main/res/layout/activity_select_widget.xml
Normal file
73
app/src/main/res/layout/activity_select_widget.xml
Normal 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/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:contentDescription="@string/content_description_close"
|
||||
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>
|
15
app/src/main/res/layout/activity_widget_panel.xml
Normal file
15
app/src/main/res/layout/activity_widget_panel.xml
Normal 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>
|
|
@ -24,6 +24,21 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="10dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_select_color_alpha" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/dialog_select_color_seekbar_alpha"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:max="255" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="10dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -65,18 +80,4 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:max="255" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="10dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_select_color_alpha" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/dialog_select_color_seekbar_alpha"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:max="255" />
|
||||
</LinearLayout>
|
18
app/src/main/res/layout/dialog_create_widget_panel.xml
Normal file
18
app/src/main/res/layout/dialog_create_widget_panel.xml
Normal 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>
|
18
app/src/main/res/layout/dialog_rename_widget_panel.xml
Normal file
18
app/src/main/res/layout/dialog_rename_widget_panel.xml
Normal 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>
|
26
app/src/main/res/layout/dialog_select_widget_panel.xml
Normal file
26
app/src/main/res/layout/dialog_select_widget_panel.xml
Normal 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>
|
|
@ -62,6 +62,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/content_description_close"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="true"
|
||||
android:paddingLeft="16sp"
|
||||
|
@ -72,6 +73,7 @@
|
|||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<ImageView
|
||||
android:id="@+id/list_lock"
|
||||
android:contentDescription="@string/content_description_lock"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -91,7 +93,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabIndicatorColor="?attr/colorAccent"
|
||||
custom:tabTextColor="?attr/android:textColor" />
|
||||
custom:tabTextColor="?attr/android:textColor"
|
||||
tools:ignore="SpeakableTextPresentCheck" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
@ -110,6 +113,7 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/list_appbar"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
custom:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
custom:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:ignore="SpeakableTextPresentCheck" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -27,6 +27,8 @@
|
|||
android:text=""
|
||||
android:textSize="11sp"
|
||||
tools:text="@string/app_name"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
app:layout_constraintTop_toBottomOf="@id/list_apps_row_icon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
android:id="@+id/list_other_row_icon"
|
||||
android:layout_width="35sp"
|
||||
android:layout_height="35sp"
|
||||
android:contentDescription="@null"
|
||||
android:gravity="center"
|
||||
android:textSize="30sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
37
app/src/main/res/layout/list_widget_panels_row.xml
Normal file
37
app/src/main/res/layout/list_widget_panels_row.xml
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/list_widget_panels_row_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
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=""
|
||||
tools:text="Panel #1"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<TextView
|
||||
android:id="@+id/list_widget_panels_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="60sp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:gravity="start"
|
||||
android:text=""
|
||||
tools:text="Contains 5 widgets"
|
||||
android:textSize="11sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/list_widget_panels_label" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
35
app/src/main/res/layout/list_widgets_header.xml
Normal file
35
app/src/main/res/layout/list_widgets_header.xml
Normal 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>
|
101
app/src/main/res/layout/list_widgets_row.xml
Normal file
101
app/src/main/res/layout/list_widgets_row.xml
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?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_marginHorizontal="30sp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="?cardBackgroundColor"
|
||||
app:cardElevation="8dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardUseCompatPadding="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_margin="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/icon_title_description_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/list_widgets_row_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
tools:src="@mipmap/ic_launcher_round"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_widgets_row_name"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginStart="10sp"
|
||||
android:layout_marginEnd="10sp"
|
||||
android:text=""
|
||||
style="@style/TextAppearance.Material3.HeadlineSmall"
|
||||
tools:text="Some Widget"
|
||||
app:layout_constraintStart_toEndOf="@id/list_widgets_row_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/list_widgets_row_icon"
|
||||
app:layout_constraintBottom_toBottomOf="@id/list_widgets_row_icon"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_widgets_row_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=""
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
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 that may take up multiple lines." />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/icon_title_description_container">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/list_widgets_row_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:maxHeight="100dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/list_widgets_row_icon"
|
||||
tools:src="@mipmap/ic_launcher_round"
|
||||
tools:ignore="ContentDescription,NotSibling" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -20,6 +20,22 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/settings_system"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="@string/settings"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="true"
|
||||
android:paddingLeft="16sp"
|
||||
android:paddingRight="16sp"
|
||||
android:src="@drawable/baseline_settings_applications_24"
|
||||
custom:layout_constraintBottom_toBottomOf="parent"
|
||||
custom:layout_constraintStart_toStartOf="parent"
|
||||
custom:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/settings_heading"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -40,6 +56,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="@string/content_description_close"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="true"
|
||||
android:paddingLeft="16sp"
|
||||
|
@ -48,28 +65,14 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/settings_system"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="true"
|
||||
android:paddingLeft="16sp"
|
||||
android:paddingRight="16sp"
|
||||
android:src="@drawable/baseline_settings_applications_24"
|
||||
custom:layout_constraintBottom_toBottomOf="parent"
|
||||
custom:layout_constraintStart_toStartOf="parent"
|
||||
custom:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/settings_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabTextColor="?attr/android:textColor" />
|
||||
app:tabTextColor="?attr/android:textColor"
|
||||
tools:ignore="SpeakableTextPresentCheck" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
android:id="@+id/settings_actions_row_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/content_description_settings_actions_row_button_remove"
|
||||
android:padding="8sp"
|
||||
android:src="@drawable/baseline_close_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
|
@ -41,6 +41,13 @@
|
|||
android:text="@string/settings_meta_view_code"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/settings_meta_button_view_docs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_meta_view_docs"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/settings_meta_button_report_bug"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
android:id="@+id/tutorial_button_back"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:contentDescription="@string/content_description_navigate_back"
|
||||
android:gravity="center"
|
||||
android:alpha="0.5"
|
||||
android:src="@drawable/baseline_navigate_before_24"
|
||||
|
@ -43,12 +44,14 @@
|
|||
app:layout_constraintStart_toEndOf="@+id/tutorial_button_back"
|
||||
app:tabBackground="@drawable/tutorial_tab_selector"
|
||||
app:tabGravity="center"
|
||||
app:tabIndicatorHeight="0dp" />
|
||||
app:tabIndicatorHeight="0dp"
|
||||
tools:ignore="SpeakableTextPresentCheck" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/tutorial_button_next"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:contentDescription="@string/content_description_navigate_next"
|
||||
android:gravity="center"
|
||||
android:src="@drawable/baseline_navigate_next_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
|
@ -33,17 +33,27 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tutorial_setup_title" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/tutorial_setup_actions_rview_fragment"
|
||||
android:name="de.jrpie.android.launcher.ui.settings.actions.SettingsFragmentActionsRecycler"
|
||||
android:layout_width="0dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardElevation="8dp"
|
||||
app:cardBackgroundColor="?cardBackgroundColor"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardUseCompatPadding="true"
|
||||
app:layout_constraintTop_toBottomOf="@id/tutorial_setup_subtitle"
|
||||
app:layout_constraintBottom_toTopOf="@id/tutorial_setup_text_bottom"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tutorial_setup_subtitle" />
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/tutorial_setup_actions_rview_fragment"
|
||||
android:name="de.jrpie.android.launcher.ui.settings.actions.SettingsFragmentActionsRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginStart="10dp"/>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tutorial_setup_text_bottom"
|
||||
|
|
|
@ -3,15 +3,14 @@
|
|||
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/home_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:longClickable="false"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ui.HomeActivity">
|
||||
tools:context=".ui.widgets.ClockView">
|
||||
|
||||
<TextClock
|
||||
android:id="@+id/home_upper_view"
|
||||
android:id="@+id/clock_upper_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start|center_vertical"
|
||||
|
@ -20,32 +19,17 @@
|
|||
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: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/home_upper_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/clock_upper_view"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<!-- only shown when µLauncher settings can't be reached by a gesture -->
|
||||
<ImageView
|
||||
android:id="@+id/button_fallback_settings"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/settings"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:padding="20dp"
|
||||
android:alpha="0.4"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:srcCompat="@drawable/baseline_settings_24"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
16
app/src/main/res/layout/widget_debug_info.xml
Normal file
16
app/src/main/res/layout/widget_debug_info.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:longClickable="false"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ui.widgets.DebugInfoView">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/debugInfoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -95,9 +95,9 @@
|
|||
<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">إيماءات التمرير المزدوج</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">إيماءات تمرير الحافة</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>
|
||||
|
@ -153,7 +153,7 @@
|
|||
<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="list_other_launch_other_launcher">تشغيل شاشة رئيسية أخرى</string>
|
||||
<string name="pin_shortcut_title">أضف اختصارًا</string>
|
||||
<string name="pin_shortcut_button_bind">اربط بإيماءة</string>
|
||||
<string name="tutorial_title">درس تعليمي</string>
|
||||
|
@ -162,11 +162,11 @@
|
|||
<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_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">اخترنا لك بعض التطبيقات الافتراضية. يمكنك تغييرها الآن إذا كنت ترغب في ذلك:</string>
|
||||
<string name="tutorial_setup_text_2">يمكنك أيضًا تغيير اختيارك لاحقًا.</string>
|
||||
<string name="tutorial_finish_title">لنبدأ!</string>
|
||||
<string name="tutorial_finish_button">ابدأ</string>
|
||||
|
@ -235,7 +235,7 @@
|
|||
<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_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>
|
||||
|
@ -245,7 +245,7 @@
|
|||
<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="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>
|
||||
|
@ -257,8 +257,85 @@
|
|||
<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="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>
|
||||
<string name="dialog_create_widget_panel_title">إنشاء لوحة أداة جديدة</string>
|
||||
<string name="settings_widgets_widgets">إدارة الأدوات المصغّرة</string>
|
||||
<string name="settings_widgets_custom_panels">إدارة لوحات الأدوات المصغّرة</string>
|
||||
<string name="screen_lock_method_dialog_text"><![CDATA[
|
||||
<h1>اختر طريقة القفل</h1>
|
||||
هناك طريقتان لقفل الشاشة.
|
||||
للأسف، كلا الطريقتين لهما عيوب:<br/><br/>
|
||||
|
||||
<h3>إدارة الجهاز</h3>
|
||||
لا تعمل مع فتح القفل باستخدام بصمة الإصبع أو التعرف على الوجه.
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<h3>خدمة الوصول</h3>
|
||||
تتطلب صلاحيات واسعة.
|
||||
سيستخدم تطبيق μLauncher هذه الصلاحيات فقط لقفل الشاشة.
|
||||
<br/>
|
||||
(يجب ألا تثق بتطبيق عشوائي قمت بتحميله للتو بهذا الادعاء، ولكن يمكنك التحقق من <a href=\"https://github.com/jrpie/Launcher\">الكود المصدري</a>.)
|
||||
<br/>
|
||||
في بعض الأجهزة، لن يُستخدم رمز PIN الخاص بالتشغيل لتشفير البيانات بعد تفعيل خدمة الوصول.
|
||||
يمكن <a href="https://issuetracker.google.com/issues/37010136#comment36">إعادة تفعيل</a> هذا لاحقًا.
|
||||
|
||||
<br/><br/><br/><br/>
|
||||
يمكنك تغيير اختيارك لاحقًا في الإعدادات.
|
||||
]]></string>
|
||||
<string name="widget_clock_description">الساعة الافتراضية لـ μLauncher</string>
|
||||
<string name="dialog_select_widget_panel_info_no_panels"><![CDATA[
|
||||
لم يتم العثور على أي لوحات أدوات. يمكنك إنشاء لوحات أدوات في الإعدادات > المشغل > إدارة لوحات الأدوات.
|
||||
]]></string>
|
||||
<string name="select_widget_title">اختر الأداة</string>
|
||||
<string name="widget_menu_remove">إزالة</string>
|
||||
<string name="widget_menu_configure">تهيئة</string>
|
||||
<string name="widget_menu_enable_interaction">تمكين التفاعل</string>
|
||||
<string name="widget_menu_disable_interaction">تعطيل التفاعل</string>
|
||||
<string name="widget_clock_label">ساعة</string>
|
||||
<string name="manage_widget_panels_delete">حذف</string>
|
||||
<string name="manage_widget_panels_rename">إعادة التسمية</string>
|
||||
<string name="widget_panel_default_name">لوحة الأداة المصغّرة #%1$d</string>
|
||||
<string name="dialog_ok">حسنا</string>
|
||||
<string name="widget_panels_title">لوحات الأداة</string>
|
||||
<string name="dialog_select_widget_panel_title">تحديد لوحة الأداة</string>
|
||||
<string name="list_other_open_widget_panel">افتح لوحة الأدوات</string>
|
||||
<string name="alert_widget_panel_not_found">لم تعد لوحة الأدوات هذه موجودة.</string>
|
||||
<string name="settings_launcher_section_widgets">الأدوات</string>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="zero">يحتوي على %1$dأداة.</item>
|
||||
<item quantity="one">يحتوي على %1$d أداة.</item>
|
||||
<item quantity="two">يحتوي على %1$d أدوات.</item>
|
||||
<item quantity="few">يحتوي على%1$d أدوات.</item>
|
||||
<item quantity="many">يحتوي على %1$d أداة.</item>
|
||||
<item quantity="other">يحتوي على%1$d أداة.</item>
|
||||
</plurals>
|
||||
<string name="settings_functionality_auto_close_keyboard">إغلاق لوحة المفاتيح عند التمرير</string>
|
||||
<string name="crash_info"><![CDATA[
|
||||
يبدو أن هناك خطأ ما، نعتذر عن ذلك!<br><br>
|
||||
لأسباب تتعلق بالخصوصية، لا يتم جمع سجلات الأعطال تلقائيًا.<br>
|
||||
ومع ذلك، فإن السجلات مفيدة جدًا لتصحيح الأخطاء، لذا سأكون ممتنًا جدًا إذا كان بإمكانك إرسال السجل المرفق عبر البريد
|
||||
أو إنشاء تقرير عن الخطأ على GitHub.<br><br>
|
||||
يرجى ملاحظة أن سجلات الأعطال قد تحتوي على <strong>معلومات حساسة</strong>، مثل اسم التطبيق الذي حاولت تشغيله.
|
||||
يرجى <strong>حذف</strong> مثل هذه المعلومات قبل إرسال التقرير.
|
||||
<h2>ماذا يمكنني أن أفعل الآن؟</h2>
|
||||
إذا ظهر هذا الخطأ مرة أخرى، يمكنك تجربة عدة أشياء:
|
||||
<ul>
|
||||
<li>إيقاف μLauncher بالقوة</li>
|
||||
<li>مسح بيانات μLauncher's (<strong>ستفقد إعداداتك!</strong>)</li>
|
||||
<li>تثبيت إصدار أقدم (<a href="https://github.com/jrpie/Launcher/releases">GitHub</a>, <a href="https://f-droid.org/en/packages/de.jrpie.android.launcher">F-Droid</a>)</li>
|
||||
</ul>
|
||||
]]></string>
|
||||
<string name="notification_crash_title">تعطل μLauncher</string>
|
||||
<string name="notification_crash_explanation">آسف! انقر للحصول على مزيد من المعلومات.</string>
|
||||
<string name="report_crash_button_copy">نسخ تقرير التعطل إلى الحافظة</string>
|
||||
<string name="report_crash_button_mail">إرسال التقرير بالبريد</string>
|
||||
<string name="report_crash_button_report">إنشاء تقرير خطأ على GitHub</string>
|
||||
<string name="report_crash_title">تعطل μLauncher</string>
|
||||
<string name="send_email">إرسال بريد إلكتروني</string>
|
||||
<string name="notification_channel_crash">الأعطال ومعلومات التصحيح</string>
|
||||
</resources>
|
||||
|
|
|
@ -97,9 +97,9 @@
|
|||
<string name="settings_display_screen_timeout_disabled">Bildschirm nicht ausschalten</string>
|
||||
<string name="settings_display_rotate_screen">Bildschirm drehen</string>
|
||||
<string name="settings_launcher_section_functionality">Funktionalität</string>
|
||||
<string name="settings_enabled_gestures_double_swipe">Doppelte Wischaktionen</string>
|
||||
<string name="settings_enabled_gestures_double_swipe">Doppelte Wischgesten</string>
|
||||
<string name="settings_enabled_gestures_double_swipe_summary">Mit zwei Fingern wischen</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Kantenaktionen</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Kantengesten</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_edge_width">Kantenbreite</string>
|
||||
<string name="settings_functionality_auto_launch">Suchergebnis starten</string>
|
||||
<string name="settings_functionality_search_web_summary">Beim Durchsuchen der Apps Enter drücken, um stattdessen im Internet zu suchen.</string>
|
||||
|
|
|
@ -315,4 +315,46 @@
|
|||
<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>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="one">Contiene %1$d widget.</item>
|
||||
<item quantity="many">Contiene %1$d widgets.</item>
|
||||
<item quantity="other">Contiene %1$d widgets.</item>
|
||||
</plurals>
|
||||
<string name="report_crash_button_report">Crear reporte de bug en GitHub</string>
|
||||
<string name="report_crash_title">μLauncher dejó de funcionar</string>
|
||||
<string name="send_email">Enviar correo</string>
|
||||
<string name="settings_meta_view_docs">Documentación</string>
|
||||
<string name="select_widget_title">Elegir widget</string>
|
||||
<string name="widget_menu_remove">Quitar</string>
|
||||
<string name="widget_menu_configure">Configurar</string>
|
||||
<string name="widget_menu_enable_interaction">Habilitar interacción</string>
|
||||
<string name="widget_clock_label">Reloj</string>
|
||||
<string name="widget_clock_description">El reloj predeterminado de μLauncher</string>
|
||||
<string name="manage_widget_panels_delete">Eliminar</string>
|
||||
<string name="manage_widget_panels_rename">Cambiar nombre</string>
|
||||
<string name="widget_panel_default_name">Panel de widgets #%1$d</string>
|
||||
<string name="widget_panels_title">Paneles de widgets</string>
|
||||
<string name="dialog_select_widget_panel_title">Seleccionar un panel de widgets</string>
|
||||
<string name="list_other_open_widget_panel">Abrir panel de widgets</string>
|
||||
<string name="alert_widget_panel_not_found">Este panel de widgets ya no existe.</string>
|
||||
<string name="settings_launcher_section_widgets">Widgets</string>
|
||||
<string name="report_crash_button_mail">Enviar reporte por correo</string>
|
||||
<string name="dialog_ok">Ok</string>
|
||||
<string name="content_description_add_widget">Añadir widget</string>
|
||||
<string name="content_description_add_widget_panel">Añadir panel de widgets</string>
|
||||
<string name="content_description_close">Cerrar</string>
|
||||
<string name="content_description_navigate_back">Navegar atrás</string>
|
||||
<string name="content_description_navigate_next">Navegar siguiente</string>
|
||||
<string name="content_description_lock">Bloquear</string>
|
||||
<string name="content_description_settings_actions_row_button_remove">Quitar enlace</string>
|
||||
<string name="list_other_launch_other_launcher">Iniciar otra aplicación de inicio</string>
|
||||
<string name="alert_recent_apps_failed">Error: Error al mostrar las aplicaciones recientes. (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="alert_enable_accessibility_failed">Error: Error al habilitar el servicio de accesibilidad.</string>
|
||||
<string name="widget_menu_disable_interaction">Deshabilitar interacción</string>
|
||||
<string name="dialog_create_widget_panel_title">Crear nuevo panel de widgets</string>
|
||||
<string name="report_crash_button_copy">Copiar reporte de crash al portapapeles</string>
|
||||
<string name="settings_widgets_custom_panels">Administrar paneles de widgets</string>
|
||||
<string name="list_other_recent_apps">Aplicaciones recientes</string>
|
||||
<string name="settings_gesture_swipe_larger_reverse"><![CDATA[> (Inverso)]]></string>
|
||||
<string name="settings_widgets_widgets">Administrar widgets</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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 a destra sul bordo inferiore dello schermo</string>
|
||||
<string name="settings_launcher_section_appearance">Aspetto</string>
|
||||
<string name="settings_apps_choose">Scegliere</string>
|
||||
<string name="settings_apps_choose">Associa app</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">μLauncher è progettato per essere minimale, efficiente e privo di distrazione.\n\nNon contiene annunci e non raccoglie dati.</string>
|
||||
<string name="settings_theme_color_theme_item_default">Predefinito</string>
|
||||
<string name="settings_apps_hide_bound_apps">Non mostrare applicazioni collegate a gesti nella lista delle app</string>
|
||||
<string name="settings_apps_hide_bound_apps">Non mostrare nella lista le applicazioni associate a gesti</string>
|
||||
<string name="settings_list_layout_item_text">Testo</string>
|
||||
<string name="accessibility_service_description">Impostare µLauncher come servizio accessibilità permette l\'azione di blocco dello schermo. Si precisa che sono richiesti permessi eccessivi. Non si dovrebbe mai concedere con leggerezza permessi ad alcuna app. µLauncher utilizza i servizi di accessibilità esclusivamente per il blocco dello schermo. Puoi verificare il codice sorgente. Si segnala che il blocco schermo si può attivare anche concedendo a µLauncher i permessi di amministratore, tuttavia tale metodo non funziona con lo sblocco tramite impronta o riconoscimento facciale.</string>
|
||||
<string name="settings_theme_font_item_sans_serif">Sans serif (senza grazie)</string>
|
||||
<string name="settings_gesture_description_double_up">Trascina due dita dal basso verso l\'alto</string>
|
||||
<string name="settings_apps_toast_store_not_found">Negozio non trovato</string>
|
||||
<string name="accessibility_service_description">Impostare µLauncher come servizio accessibilità permette l\'azione di blocco dello schermo. Nota che sono richiesti permessi eccessivi. Non si dovrebbero mai concedere con leggerezza permessi ad alcuna app. µLauncher utilizza i servizi di accessibilità esclusivamente per il blocco dello schermo. Puoi verificare il codice sorgente. Nota che il blocco schermo si può attivare anche concedendo a µLauncher i permessi di amministratore, tuttavia tale metodo non funziona con lo sblocco tramite impronta o riconoscimento facciale.</string>
|
||||
<string name="settings_theme_font_item_sans_serif">Sans serif</string>
|
||||
<string name="settings_gesture_description_double_up">Scorri verso l\'alto con due dita</string>
|
||||
<string name="settings_apps_toast_store_not_found">Store non trovato</string>
|
||||
<string name="settings_list_layout_item_grid">Griglia</string>
|
||||
<string name="screen_lock_method_dialog_text"><![CDATA[
|
||||
<h1>Scegli un sistema di blocco</h1>
|
||||
|
@ -30,114 +30,118 @@
|
|||
<br/>
|
||||
(Non ci si dovrebbe mai fidare di un\'applicazione qualsiasi appena scaricata su queste cose, ma puoi verificare il <a href=\"https://github.com/jrpie/Launcher\">codice sorgente</a>.)
|
||||
|
||||
In alcuni dispositivi, il PIN iniziale non verrà più utilizzato per la crittografia dei dati dopo aver attivato un servizio di accessibilità.
|
||||
|
||||
Può essere <a href="https://issuetracker.google.com/issues/37010136#comment36">riattivato</a> dopo.
|
||||
|
||||
|
||||
<br/><br/><br/><br/>
|
||||
Puoi cambiare le tue scelte in seguito nelle impostazioni.
|
||||
]]></string>
|
||||
<string name="alert_cant_open_title">Impossibile aprire l\'applicazione</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="alert_cant_open_title">Impossibile avviare l\'app</string>
|
||||
<string name="alert_cant_open_message">Modificare le impostazioni?</string>
|
||||
<string name="toast_cant_open_message">Apri impostazioni per associare un\'azione a questo gesto</string>
|
||||
<string name="settings_title">Impostazioni</string>
|
||||
<string name="settings_tab_launcher">Launcher</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_left">Sinistra</string>
|
||||
<string name="settings_gesture_description_left">Scorrere verso sinistra</string>
|
||||
<string name="settings_gesture_double_left">Due dita verso sinistra</string>
|
||||
<string name="settings_gesture_description_double_left">Scorrere verso sinistra con due dita</string>
|
||||
<string name="settings_gesture_description_left">Scorri verso sinistra</string>
|
||||
<string name="settings_gesture_double_left">Due dita a sinistra</string>
|
||||
<string name="settings_gesture_description_double_left">Scorri verso sinistra con due dita</string>
|
||||
<string name="settings_gesture_right">Destra</string>
|
||||
<string name="settings_gesture_description_right">Scorri verso destra</string>
|
||||
<string name="settings_gesture_double_right">Due dita verso destra</string>
|
||||
<string name="settings_gesture_description_double_right">Scorri a destra con due dita</string>
|
||||
<string name="settings_gesture_double_right">Due dita a destra</string>
|
||||
<string name="settings_gesture_description_double_right">Scorri verso destra con due dita</string>
|
||||
<string name="settings_gesture_right_top_edge">Destra (in alto)</string>
|
||||
<string name="settings_gesture_description_right_top_edge">Scorri verso destra sul bordo superiore dello schermo</string>
|
||||
<string name="settings_gesture_description_left_bottom_edge">Scorri verso sinistra sul bordo inferiore dello schermo</string>
|
||||
<string name="settings_gesture_description_left_top_edge">Scorri verso sinistra sul bordo superiore dello schermo</string>
|
||||
<string name="settings_gesture_up_left_edge">Verso l\'alto (lato sinistro)</string>
|
||||
<string name="settings_gesture_up">Verso l\'alto</string>
|
||||
<string name="settings_gesture_description_up">Striscia il dito dal basso verso l\'alto</string>
|
||||
<string name="settings_gesture_down">Verso il basso</string>
|
||||
<string name="settings_gesture_double_down">Trascina due dita dall\'alto verso il basso</string>
|
||||
<string name="settings_gesture_description_down">Trascina un dito dall\'alto verso il basso</string>
|
||||
<string name="settings_gesture_right_bottom_edge">Destra (bordo inferiore)</string>
|
||||
<string name="settings_gesture_left_bottom_edge">Sinistra (bordo inferiore)</string>
|
||||
<string name="settings_gesture_left_top_edge">Sinistra (bordo superiore)</string>
|
||||
<string name="settings_gesture_description_up_left_edge">Scorri verso l\'alto sul bordo sinistro dello schermo</string>
|
||||
<string name="settings_gesture_up_right_edge">Alto (lato destro)</string>
|
||||
<string name="settings_gesture_description_up_right_edge">Scorri verso l\'alto sul bordo destro dello schermo</string>
|
||||
<string name="settings_gesture_down_left_edge">Basso (bordo sinistro)</string>
|
||||
<string name="settings_gesture_description_down_left_edge">Scorri verso il basso sul bordo sinistro dello schermo</string>
|
||||
<string name="settings_gesture_down_right_edge">Basso (Lato destro)</string>
|
||||
<string name="settings_gesture_description_down_right_edge">Scorri verso il basso sul lato destro dello schermo</string>
|
||||
<string name="settings_gesture_vol_up">Aumenta il volume</string>
|
||||
<string name="settings_gesture_double_click">Doppio click</string>
|
||||
<string name="settings_gesture_description_double_click">Doppio click in un\'area vuota</string>
|
||||
<string name="settings_gesture_long_click">Tocco prolungato</string>
|
||||
<string name="settings_gesture_description_long_click">Tocco prolungato su un\'area vuota</string>
|
||||
<string name="settings_gesture_description_right_top_edge">Scorri a destra sul bordo superiore dello schermo</string>
|
||||
<string name="settings_gesture_description_left_bottom_edge">Scorri a sinistra sul bordo inferiore dello schermo</string>
|
||||
<string name="settings_gesture_description_left_top_edge">Scorri a sinistra sul bordo superiore dello schermo</string>
|
||||
<string name="settings_gesture_up_left_edge">Su (bordo sinistro)</string>
|
||||
<string name="settings_gesture_up">Su</string>
|
||||
<string name="settings_gesture_description_up">Scorri verso l\'alto</string>
|
||||
<string name="settings_gesture_down">Giù</string>
|
||||
<string name="settings_gesture_double_down">Scorri giù con due dita</string>
|
||||
<string name="settings_gesture_description_down">Scorri verso il basso</string>
|
||||
<string name="settings_gesture_right_bottom_edge">Destra (in basso)</string>
|
||||
<string name="settings_gesture_left_bottom_edge">Sinistra (in basso)</string>
|
||||
<string name="settings_gesture_left_top_edge">Sinistra (in alto)</string>
|
||||
<string name="settings_gesture_description_up_left_edge">Scorri in alto sul bordo sinistro dello schermo</string>
|
||||
<string name="settings_gesture_up_right_edge">Su (bordo destro)</string>
|
||||
<string name="settings_gesture_description_up_right_edge">Scorri in alto sul bordo destro dello schermo</string>
|
||||
<string name="settings_gesture_down_left_edge">Giù (bordo sinistro)</string>
|
||||
<string name="settings_gesture_description_down_left_edge">Scorri in basso sul bordo sinistro dello schermo</string>
|
||||
<string name="settings_gesture_down_right_edge">Giù (bordo destro)</string>
|
||||
<string name="settings_gesture_description_down_right_edge">Scorri in basso sul bordo destro dello schermo</string>
|
||||
<string name="settings_gesture_vol_up">Volume +</string>
|
||||
<string name="settings_gesture_double_click">Doppio tap</string>
|
||||
<string name="settings_gesture_description_double_click">Doppio tap in spazio vuoto</string>
|
||||
<string name="settings_gesture_long_click">Tap lungo</string>
|
||||
<string name="settings_gesture_description_long_click">Tap lungo in spazio vuoto</string>
|
||||
<string name="settings_gesture_date">Data</string>
|
||||
<string name="settings_gesture_description_date">Premi sulla data</string>
|
||||
<string name="settings_gesture_description_date">Tap sulla data</string>
|
||||
<string name="settings_gesture_time">Ora</string>
|
||||
<string name="settings_gesture_description_time">Premi sull\'ora</string>
|
||||
<string name="settings_gesture_description_vol_up">Premi il pulsante di aumento del volume</string>
|
||||
<string name="settings_gesture_vol_down">Riduci il volume</string>
|
||||
<string name="settings_gesture_description_vol_down">Premi il pulsante per ridurre il volume</string>
|
||||
<string name="settings_apps_install">Installa le applicazioni</string>
|
||||
<string name="settings_gesture_description_time">Tap sull\'ora</string>
|
||||
<string name="settings_gesture_description_vol_up">Premi il pulsante Volume +</string>
|
||||
<string name="settings_gesture_vol_down">Volume -</string>
|
||||
<string name="settings_gesture_description_vol_down">Premi il pulsante Volume -</string>
|
||||
<string name="settings_apps_install">Installa apps</string>
|
||||
<string name="settings_theme_monochrome_icons">Icone monocromatiche</string>
|
||||
<string name="settings_clock_time_visible">Mostra l\'ora</string>
|
||||
<string name="settings_clock_date_visible">Mostra la data</string>
|
||||
<string name="settings_clock_localized">Usa il formato ora locale</string>
|
||||
<string name="settings_clock_show_seconds">Mostra i secondi</string>
|
||||
<string name="settings_clock_time_visible">Mostra orario</string>
|
||||
<string name="settings_clock_date_visible">Mostra data</string>
|
||||
<string name="settings_clock_localized">Usa formato data locale</string>
|
||||
<string name="settings_clock_show_seconds">Mostra secondi</string>
|
||||
<string name="settings_launcher_section_date_time"><![CDATA[Data e ora]]></string>
|
||||
<string name="settings_enabled_gestures_double_swipe_summary">Scorri con due dita</string>
|
||||
<string name="settings_enabled_gestures_double_swipe">Azioni a scorrimento con due dita</string>
|
||||
<string name="settings_enabled_gestures_double_swipe">Scorrimento a due dita</string>
|
||||
<string name="settings_functionality_auto_launch">Apri il risultato della ricerca</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Azioni a scorrimento ai lati dello schermo</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_summary">Scorri sul lato dello schermo</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_edge_width">Larghezza margine laterale</string>
|
||||
<string name="settings_meta_view_code">Vedi il codice sorgente</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Scorrimento sui bordi dello schermo</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_summary">Scorri sui bordi dello schermo</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_edge_width">Larghezza bordo</string>
|
||||
<string name="settings_meta_view_code">Codice sorgente</string>
|
||||
<string name="list_other_list">Tutte le applicazioni</string>
|
||||
<string name="list_other_list_favorites">Applicazioni preferite</string>
|
||||
<string name="list_other_track_next">Musica: passa alla traccia successiva</string>
|
||||
<string name="list_other_volume_down">Musica: riduci il volume</string>
|
||||
<string name="list_other_track_previous">Musica: torna alla traccia precedente</string>
|
||||
<string name="list_other_volume_up">Musica: Aumenta il volume</string>
|
||||
<string name="list_other_track_next">Musica: traccia successiva</string>
|
||||
<string name="list_other_volume_down">Abbassa volume</string>
|
||||
<string name="list_other_track_previous">Musica: traccia precedente</string>
|
||||
<string name="list_other_volume_up">Alza volume</string>
|
||||
<string name="undo">Annulla</string>
|
||||
<string name="list_other_expand_settings_panel">Impostazioni rapide</string>
|
||||
<string name="device_admin_explanation">Azione necessaria per abilitare il blocco dello schermo.</string>
|
||||
<string name="settings_theme_text_shadow">Ombreggiatura del testo</string>
|
||||
<string name="settings_theme_background">Sfondo (lista applicazioni e impostazioni)</string>
|
||||
<string name="device_admin_explanation">Azione necessaria per abilitare il blocco schermo.</string>
|
||||
<string name="settings_theme_text_shadow">Ombreggiatura testo</string>
|
||||
<string name="settings_theme_background">Sfondo (lista apps e impostazioni)</string>
|
||||
<string name="settings_theme_font">Font</string>
|
||||
<string name="settings_clock_flip_date_time">Inverti data e ora</string>
|
||||
<string name="settings_theme_wallpaper">Scegli uno sfondo</string>
|
||||
<string name="settings_theme_wallpaper">Imposta sfondo</string>
|
||||
<string name="settings_launcher_section_display">Schermo</string>
|
||||
<string name="settings_display_screen_timeout_disabled">Mantieni lo schermo acceso</string>
|
||||
<string name="settings_display_rotate_screen">Ruota lo schermo</string>
|
||||
<string name="settings_launcher_section_functionality">Funzionalità</string>
|
||||
<string name="settings_functionality_auto_keyboard">Apri automaticamente la tastiera per cercare</string>
|
||||
<string name="settings_display_rotate_screen">Ruota schermo</string>
|
||||
<string name="settings_launcher_section_functionality">Funzioni</string>
|
||||
<string name="settings_functionality_auto_keyboard">Apri automaticamente la tastiera</string>
|
||||
<string name="settings_launcher_sensitivity">Sensibilità</string>
|
||||
<string name="list_title_pick">Scegli un\'applicazione</string>
|
||||
<string name="list_title_pick">Scegli applicazione</string>
|
||||
<string name="tutorial_setup_title">Configurazione</string>
|
||||
<string name="tutorial_setup_text">Abbiamo impostato alcune app predefinite per te. Puoi modificarle ora se lo desideri:</string>
|
||||
<string name="tutorial_setup_text_2">Puoi anche cambiare la tua selezione in seguito.</string>
|
||||
<string name="tutorial_setup_text">Abbiamo impostato alcune app predefinite. Puoi modificarle ora se vuoi:</string>
|
||||
<string name="tutorial_setup_text_2">Puoi anche modificare la selezione in seguito.</string>
|
||||
<string name="tutorial_finish_title">Iniziamo!</string>
|
||||
<string name="tutorial_finish_text">Sei pronto per iniziare! Spero questa applicazione ti risulti preziosa! - Finn (che ha ideato il launcher)\n \te Josia (che ha aggiunto qualche miglioramento e mantiene il fork μLauncher)</string>
|
||||
<string name="tutorial_finish_text">Sei pronto per iniziare!\n\nSpero che lo apprezzi!\n\n- Finn (che ha fatto Launcher) e Josia (che ha apportato alcuni miglioramenti e mantiene il fork μLauncher)</string>
|
||||
<string name="tutorial_finish_button">Inizia</string>
|
||||
<string name="settings">Impostazioni</string>
|
||||
<string name="ic_menu_alt">Altre opzioni</string>
|
||||
<string name="tutorial_usage_text_2">Puoi aprire le tue app facendo scorrere il dito sullo schermo o premendo un pulsante. Configura i gesti nella prossima slide.</string>
|
||||
<string name="alert_cant_expand_status_bar_panel">Errore: impossibile espandere la barra di stato. Questa azione utilizza funzionalità non incluse nelle API Android pubbliche. Sfortunatamente, non sembra funzionare sul tuo dispositivo.</string>
|
||||
<string name="snackbar_app_hidden">Applicazione nascosta. Puoi renderla nuovamente visibile nelle impostazioni.</string>
|
||||
<string name="toast_device_admin_not_enabled">µLauncher deve essere autorizzato come amministratore del dispositivo per bloccare lo schermo.</string>
|
||||
<string name="device_admin_description">Abilita il blocco dello schermo</string>
|
||||
<string name="tutorial_usage_text_2">Puoi avviare le tue app principali scorrendo il dito sullo schermo o premendo un pulsante.</string>
|
||||
<string name="alert_cant_expand_status_bar_panel">Errore: impossibile espandere la barra di stato. Questa azione utilizza funzionalità non incluse nelle API Android. Sfortunatamente, non sembra funzionare sul tuo dispositivo.</string>
|
||||
<string name="snackbar_app_hidden">Applicazione nascosta. Puoi renderla nuovamente visibile dalle impostazioni.</string>
|
||||
<string name="toast_device_admin_not_enabled">µLauncher deve amministrare il dispositivo per poter bloccare lo schermo.</string>
|
||||
<string name="device_admin_description">Abilita il blocco schermo</string>
|
||||
<string name="alert_no_torch_found">Nessuna camera con torcia rilevata.</string>
|
||||
<string name="alert_torch_access_exception">Errore: impossibile accedere alla torcia.</string>
|
||||
<string name="toast_accessibility_service_not_enabled">Il servizio accessibilità per µLauncher non è attivo. Per favore attivalo nelle impostazioni</string>
|
||||
<string name="toast_accessibility_service_not_enabled">Il servizio accessibilità per µLauncher non è attivo. Attivalo nelle impostazioni</string>
|
||||
<string name="alert_lock_screen_failed">Errore: impossibile bloccare lo schermo. (Se hai appena aggiornato l\'app, prova a disabilitare e riattivare il servizio accessibilità nelle impostazioni del telefono)</string>
|
||||
<string name="toast_lock_screen_not_supported">Errore: Il blocco schermo tramite accessibilità non è supportato su questo dispositivo. Per favore usa invece il servizio amministratore dispositivo.</string>
|
||||
<string name="accessibility_service_name">µLauncher - blocco schermo</string>
|
||||
<string name="toast_lock_screen_not_supported">Errore: Il blocco schermo tramite accessibilità non è supportato su questo dispositivo. In alternativa usa il servizio amministratore dispositivo.</string>
|
||||
<string name="accessibility_service_name">μLauncher</string>
|
||||
<string name="screen_lock_method_dialog_title">Scegli come bloccare lo schermo</string>
|
||||
<string name="screen_lock_method_use_accessibility">Usa il servizio accessibilità</string>
|
||||
<string name="screen_lock_method_use_device_admin">Usa l\'amministratore dispositivo</string>
|
||||
<string name="screen_lock_method_use_device_admin">Usa Amministratore dispositivo</string>
|
||||
<string name="settings_actions_lock_method">Scegli un sistema di blocco dello schermo</string>
|
||||
<string name="settings_theme_color_theme_item_dark">Scuro</string>
|
||||
<string name="settings_theme_color_theme_item_light">Chiaro</string>
|
||||
|
@ -145,22 +149,22 @@
|
|||
<string name="settings_theme_background_item_blur">Sfocato</string>
|
||||
<string name="settings_theme_background_item_solid">Solido</string>
|
||||
<string name="settings_theme_font_item_system_default">Predefinito di sistema</string>
|
||||
<string name="settings_theme_font_item_serif">Serif (con grazie)</string>
|
||||
<string name="settings_theme_font_item_monospace">Monospace (a larghezza fissa)</string>
|
||||
<string name="settings_theme_font_item_serif_monospace">Serif monospace (a larghezza fissa con grazie)</string>
|
||||
<string name="settings_theme_font_item_serif">Serif</string>
|
||||
<string name="settings_theme_font_item_monospace">Monospace</string>
|
||||
<string name="settings_theme_font_item_serif_monospace">Serif monospace</string>
|
||||
<string name="settings_launcher_section_apps">Applicazioni</string>
|
||||
<string name="settings_apps_hidden">Applicazioni nascoste</string>
|
||||
<string name="settings_list_layout">Configurazione della lista applicazioni</string>
|
||||
<string name="settings_list_layout">Configura la lista applicazioni</string>
|
||||
<string name="settings_list_layout_item_default">Predefinito</string>
|
||||
<string name="settings_theme_background_item_dim">Offuscato</string>
|
||||
<string name="settings_general_choose_home_screen">Imposta μLauncher come predefinito per la schermata principale</string>
|
||||
<string name="settings_meta_cant_select_launcher">Informazioni sulle applicazioni</string>
|
||||
<string name="settings_meta_show_tutorial">Apri il tutorial del launcher</string>
|
||||
<string name="settings_meta_reset">Ripristina le impostazioni predefinite</string>
|
||||
<string name="settings_meta_reset_confirm">Stai per eliminare tutte le preferenze impostate. Vuoi continuare?</string>
|
||||
<string name="settings_theme_background_item_dim">Soffuso</string>
|
||||
<string name="settings_general_choose_home_screen">Imposta μLauncher come predefinito</string>
|
||||
<string name="settings_meta_cant_select_launcher">Informazioni app</string>
|
||||
<string name="settings_meta_show_tutorial">Tutorial di µLauncher</string>
|
||||
<string name="settings_meta_reset">Ripristina le impostazioni</string>
|
||||
<string name="settings_meta_reset_confirm">Stai per ripristinare tutte le impostazioni. Continuare?</string>
|
||||
<string name="settings_meta_report_bug">Segnala un bug</string>
|
||||
<string name="settings_meta_fork_contact">Contatta lo sviluppatore del fork</string>
|
||||
<string name="settings_meta_join_chat">Partecipa alla chat di μLauncher</string>
|
||||
<string name="settings_meta_join_chat">Unisciti alla chat di μLauncher</string>
|
||||
<string name="settings_meta_privacy">Informativa sulla privacy</string>
|
||||
<string name="settings_meta_contact">Contatta lo sviluppatore originale</string>
|
||||
<string name="settings_meta_discord">Unisciti a noi su Discord!</string>
|
||||
|
@ -168,9 +172,9 @@
|
|||
<string name="list_title_favorite">Applicazioni preferite</string>
|
||||
<string name="list_title_hidden">Applicazioni nascoste</string>
|
||||
<string name="list_tab_app">Applicazioni</string>
|
||||
<string name="list_tab_other">Altri</string>
|
||||
<string name="list_tab_other">Altro</string>
|
||||
<string name="list_app_delete">Disinstalla</string>
|
||||
<string name="list_app_info">Informazioni sull\'app</string>
|
||||
<string name="list_app_info">Informazioni app</string>
|
||||
<string name="list_app_favorite_add">Aggiungi ai preferiti</string>
|
||||
<string name="list_app_favorite_remove">Rimuovi dai preferiti</string>
|
||||
<string name="list_app_hidden_add">Nascondi</string>
|
||||
|
@ -178,29 +182,29 @@
|
|||
<string name="list_app_rename">Rinomina</string>
|
||||
<string name="list_apps_search_hint">Cerca</string>
|
||||
<string name="list_other_settings">Impostazioni μLauncher</string>
|
||||
<string name="list_other_expand_notifications_panel">Espandi il pannello notifiche</string>
|
||||
<string name="list_other_expand_notifications_panel">Espandi pannello notifiche</string>
|
||||
<string name="list_other_nop">Non fare niente</string>
|
||||
<string name="list_other_lock_screen">Blocca lo schermo</string>
|
||||
<string name="list_other_torch">Accendi/spegni la torcia</string>
|
||||
<string name="list_other_lock_screen">Blocca schermo</string>
|
||||
<string name="list_other_torch">Torcia ON/OFF</string>
|
||||
<string name="tutorial_title">Tutorial</string>
|
||||
<string name="tutorial_start_text">Prenditi qualche secondo per imparare ad usare questo launcher!</string>
|
||||
<string name="tutorial_start_text">👋\n\nPrenditi qualche secondo per imparare ad usare questo launcher!</string>
|
||||
<string name="tutorial_concept_title">Concetto</string>
|
||||
<string name="tutorial_concept_text_2">L\'app è open source (sotto licenza MIT) e disponibile su GitHub! Visita il nostro archivio!</string>
|
||||
<string name="tutorial_concept_text_2">E\' software libero (licenza MIT)!\nAssicurati di controllare il repository!</string>
|
||||
<string name="tutorial_usage_title">Utilizzo</string>
|
||||
<string name="tutorial_usage_text">La schermata principale contiene solo data e ora. Nessuna distrazione.</string>
|
||||
<string name="alert_requires_android_m">Questa funzione richiede Android 6 o successivi.</string>
|
||||
<string name="dialog_rename_title">Rinomina %1$s</string>
|
||||
<string name="settings_theme_color_theme_item_dynamic">Dinamico</string>
|
||||
<string name="settings_clock_color">Colore</string>
|
||||
<string name="settings_gesture_double_up">Due dita verso l\'alto</string>
|
||||
<string name="settings_gesture_double_up">Scorri su con due dita</string>
|
||||
<string name="dialog_consent_accessibility_privileges">Sono consapevole che questo concederà privilegi estesi a µLauncher.</string>
|
||||
<string name="dialog_consent_accessibility_consent">Accetto che µLauncher utilizzi il servizio di accessibilità per fornire funzionalità non correlate all\'accessibilità.</string>
|
||||
<string name="dialog_consent_accessibility_data_collection">Accetto che µLauncher non raccolga alcun dato.</string>
|
||||
<string name="settings_apps_hide_paused_apps">Nascondi le app in pausa</string>
|
||||
<string name="list_other_toggle_private_space_lock">Attiva/Disattiva Blocco Spazio Privato</string>
|
||||
<string name="alert_requires_android_v">Questa funzionalità richiede Android 15 o successivi.</string>
|
||||
<string name="list_other_toggle_private_space_lock">Blocca/Sblocca Spazio Privato</string>
|
||||
<string name="alert_requires_android_v">Questa funzione richiede Android 15 o successivi.</string>
|
||||
<string name="dialog_select_color_red">Rosso</string>
|
||||
<string name="dialog_select_color_alpha">Trasparente</string>
|
||||
<string name="dialog_select_color_alpha">Alpha</string>
|
||||
<string name="dialog_select_color_blue">Blu</string>
|
||||
<string name="dialog_select_color_green">Verde</string>
|
||||
<string name="dialog_select_color_color_hex">Colore</string>
|
||||
|
@ -208,24 +212,135 @@
|
|||
<string name="dialog_consent_accessibility_ok">Attiva Servizi di Accessibilità</string>
|
||||
<string name="dialog_consent_accessibility_other_options">Sono consapevole che esistono altre opzioni (utilizzando i privilegi di amministratore del dispositivo o il pulsante di accensione).</string>
|
||||
<string name="dialog_consent_accessibility_title">Attivazione dei Servizi di Accessibilità</string>
|
||||
<string name="settings_functionality_search_web">Cerca su internet</string>
|
||||
<string name="settings_functionality_search_web_summary">Premi invio durante la ricerca nell\'elenco delle app per avviare una ricerca su internet.</string>
|
||||
<string name="settings_functionality_search_web">Cerca sul web</string>
|
||||
<string name="settings_functionality_search_web_summary">Invio in ricerca app per avviare una ricerca web.</string>
|
||||
<string name="list_apps_search_hint_no_auto_launch">Cerca (senza avvio automatico)</string>
|
||||
<string name="settings_meta_licenses">Licenze Open Source</string>
|
||||
<string name="legal_info_title">Licenze Open Source</string>
|
||||
<string name="dialog_report_bug_title">Segnala un bug</string>
|
||||
<string name="dialog_report_bug_info">Grazie per aver contribuito a migliorare µLauncher!\nSi prega di aggiungere le seguenti informazioni alla segnalazione del bug:</string>
|
||||
<string name="dialog_report_bug_info">Grazie per il tuo contributo al miglioramento di µLauncher!\nAggiungi le seguenti informazioni alla segnalazione del bug:</string>
|
||||
<string name="dialog_report_bug_button_clipboard">Copia negli appunti</string>
|
||||
<string name="dialog_report_bug_security_info">Non segnalare pubblicamente le vulnerabilità di sicurezza su GitHub, ma utilizza invece:</string>
|
||||
<string name="dialog_report_bug_security_info">Non segnalare le vulnerabilità di sicurezza pubblicamente su GitHub, ma usa invece:</string>
|
||||
<string name="dialog_cancel">Annulla</string>
|
||||
<string name="settings_functionality_auto_launch_summary">Premi spazio per disabilitare temporaneamente questa funzionalità.</string>
|
||||
<string name="settings_functionality_auto_launch_summary">Spazio per disabilitare temporaneamente.</string>
|
||||
<string name="dialog_report_bug_button_security">Segnala una vulnerabilità di sicurezza</string>
|
||||
<string name="dialog_report_bug_create_report">Crea una segnalazione</string>
|
||||
<string name="toast_private_space_locked">Spazio privato bloccato</string>
|
||||
<string name="toast_private_space_unlocked">Spazio privato sbloccato</string>
|
||||
<string name="toast_private_space_not_available">Spazio privato non disponibile</string>
|
||||
<string name="toast_private_space_default_home_screen">µLauncher deve essere la schermata iniziale predefinita per accedere allo spazio privato.</string>
|
||||
<string name="toast_private_space_default_home_screen">µLauncher deve essere il launcher predefinito per poter accedere allo spazio privato.</string>
|
||||
<string name="toast_activity_not_found_browser">Impossibile aprire l\'URL: nessun browser trovato.</string>
|
||||
<string name="toast_activity_not_found_search_web">Non è stata trovata un\'applicazione per gestire la ricerca.</string>
|
||||
<string name="dialog_consent_accessibility_text"><![CDATA[Stai per arrivare il servizio di accessibilità. Questo garantirà <strong>privilegi più ampi</strong> a µLauncher.<br/>µLauncher utilizzerà questi privilegi <strong>solo per bloccare lo schermo</strong>. µLauncher <strong>non raccoglierà mai alcun dato</strong>. In particolare, µLauncher non usa il servizio di accessibilità per raccogliere nessun dato.]]></string>
|
||||
<string name="toast_activity_not_found_search_web">Nessuna applicazione trovata per gestire la ricerca.</string>
|
||||
<string name="dialog_consent_accessibility_text"><![CDATA[Stai per attivare il servizio di accessibilità. Questo concederà <strong>privilegi estesi</strong> a μLauncher.<br/>μLauncher userà questi privilegi <strong>solo</strong> per eseguire le seguenti azioni:
|
||||
<ul>
|
||||
<li>Blocco shermo</li>
|
||||
<li>App recenti</li>
|
||||
</ul>
|
||||
μLauncher <strong>non raccoglierà mai alcun dato</strong>. In particolare, μLauncher non utilizza il servizio di accessibilità per raccogliere dati.]]></string>
|
||||
<string name="list_title_private_space">Spazio privato</string>
|
||||
<string name="list_other_list_private_space">Spazio privato</string>
|
||||
<string name="list_other_volume_adjust">Regola volume</string>
|
||||
<string name="pin_shortcut_button_bind">Associa al gesto</string>
|
||||
<string name="settings_display_hide_status_bar">Nascondi barra di stato</string>
|
||||
<string name="settings_display_hide_navigation_bar">Nascondi barra di navigazione</string>
|
||||
<string name="settings_meta_donate">Dona</string>
|
||||
<string name="list_other_recent_apps">App recenti</string>
|
||||
<string name="settings_gesture_tap_up">Tap + Su</string>
|
||||
<string name="settings_gesture_description_tap_up">Tap e scorri su</string>
|
||||
<string name="settings_gesture_tap_down">Tap + Giù</string>
|
||||
<string name="settings_gesture_description_tap_down">Tap e scorri verso il basso</string>
|
||||
<string name="settings_gesture_tap_left">Tap + Sinistra</string>
|
||||
<string name="settings_gesture_tap_right">Tap + Destra</string>
|
||||
<string name="settings_gesture_description_swipe_larger">Alto sx -> centro dx -> basso sx</string>
|
||||
<string name="settings_gesture_description_tap_left">Tap e scorri vesro sinistra</string>
|
||||
<string name="settings_gesture_description_tap_right">Tap e scorri verso destra</string>
|
||||
<string name="settings_gesture_swipe_larger_reverse"><![CDATA[> (Inverso)]]></string>
|
||||
<string name="settings_gesture_description_swipe_larger_reverse">Basso sx -> centro dx -> alto sx</string>
|
||||
<string name="settings_gesture_description_swipe_smaller">Alto dx -> centro sx -> basso dx</string>
|
||||
<string name="settings_gesture_swipe_v">V</string>
|
||||
<string name="settings_gesture_description_swipe_v">Alto sx -> centro basso -> alto dx</string>
|
||||
<string name="settings_gesture_swipe_v_reverse">V (Inverso)</string>
|
||||
<string name="settings_gesture_description_swipe_v_reverse">Alto dx -> centro basso -> alto sx</string>
|
||||
<string name="settings_gesture_swipe_lambda">Λ</string>
|
||||
<string name="settings_gesture_description_swipe_lambda">Basso sx -> centro alto -> basso dx</string>
|
||||
<string name="settings_gesture_description_swipe_lambda_reverse">Basso dx -> centro alto -> basso sx</string>
|
||||
<string name="settings_gesture_swipe_smaller"><![CDATA[<]]></string>
|
||||
<string name="settings_gesture_swipe_smaller_reverse"><![CDATA[< (Inverso)]]></string>
|
||||
<string name="settings_gesture_swipe_lambda_reverse">Λ (Inverso)</string>
|
||||
<string name="list_other_track_play_pause">Musica: Riproduci / Pausa</string>
|
||||
<string name="settings_list_reverse_layout">Inverti la lista applicazioni</string>
|
||||
<string name="settings_tab_actions">Azioni</string>
|
||||
<string name="settings_gesture_description_back">Pulsante / gesto indietro</string>
|
||||
<string name="settings_gesture_back">Indietro</string>
|
||||
<string name="settings_gesture_description_swipe_smaller_reverse">Basso dx -> centro sx -> alto dx</string>
|
||||
<string name="settings_apps_hide_private_space_apps">Nascondi lo spazio privato dalla lista app</string>
|
||||
<string name="list_other_launch_other_launcher">Avvia un altro launcher</string>
|
||||
<string name="pin_shortcut_title">Aggiungi scorciatoia</string>
|
||||
<string name="settings_gesture_swipe_larger"><![CDATA[>]]></string>
|
||||
<string name="pin_shortcut_switch_visible">Mostra in lista app</string>
|
||||
<string name="tooltip_lock_private_space">Blocca spazio privato</string>
|
||||
<string name="tooltip_unlock_private_space">Sblocca spazio privato</string>
|
||||
<string name="tutorial_concept_label_version">Versione</string>
|
||||
<string name="alert_enable_accessibility_failed">Errore: impossibile abilitare il servizio di accessibilità.</string>
|
||||
<string name="tutorial_app_list_text_2">Quando corrisponde una sola app, viene avviata automaticamente.\nPuoi disabilitare l\'avvio con uno spazio prima della query.</string>
|
||||
<string name="tutorial_app_list_title">Tutte le app</string>
|
||||
<string name="tutorial_app_list_text">Puoi cercare rapidamente tra tutte le app nella lista app.\n\nScorri su per la lista o associa ad un gesto diverso.</string>
|
||||
<string name="alert_recent_apps_failed">Errore: impossibile mostrare le app recenti. (Se hai appena aggiornato l\'app, prova a disabilitare e riabilitare il servizio di accessibilità dalle impostazioni del telefono)</string>
|
||||
<string name="settings_functionality_auto_close_keyboard">Chiudi la tastiera durante lo scorrimento</string>
|
||||
<string name="settings_widgets_widgets">Gestione widget</string>
|
||||
<string name="widget_menu_remove">Rimuovi</string>
|
||||
<string name="settings_widgets_custom_panels">Gestione pannelli widget</string>
|
||||
<string name="select_widget_title">Scegli widget</string>
|
||||
<string name="widget_menu_configure">Configura</string>
|
||||
<string name="widget_menu_enable_interaction">Abilita interazione</string>
|
||||
<string name="widget_menu_disable_interaction">Disabilita interazione</string>
|
||||
<string name="widget_clock_label">Orologio</string>
|
||||
<string name="widget_clock_description">Orologio predefinito di μLauncher</string>
|
||||
<string name="manage_widget_panels_delete">Elimina</string>
|
||||
<string name="manage_widget_panels_rename">Rinomina</string>
|
||||
<string name="widget_panel_default_name">Pannello widget #%1$d</string>
|
||||
<string name="dialog_ok">Ok</string>
|
||||
<string name="widget_panels_title">Pannelli widget</string>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="one">Contiene %1$d widget.</item>
|
||||
<item quantity="many">Contiene %1$d widget.</item>
|
||||
<item quantity="other">Contiene %1$d widget.</item>
|
||||
</plurals>
|
||||
<string name="dialog_create_widget_panel_title">Crea nuovo pannello widget</string>
|
||||
<string name="list_other_open_widget_panel">Apri pannello widget</string>
|
||||
<string name="alert_widget_panel_not_found">Questo pannello widget non esiste più.</string>
|
||||
<string name="settings_launcher_section_widgets">Widget</string>
|
||||
<string name="dialog_select_widget_panel_title">Seleziona pannello widget</string>
|
||||
<string name="dialog_select_widget_panel_info_no_panels"><![CDATA[Nessun pannello widget trovato. Puoi creare pannelli widget da Impostazioni > Launcher > Gestione Pannelli Widget.]]></string>
|
||||
<string name="settings_meta_view_docs">Documentazione</string>
|
||||
<string name="notification_crash_explanation">Scusa! Clicca per altre info.</string>
|
||||
<string name="notification_crash_title">µLauncher è crashato</string>
|
||||
<string name="report_crash_button_copy">Copia il rapporto del crash negli appunti</string>
|
||||
<string name="report_crash_button_mail">Invia il rapporto per email</string>
|
||||
<string name="report_crash_button_report">Crea un bug report in GitHub</string>
|
||||
<string name="report_crash_title">µLauncher è crashato</string>
|
||||
<string name="send_email">Invia email</string>
|
||||
<string name="notification_channel_crash">Info su crash e debug</string>
|
||||
<string name="crash_info"><![CDATA[
|
||||
Sembra che qualcosa sia andato storto, mi scuso per questo!<br><br>
|
||||
Per motivi di privacy, i log dei crash non sono raccolti automaticamente.<br>
|
||||
Comunque i log sono molto utili per il debug, quindi ti sarei molto grato se potessi inviarmi i log per email
|
||||
oppure aprire un bug report su github.<br><br>
|
||||
Nota che i crash log potrebbero contenere <strong>informazioni sensibili</strong>, come il nome dell\'app che hai provato ad avviare.
|
||||
Please <strong>redact</strong> such information before sending the report.
|
||||
<h2>What can I do now?</h2>
|
||||
If this bug appears again and again, you can try several things:
|
||||
<ul>
|
||||
<li>Force stop μLauncher</li>
|
||||
<li>Clear μLauncher\'s storage (<strong>Your settings will be lost!</strong>)</li>
|
||||
<li>Install an older version (<a href=\"https://github.com/jrpie/Launcher/releases\">GitHub</a>, <a href=\"https://f-droid.org/en/packages/de.jrpie.android.launcher\">F-Droid</a>)</li>
|
||||
</ul>
|
||||
]]></string>
|
||||
<string name="content_description_add_widget_panel">Aggiungi pannello widget</string>
|
||||
<string name="content_description_close">Chiudi</string>
|
||||
<string name="content_description_navigate_back">Naviga indietro</string>
|
||||
<string name="content_description_navigate_next">Naviga avanti</string>
|
||||
<string name="content_description_lock">Blocca</string>
|
||||
<string name="content_description_add_widget">Aggiungi widget</string>
|
||||
<string name="content_description_settings_actions_row_button_remove">Rimuovi associazione</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,16 +1,118 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!--
|
||||
-
|
||||
- Home - Pradžia
|
||||
-
|
||||
-->
|
||||
<string name="alert_cant_open_title">Nepavyksta paleisti programėlės</string>
|
||||
<string name="alert_cant_open_message">Norite pakeisti nustatymus?</string>
|
||||
<string name="toast_cant_open_message">Atidarykite nustatymus norėdami pasirinkti šio gesto veiksmą</string>
|
||||
<!--
|
||||
-
|
||||
- Settings
|
||||
-
|
||||
-->
|
||||
<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>
|
||||
<!--
|
||||
-
|
||||
- Settings : Apps
|
||||
-
|
||||
-->
|
||||
<string name="settings_gesture_back">Atgal</string>
|
||||
<string name="settings_gesture_description_back">Grįžimo mygtukas / grįžimo gestas</string>
|
||||
<string name="settings_gesture_up">Aukštyn</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>
|
||||
<string name="settings_gesture_double_up">Dvigubai aukštyn</string>
|
||||
<string name="settings_gesture_description_double_up">Perbraukite aukštyn dviem pirštais</string>
|
||||
<string name="settings_gesture_down">Žemyn</string>
|
||||
<string name="settings_gesture_description_down">Perbraukite žemyn</string>
|
||||
<string name="settings_gesture_tap_down">Bakstelėkite + žemyn</string>
|
||||
<string name="settings_gesture_description_tap_down">Bakstelėkite ir perbraukite žemyn</string>
|
||||
<string name="settings_gesture_double_down">Dvigubai žemyn</string>
|
||||
<string name="settings_gesture_description_double_down">Perbraukite dviem pirštais</string>
|
||||
<string name="settings_gesture_left">Kairėje</string>
|
||||
<string name="settings_gesture_description_left">Perbraukite į kairę</string>
|
||||
<string name="settings_gesture_tap_left">Bakstelėkite + kairę</string>
|
||||
<string name="settings_gesture_description_tap_left">Bakstelėkite ir perbraukite į kairę</string>
|
||||
<string name="settings_gesture_double_left">Dvigubai kairėje</string>
|
||||
<string name="settings_gesture_description_double_left">Du pirštais perbraukite kairėn</string>
|
||||
<string name="settings_gesture_right">Dešinė</string>
|
||||
<string name="settings_gesture_description_right">Perbraukite į dešinę</string>
|
||||
<string name="settings_gesture_tap_right">Bakstelėkite + dešinė</string>
|
||||
<string name="settings_gesture_description_tap_right">Bakstelėkite ir perbraukite į dešinę</string>
|
||||
<string name="settings_gesture_double_right">Dviguba dešinė</string>
|
||||
<string name="settings_gesture_description_double_right">Perbraukite į dešinę dviem pirštais</string>
|
||||
<string name="settings_gesture_right_top_edge">Dešinė (viršuje)</string>
|
||||
<string name="settings_gesture_description_right_top_edge">Perbraukite tiesiai ekrano viršuje</string>
|
||||
<string name="settings_gesture_right_bottom_edge">Dešinė (apačia)</string>
|
||||
<string name="settings_gesture_description_right_bottom_edge">Perbraukite tiesiai ekrano apačioje</string>
|
||||
<string name="settings_gesture_left_bottom_edge">Kairė (apačia)</string>
|
||||
<string name="settings_gesture_description_left_bottom_edge">Perbraukite į kairę ekrano apačioje</string>
|
||||
<string name="settings_gesture_left_top_edge">Kairė (viršuje)</string>
|
||||
<string name="settings_gesture_description_left_top_edge">Perbraukite kairėn ekrano viršuje</string>
|
||||
<string name="settings_gesture_up_left_edge">Aukštyn (kairysis kraštas)</string>
|
||||
<string name="settings_gesture_description_up_left_edge">Perbraukite aukštyn kairiajame ekrano krašte</string>
|
||||
<string name="settings_gesture_up_right_edge">Aukštyn (dešinysis kraštas)</string>
|
||||
<string name="settings_gesture_description_up_right_edge">Perbraukite aukštyn dešiniajame ekrano krašte</string>
|
||||
<string name="settings_gesture_down_left_edge">Žemyn (kairysis kraštas)</string>
|
||||
<string name="settings_gesture_description_down_left_edge">Perbraukite žemyn kairiajame ekrano krašte</string>
|
||||
<string name="settings_gesture_down_right_edge">Žemyn (dešinysis kraštas)</string>
|
||||
<string name="settings_gesture_description_down_right_edge">Žemyn (dešinysis kraštas)</string>
|
||||
<string name="settings_gesture_vol_up">Garsumo didinimo klavišas</string>
|
||||
<string name="settings_gesture_description_vol_up">Paspauskite mygtuką „Volume Up“</string>
|
||||
<string name="settings_gesture_vol_down">Volume žemyn klavišas</string>
|
||||
<string name="settings_gesture_description_vol_down">Paspauskite mygtuką „Volume Down“</string>
|
||||
<string name="settings_gesture_double_click">Dukart spustelėkite</string>
|
||||
<string name="settings_gesture_description_double_click">Dukart spustelėkite tuščią sritį</string>
|
||||
<string name="settings_gesture_long_click">Ilgas spustelėjimas</string>
|
||||
<string name="settings_gesture_description_long_click">Ilgai spustelėkite tuščią sritį</string>
|
||||
<string name="settings_gesture_date">Data</string>
|
||||
<string name="settings_gesture_description_date">Spustelėkite datą</string>
|
||||
<string name="settings_gesture_time">Laikas</string>
|
||||
<string name="settings_gesture_description_time">Spustelėkite laiką</string>
|
||||
<string name="settings_widgets_widgets">Tvarkykite valdiklius</string>
|
||||
<string name="settings_widgets_custom_panels">Tvarkykite valdiklio skydelius</string>
|
||||
<string name="settings_apps_choose">Pasirinkite programą</string>
|
||||
<string name="settings_apps_install">Įdiekite programas</string>
|
||||
<string name="settings_apps_toast_store_not_found">Parduotuvėje nerasta</string>
|
||||
<!--
|
||||
-
|
||||
- Settings : Launcher
|
||||
-
|
||||
-->
|
||||
<string name="settings_launcher_section_appearance">Išvaizda</string>
|
||||
<string name="settings_theme_color_theme">Spalvos tema</string>
|
||||
<string name="settings_theme_color_theme_item_default">Numatytasis</string>
|
||||
<string name="settings_theme_color_theme_item_dark">Tamsu</string>
|
||||
<string name="settings_theme_color_theme_item_light">Šviesa</string>
|
||||
<string name="settings_theme_color_theme_item_dynamic">Dinaminis</string>
|
||||
<string name="settings_theme_text_shadow">Teksto šešėlis</string>
|
||||
<string name="settings_theme_background">Fonas (programų sąrašas ir nustatymas)</string>
|
||||
<string name="settings_theme_background_item_transparent">Skaidrus</string>
|
||||
<string name="settings_theme_background_item_dim">Dim</string>
|
||||
<string name="settings_theme_background_item_blur">Blur</string>
|
||||
<string name="settings_theme_background_item_solid">Solidus</string>
|
||||
<string name="settings_theme_font">Šriftas</string>
|
||||
<!-- names for @array/settings_theme_font_values -->
|
||||
<string name="settings_theme_font_item_system_default">Sistemos numatytasis</string>
|
||||
<string name="settings_theme_font_item_sans_serif">Be serifo</string>
|
||||
<string name="settings_theme_font_item_serif">Serifas</string>
|
||||
<string name="settings_theme_font_item_monospace">Monoerdvė</string>
|
||||
<string name="settings_theme_font_item_serif_monospace">Serifo monospace</string>
|
||||
<string name="settings_theme_monochrome_icons">Vienspalvių programų piktogramos</string>
|
||||
<string name="settings_launcher_section_date_time"><![CDATA[Date & time]]></string>
|
||||
<string name="settings_clock_color">Spalva</string>
|
||||
<string name="settings_clock_time_visible">Rodyti laiką</string>
|
||||
<string name="settings_clock_date_visible">Rodyti datą</string>
|
||||
<string name="settings_clock_localized">Naudoti lokalizuotą datos formatą</string>
|
||||
<string name="settings_clock_show_seconds">Rodyti sekundes</string>
|
||||
<string name="settings_clock_flip_date_time">Apversti datą ir laiką</string>
|
||||
<string name="settings_theme_wallpaper">Pasirinkite ekrano foną</string>
|
||||
<string name="settings_launcher_section_display">Ekranas</string>
|
||||
</resources>
|
||||
|
|
312
app/src/main/res/values-nl/strings.xml
Normal file
312
app/src/main/res/values-nl/strings.xml
Normal file
|
@ -0,0 +1,312 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="settings_gesture_description_double_up">Met twee vingers naar boven vegen</string>
|
||||
<string name="settings_widgets_widgets">Bewerk widgets</string>
|
||||
<string name="settings_clock_color">Kleur</string>
|
||||
<string name="settings_apps_toast_store_not_found">App-winkel niet gevonden</string>
|
||||
<string name="settings_launcher_section_appearance">Uiterlijk</string>
|
||||
<string name="settings_theme_color_theme">Kleurenschema</string>
|
||||
<string name="settings_theme_color_theme_item_default">Standaard</string>
|
||||
<string name="settings_theme_color_theme_item_dark">Donker</string>
|
||||
<string name="settings_apps_choose">Kies app</string>
|
||||
<string name="settings_general_choose_home_screen">µLauncher als standaard instellen</string>
|
||||
<string name="settings_meta_cant_select_launcher">App info</string>
|
||||
<string name="settings_meta_show_tutorial">Bekijk de µLauncher handleiding</string>
|
||||
<string name="settings_meta_view_code">Broncode bekijken</string>
|
||||
<string name="settings_meta_report_bug">Een probleem melden</string>
|
||||
<string name="dialog_report_bug_title">Een probleem melden</string>
|
||||
<string name="dialog_report_bug_button_clipboard">Naar klembord kopiëren</string>
|
||||
<string name="dialog_report_bug_security_info">Meld veiligheidsproblemen niet publiek op GitHub, gebruik daarvoor het volgende:</string>
|
||||
<string name="dialog_report_bug_create_report">Rapport maken</string>
|
||||
<string name="settings_meta_fork_contact">Neem contact met de ontwikkelaar van de fork op</string>
|
||||
<string name="settings_meta_join_chat">Word lid van de µLauncher chat</string>
|
||||
<string name="settings_meta_reset">Instellingen terugzetten</string>
|
||||
<string name="pin_shortcut_button_bind">Aan gebaar binden</string>
|
||||
<string name="pin_shortcut_switch_visible">In aaps-lijst tonen</string>
|
||||
<string name="tutorial_start_text">👋\n\nEen korte uitleg over hoe µLauncher functioneert.</string>
|
||||
<string name="alert_enable_accessibility_failed">Foutmelding: De toegankelijkheidsdienst kon niet ingeschakeld worden.</string>
|
||||
<string name="settings_gesture_description_tap_right">Tikken en dan naar rechts vegen</string>
|
||||
<string name="settings_functionality_search_web_summary">Druk tijdens het zoeken naar apps enter, om op het internet te zoeken.</string>
|
||||
<string name="toast_cant_open_message">Instellingen openen om voor dit gebaar een actie te kiezen</string>
|
||||
<string name="settings_clock_localized">Gebruik gelokalizeerde datumformaat</string>
|
||||
<string name="dialog_cancel">Annuleren</string>
|
||||
<string name="settings_gesture_description_back">Terug-knop of gebaar</string>
|
||||
<string name="settings_gesture_description_left_bottom_edge">Onderin naar links vegen</string>
|
||||
<string name="settings_gesture_description_down_right_edge">Rechts naar beneden vegen</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_summary">In de hoek vegen</string>
|
||||
<string name="tutorial_title">Handleiding</string>
|
||||
<string name="settings_gesture_description_double_down">Met twee vingers naar beneder vegen</string>
|
||||
<string name="settings_apps_install">Apps installeren</string>
|
||||
<string name="settings_list_layout_item_grid">Rooster</string>
|
||||
<string name="settings_meta_reset_confirm">Hierdoor verwijdert u alle instellingen. Doorgaan?</string>
|
||||
<string name="dialog_report_bug_info">Bedankt voor het helpen verbeteren van μLauncher!\nHet zou behulpzaam zijn om volgende informatie aan het rapport toe te voegen:</string>
|
||||
<string name="pin_shortcut_title">Shortcut toevoegen</string>
|
||||
<string name="alert_no_torch_found">Foutmelding: Er werd geen zaklamp gevonden.</string>
|
||||
<string name="alert_torch_access_exception">Foutmelding: Geen toegang tot de zaklamp.</string>
|
||||
<string name="accessibility_service_description">Door μLauncher in te stellen als toegankelijkheidsdienst kan het scherm worden vergrendeld en het menu met recente apps worden geopend. Merk op dat veel toestemingen vereist zijn. Wees hierdoor erg vorzichtig bij het geven van zulke machten aan een app. μLauncher zal de toegankelijkheidsdienst alleen gebruiken om de volgende acties uit te voeren wanneer de gebruiker daarom vraagt: * vergrendelscherm * recente apps openen μLauncher zal de toegankelijkheidsdienst nooit gebruiken om gegevens te verzamelen. U kunt de broncode controleren om er zeker van te zijn. Merk op dat het vergrendelen van het scherm ook kan worden bereikt door μLauncher apparaatbeheerdersrechten te geven, maar dat werkt echter niet met vingerafdruk- en gezichtsontgrendeling.</string>
|
||||
<string name="screen_lock_method_dialog_text"><![CDATA[
|
||||
<h1>Methode voor vergrendeling kiezen</h1>
|
||||
Er zijn twee methodes om het scherm te vergrendelen.
|
||||
Helaas hebben beide nadelen:<br/><br/>
|
||||
|
||||
<h3>Apparaatbeheerder</h3>
|
||||
Werkt niet met ontgrendeling via vingerafdruk of gezichtsherkenning.
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<h3>Toegankelijkheidsdienst</h3>
|
||||
Vereist veel rechten.
|
||||
μLauncher gebruikt deze rechten alleen om het scherm te vergrendelen.
|
||||
<br/>
|
||||
(Echter moet u niet zomaar een willekeurige app zulke rechten geven, maar u kunt de <a href=\"https://github.com/jrpie/Launcher\">Broncode</a>bekijken.)
|
||||
<br/>
|
||||
Op sommige apparaten wordt de pin niet meer gebruikt om data te vergrendelen na het aanzetten van een toegankelijkheidsdienst.
|
||||
Dit kan nadehand <a href="https://issuetracker.google.com/issues/37010136#comment36">heraktiveerd</a> worden .
|
||||
|
||||
<br/><br/><br/><br/>
|
||||
U kunt uw keuze altijd in de instellingen veranderen.
|
||||
]]></string>
|
||||
<string name="dialog_consent_accessibility_text"><![CDATA[U gaat hiermee de toegankelijkheidsdienst activeren. Dit geeft <strong>uitgebreide privileges</strong> aan μLauncher.<br/>μLauncher gebruikt deze privileges <strong>alleenmaar</strong> voor volgende doeleinde:
|
||||
<ul>
|
||||
<li>Vergrendelscherm</li>
|
||||
<li>Recente apps</li>
|
||||
</ul>
|
||||
μLauncher <strong>verzamelt nooit gegevens</strong>. Onder anderen, μLauncher gebruikt de toegankelijkheidsdienst om gegevens verzamelen.]]></string>
|
||||
<string name="settings_widgets_custom_panels">Bewerk widget paneel</string>
|
||||
<string name="settings_theme_color_theme_item_light">Licht</string>
|
||||
<string name="settings_theme_color_theme_item_dynamic">Dynamisch</string>
|
||||
<string name="settings_theme_text_shadow">Tekstschaduw</string>
|
||||
<string name="settings_theme_background">Achtergrond (zichtbaar in de instelligen en de app-lijst)</string>
|
||||
<string name="settings_theme_background_item_transparent">Doorzichtig</string>
|
||||
<string name="settings_theme_background_item_dim">Dimmen</string>
|
||||
<string name="settings_theme_background_item_blur">Vervagen</string>
|
||||
<string name="settings_theme_background_item_solid">Eenkleurig</string>
|
||||
<string name="settings_theme_font">Lettertype</string>
|
||||
<string name="settings_theme_font_item_system_default">Systeemstandaard</string>
|
||||
<string name="settings_theme_font_item_sans_serif">Sans sarif</string>
|
||||
<string name="settings_theme_font_item_serif">Serif</string>
|
||||
<string name="settings_theme_font_item_monospace">Monospace</string>
|
||||
<string name="settings_theme_font_item_serif_monospace">Serif monospace</string>
|
||||
<string name="settings_theme_monochrome_icons">Eenkleurige aap-icoontjes</string>
|
||||
<string name="settings_launcher_section_date_time"><![CDATA[Datum & Tijd]]></string>
|
||||
<string name="settings_functionality_auto_keyboard">Toetenbord in de apps-lijst automatisch openen</string>
|
||||
<string name="settings_launcher_section_apps">Apps</string>
|
||||
<string name="settings_list_layout_item_text">Tekst</string>
|
||||
<string name="settings_meta_donate">Doneer</string>
|
||||
<string name="settings_meta_privacy">Privacybeleid</string>
|
||||
<string name="settings_meta_contact">Contact opnemen met de oorspronkelijke ontwikkelaar</string>
|
||||
<string name="settings_meta_discord">Wordt lid van onze Discord</string>
|
||||
<string name="list_title_view">Alle apps</string>
|
||||
<string name="list_title_favorite">Favorieten</string>
|
||||
<string name="list_title_hidden">Verstopte apps</string>
|
||||
<string name="list_title_private_space">Privébereik</string>
|
||||
<string name="list_title_pick">App kiezen</string>
|
||||
<string name="list_tab_app">Apps</string>
|
||||
<string name="list_tab_other">Andere</string>
|
||||
<string name="list_app_delete">Deïnstalleren</string>
|
||||
<string name="list_app_info">App info</string>
|
||||
<string name="list_app_favorite_add">Aan favorieten toevoegen</string>
|
||||
<string name="list_app_favorite_remove">Uit favorieten verwijderen</string>
|
||||
<string name="list_app_hidden_add">Verstoppen</string>
|
||||
<string name="list_app_hidden_remove">Zichtbaar maken</string>
|
||||
<string name="list_app_rename">Hernoemen</string>
|
||||
<string name="list_apps_search_hint">Zoeken</string>
|
||||
<string name="list_apps_search_hint_no_auto_launch">Zoeken (geen snelstart)</string>
|
||||
<string name="list_other_settings">µLauncher instellingen</string>
|
||||
<string name="list_other_list">Alle apps</string>
|
||||
<string name="list_other_list_favorites">Favoriete apps</string>
|
||||
<string name="list_other_list_private_space">Privéruimte</string>
|
||||
<string name="list_other_toggle_private_space_lock">Privéruimte (ont)sluiten</string>
|
||||
<string name="list_other_volume_up">Volume omhoog</string>
|
||||
<string name="list_other_volume_down">Volume omlaag</string>
|
||||
<string name="list_other_volume_adjust">Volume veranderen</string>
|
||||
<string name="list_other_track_next">Muziek: Volgende</string>
|
||||
<string name="list_other_track_previous">Muziek: Vorige</string>
|
||||
<string name="list_other_track_play_pause">Muziek: Afspelen / Pauzeren</string>
|
||||
<string name="list_other_expand_notifications_panel">Medling-scherm uitvouwen</string>
|
||||
<string name="list_other_recent_apps">Recente apps</string>
|
||||
<string name="list_other_lock_screen">Scherm vergrendelen</string>
|
||||
<string name="list_other_torch">Zaklamp aan / uit</string>
|
||||
<string name="list_other_launch_other_launcher">Andere launcher gebruiken</string>
|
||||
<string name="tutorial_concept_title">Concept</string>
|
||||
<string name="tutorial_concept_text">µLauncher biedt een minimalistische, efficiënte en afleidingsvrije omgeving.\n\nDe app is vrije software, het heeft geen advertenties en verzamelt geen data.</string>
|
||||
<string name="tutorial_concept_label_version">Versie</string>
|
||||
<string name="tutorial_usage_title">Gebruik</string>
|
||||
<string name="tutorial_usage_text">Het startscherm toont allen de datum en tijd. Geen afleiding.</string>
|
||||
<string name="tutorial_usage_text_2">Vaak gebruikte apps kunnen via gebaren of de volumeknoppen geopend worden.</string>
|
||||
<string name="tutorial_app_list_title">Alle apps</string>
|
||||
<string name="tutorial_app_list_text">In de applijst kan snel en eenvoudig naar apps gezocht worden.\n\nVeeg omhoog om de lijst te openen, of verander het gebaar in de settings.</string>
|
||||
<string name="tutorial_app_list_text_2">Als maar één app bij het zoekbegrip past, wordt deze automatisch geopend.\nDoor een spatie voor het zoekbegrip intevoegen wordt dit onderdrukt.</string>
|
||||
<string name="tutorial_setup_title">Instellen</string>
|
||||
<string name="tutorial_setup_text">Wij hebben een paar standaard-apps voor u gekozen, u mag deze gerust veranderen:</string>
|
||||
<string name="tutorial_setup_text_2">De selectie kan op elk moment in de instellingen aangepast worden.</string>
|
||||
<string name="tutorial_finish_title">Starten!</string>
|
||||
<string name="tutorial_finish_text">Het kan beginnen!\n\nWij hopen dat deze app u helpt!\n\n- Finn (de ontwikelaar) en Josia (de ontwikkelaar van de fork µLauncher)</string>
|
||||
<string name="tutorial_finish_button">Starten</string>
|
||||
<string name="settings">Instellingen</string>
|
||||
<string name="ic_menu_alt">Meer opties</string>
|
||||
<string name="alert_cant_expand_status_bar_panel">Foutmelding: Deze actie gebruikt een functie dat niet onderdeel is van de Android API, uw apparaat ondersteunt deze functie niet.</string>
|
||||
<string name="alert_requires_android_m">Deze functie is pas vanaf Android 6 beschikbaar.</string>
|
||||
<string name="alert_requires_android_v">Deze functie is pas vanaf Android 15 beschikbaar.</string>
|
||||
<string name="snackbar_app_hidden">De app werd verstopt, het kan in de settings weer zichtbaar gemaakt worden.</string>
|
||||
<string name="undo">Ongedaan maken</string>
|
||||
<string name="list_other_expand_settings_panel">Snelle instellingen</string>
|
||||
<string name="alert_recent_apps_failed">Foutmelding: Kon geen recente apps tonen (probeer de toegankelijkheidsdienst in de apparaatinstellingen uit en weer aan te zetten)</string>
|
||||
<string name="toast_device_admin_not_enabled">µLauncher moet apparaatbeheerder zijn om het scherm te mogen vergrendelen.</string>
|
||||
<string name="device_admin_explanation">Dit is nodig om het scherm te kunnen vergrendelen.</string>
|
||||
<string name="device_admin_description">De actie \"scherm vergrendelen\" activeren</string>
|
||||
<string name="toast_accessibility_service_not_enabled">De toegankelijkheidsdienst voor µLauncher staat niet aan. Schakel het aan in de instellingen</string>
|
||||
<string name="alert_lock_screen_failed">Foutmelding: Kon het scherm niet vergrendelen (probeer de toegankelijkheidsdienst in de apparaatinstellingen uit en weer aan te zetten)</string>
|
||||
<string name="toast_private_space_locked">Privégedeelte vergrendelt</string>
|
||||
<string name="toast_private_space_unlocked">Privégedeelte ontgrendelt</string>
|
||||
<string name="toast_private_space_not_available">Privégedeelte is niet bereikbaar</string>
|
||||
<string name="toast_private_space_default_home_screen">µLauncher moet als standaard-launcher ingesteld zijn om tot de privégegedeelte toegeang te krijgen.</string>
|
||||
<string name="tooltip_lock_private_space">Privégedeelte vergrendelen</string>
|
||||
<string name="tooltip_unlock_private_space">Privégedeelte ontgrendelen</string>
|
||||
<string name="toast_lock_screen_not_supported">Foutmelding: Op dit apparaat kan het scherm via de toegankelijkheidsdienst niet vergrendelt worden. Maak µLauncher apparaatbeheerder hiervoor.</string>
|
||||
<string name="accessibility_service_name">µLauncher</string>
|
||||
<string name="screen_lock_method_dialog_title">Methode voor vergrendeling kiezen</string>
|
||||
<string name="screen_lock_method_use_accessibility">Gebruik toegankelijkheidsdienst</string>
|
||||
<string name="screen_lock_method_use_device_admin">Gebruik apparaatadministratie</string>
|
||||
<string name="settings_actions_lock_method">Kies een methode om het scherm te vergrendelen</string>
|
||||
<string name="dialog_rename_title">%1$s hernoemen</string>
|
||||
<string name="dialog_select_color_red">Rood</string>
|
||||
<string name="dialog_select_color_alpha">Doorzichtigheid</string>
|
||||
<string name="dialog_select_color_blue">Blauw</string>
|
||||
<string name="dialog_select_color_green">Groen</string>
|
||||
<string name="dialog_select_color_color_hex">Kleur</string>
|
||||
<string name="dialog_choose_color_title">Kleur kiezen</string>
|
||||
<string name="dialog_consent_accessibility_other_options">Ik ben me ervan bewust dat er andere opties bestaan (met beheerdersrechten of de aan/uit-knop).</string>
|
||||
<string name="dialog_consent_accessibility_consent">Ik geef μLauncher toestemming om de toegankelijkheidservice te gebruiken om functionaliteit te bieden die niet gerelateerd is aan toegankelijkheid.</string>
|
||||
<string name="dialog_consent_accessibility_privileges">Ik ben me ervan bewust ik hierdoor uitgebreide privileges verleen aan μLauncher.</string>
|
||||
<string name="dialog_consent_accessibility_data_collection">Ik geef μLauncher toestemming om geen gegevens te verzamelen.</string>
|
||||
<string name="dialog_consent_accessibility_title">Toegankelijkheidsservice activeren</string>
|
||||
<string name="dialog_consent_accessibility_ok">Toegankelijkheidsservice activeren</string>
|
||||
<string name="settings_meta_licenses">Open Source licenties</string>
|
||||
<string name="legal_info_title">Open Source licenties</string>
|
||||
<string name="toast_activity_not_found_search_web">Geen app gevonden om de zoekopdracht uit te voeren.</string>
|
||||
<string name="select_widget_title">Kies widget</string>
|
||||
<string name="widget_menu_remove">Verwijder</string>
|
||||
<string name="widget_menu_configure">Configureren</string>
|
||||
<string name="widget_menu_enable_interaction">Interactie inschakelen</string>
|
||||
<string name="widget_menu_disable_interaction">Interactie uitschakelen</string>
|
||||
<string name="widget_clock_label">Klok</string>
|
||||
<string name="widget_clock_description">De standaard klok van µLauncher</string>
|
||||
<string name="manage_widget_panels_delete">Verwijder</string>
|
||||
<string name="manage_widget_panels_rename">Hernoem</string>
|
||||
<string name="widget_panel_default_name">Widget Paneel #%1$d</string>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="one">Beinhoudt %d widget.</item>
|
||||
<item quantity="other">Beinhoudt %d widgets.</item>
|
||||
</plurals>
|
||||
<string name="dialog_ok">Oké</string>
|
||||
<string name="widget_panels_title">Widget paneel</string>
|
||||
<string name="dialog_select_widget_panel_title">Selecteer een widget paneel</string>
|
||||
<string name="dialog_create_widget_panel_title">Maak een nieuwe widget paneel</string>
|
||||
<string name="dialog_select_widget_panel_info_no_panels"><![CDATA[Geen widget paneel gevonden. U kan een widget paneel maken in > Launcher > Beheer widget paneelen.]]></string>
|
||||
<string name="list_other_open_widget_panel">Open widget paneel</string>
|
||||
<string name="alert_widget_panel_not_found">Deze widget paneel bestaat niet meer.</string>
|
||||
<string name="settings_launcher_section_widgets">Widgets</string>
|
||||
<string name="alert_cant_open_title">App kan niet geopend worden</string>
|
||||
<string name="alert_cant_open_message">App-instellingen aanpassen?</string>
|
||||
<string name="settings_title">Instellingen</string>
|
||||
<string name="settings_tab_actions">Acties</string>
|
||||
<string name="settings_tab_launcher">Launcher</string>
|
||||
<string name="settings_tab_meta">Meta</string>
|
||||
<string name="settings_gesture_back">Terug</string>
|
||||
<string name="settings_gesture_up">Naar boven</string>
|
||||
<string name="settings_gesture_description_up">Naar boven vegen</string>
|
||||
<string name="settings_gesture_description_tap_up">Tikken en dan naar boven vegen</string>
|
||||
<string name="settings_gesture_double_up">Dubbel tikken en naar boven vegen</string>
|
||||
<string name="settings_gesture_description_down">Naar beneden vegen</string>
|
||||
<string name="settings_gesture_down">Naar beneden</string>
|
||||
<string name="settings_gesture_tap_down">Tikken en naar beneden</string>
|
||||
<string name="settings_gesture_description_tap_down">Tikken en naar beneden vegen</string>
|
||||
<string name="settings_gesture_tap_up">Tikken en boven</string>
|
||||
<string name="settings_gesture_double_down">Dubbel naar beneden</string>
|
||||
<string name="settings_gesture_left">Naar links</string>
|
||||
<string name="settings_gesture_description_left">Naar links vegen</string>
|
||||
<string name="settings_gesture_tap_left">Tikken en links</string>
|
||||
<string name="settings_gesture_description_tap_left">Tikken en dan naar links vegen</string>
|
||||
<string name="settings_gesture_double_left">Dubbel links</string>
|
||||
<string name="settings_gesture_description_double_left">Met twee vingers naar links vegen</string>
|
||||
<string name="settings_gesture_right">Naar rechts</string>
|
||||
<string name="settings_gesture_description_right">Naar rechts vegen</string>
|
||||
<string name="settings_gesture_tap_right">Tikken en rechts</string>
|
||||
<string name="settings_gesture_double_right">Dubbel rechts</string>
|
||||
<string name="settings_gesture_description_double_right">Met twee vingers naar beneden vegen</string>
|
||||
<string name="settings_gesture_right_top_edge">Rechts (boven)</string>
|
||||
<string name="settings_gesture_description_right_top_edge">Bovenin naar rechts vegen</string>
|
||||
<string name="settings_gesture_right_bottom_edge">Rechts (beneden)</string>
|
||||
<string name="settings_gesture_description_right_bottom_edge">Onderin naar rechts vegen</string>
|
||||
<string name="settings_gesture_left_bottom_edge">Links (onder)</string>
|
||||
<string name="settings_gesture_left_top_edge">Links (boven)</string>
|
||||
<string name="settings_gesture_description_left_top_edge">Bovenin naar liniks vegen</string>
|
||||
<string name="settings_gesture_up_left_edge">Omhoog (links)</string>
|
||||
<string name="settings_gesture_description_up_left_edge">Links naar boven vegen</string>
|
||||
<string name="settings_gesture_up_right_edge">Omhoog (rechts)</string>
|
||||
<string name="settings_gesture_description_up_right_edge">Rechts naar boven vegen</string>
|
||||
<string name="settings_gesture_down_left_edge">Omlaag (links)</string>
|
||||
<string name="settings_gesture_description_down_left_edge">Links naar beneden vegen</string>
|
||||
<string name="settings_gesture_down_right_edge">Omlaag (rechts)</string>
|
||||
<string name="settings_gesture_swipe_larger"><![CDATA[>]]></string>
|
||||
<string name="settings_gesture_description_swipe_larger">Boven links -> midden rechts -> onder links</string>
|
||||
<string name="settings_gesture_swipe_larger_reverse"><![CDATA[> (Achteruit)]]></string>
|
||||
<string name="settings_gesture_description_swipe_larger_reverse">Onder links -> midden rechts -> boven links</string>
|
||||
<string name="settings_gesture_swipe_smaller"><![CDATA[<]]></string>
|
||||
<string name="settings_gesture_vol_up">Volume omhoog knop</string>
|
||||
<string name="settings_gesture_description_vol_up">Druk de \"volume omhoog\" knop</string>
|
||||
<string name="settings_gesture_vol_down">Volume omlaag knop</string>
|
||||
<string name="settings_gesture_description_vol_down">Druk de \"volume omlaag\" knop</string>
|
||||
<string name="settings_gesture_double_click">Dubbelklik</string>
|
||||
<string name="settings_gesture_description_double_click">Dubbeltik op een lege plek</string>
|
||||
<string name="settings_gesture_long_click">Lange tik</string>
|
||||
<string name="settings_gesture_description_long_click">Op een lege plek lang tikken</string>
|
||||
<string name="settings_gesture_date">Datum</string>
|
||||
<string name="settings_gesture_description_date">Op de datum tikken</string>
|
||||
<string name="settings_gesture_time">Klok</string>
|
||||
<string name="settings_gesture_description_time">Op de tijd tikken</string>
|
||||
<string name="settings_gesture_description_swipe_smaller">Boven rechts -> midden links -> onder rechts</string>
|
||||
<string name="settings_gesture_swipe_smaller_reverse"><![CDATA[< (Achteruit)]]></string>
|
||||
<string name="settings_gesture_description_swipe_smaller_reverse">Onder rechts -> midden links -> boven rechts</string>
|
||||
<string name="settings_gesture_swipe_v">V</string>
|
||||
<string name="settings_gesture_description_swipe_v">Boven links -> onder midden -> boven rechts</string>
|
||||
<string name="settings_gesture_swipe_v_reverse">V (Achteruit)</string>
|
||||
<string name="settings_gesture_description_swipe_v_reverse">Boven rechts -> onder rechts -> boven links</string>
|
||||
<string name="settings_gesture_swipe_lambda">Λ</string>
|
||||
<string name="settings_gesture_description_swipe_lambda">Onder links -> boven midden -> onder rechts</string>
|
||||
<string name="settings_gesture_swipe_lambda_reverse">Λ (Achteruit)</string>
|
||||
<string name="settings_gesture_description_swipe_lambda_reverse">Onder rechts -> boven midden -> boven links</string>
|
||||
<string name="settings_clock_time_visible">Toon de tijd</string>
|
||||
<string name="settings_clock_date_visible">Toon de datum</string>
|
||||
<string name="settings_clock_show_seconds">Toon sekondes</string>
|
||||
<string name="settings_clock_flip_date_time">Spiegel datum en tijd</string>
|
||||
<string name="settings_theme_wallpaper">Achtergrond kiezen</string>
|
||||
<string name="settings_launcher_section_display">Beeldscherm</string>
|
||||
<string name="settings_display_screen_timeout_disabled">Beeldscherm aanhouden</string>
|
||||
<string name="settings_display_hide_status_bar">Statusbalk verbergen</string>
|
||||
<string name="settings_display_hide_navigation_bar">Navigatiebalk verbergen</string>
|
||||
<string name="settings_display_rotate_screen">Scherm draaien</string>
|
||||
<string name="settings_launcher_section_functionality">Functionaliteit</string>
|
||||
<string name="settings_enabled_gestures_double_swipe">Dubbele veeg gebaaren</string>
|
||||
<string name="settings_enabled_gestures_double_swipe_summary">Met twee vingers vegen</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Hoek-gebaren</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_edge_width">Kantbreedte</string>
|
||||
<string name="settings_functionality_auto_launch">Start zoekresultaten</string>
|
||||
<string name="settings_functionality_auto_launch_summary">Spatie drukken om deze functie tijdelijk te onderdruken.</string>
|
||||
<string name="settings_functionality_search_web">Op het internet zoeken</string>
|
||||
<string name="dialog_report_bug_button_security">Beveiligingsprobleem melden</string>
|
||||
<string name="tutorial_concept_text_2">MIT licentie\nDe broncode is op GitHub te vinden.</string>
|
||||
<string name="settings_functionality_auto_close_keyboard">Toetsenbord sluiten bij scrollen</string>
|
||||
<string name="settings_launcher_sensitivity">Gevoeligheid</string>
|
||||
<string name="settings_apps_hidden">Verstopte apps</string>
|
||||
<string name="settings_apps_hide_bound_apps">Toon apps die aan een gebaar gekoppeld zijn niet in de apps-lijst</string>
|
||||
<string name="settings_apps_hide_paused_apps">Gepauzeerde apps verstoppen</string>
|
||||
<string name="settings_apps_hide_private_space_apps">Toon de privéruimte niet in de apps-lijst</string>
|
||||
<string name="settings_list_layout">Opmaat van de apps-lijst</string>
|
||||
<string name="settings_list_reverse_layout">Apps-lijst omkeren</string>
|
||||
<string name="settings_list_layout_item_default">Standaard</string>
|
||||
<string name="list_other_nop">Niets doen</string>
|
||||
<string name="toast_activity_not_found_browser">URL kan niet geopend worden: geen browser gevonden.</string>
|
||||
</resources>
|
281
app/src/main/res/values-pl/strings.xml
Normal file
281
app/src/main/res/values-pl/strings.xml
Normal file
|
@ -0,0 +1,281 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="settings_gesture_right_bottom_edge">W prawo (Dół)</string>
|
||||
<string name="settings_gesture_description_down_left_edge">Przeciągnij w dół, po lewej krawędzi ekranu</string>
|
||||
<string name="settings_gesture_swipe_smaller"><![CDATA[<]]></string>
|
||||
<string name="toast_cant_open_message">Otwórz ustawienia by wybrać akcje dla tego gestu</string>
|
||||
<string name="settings_title">Ustawienia</string>
|
||||
<string name="settings_tab_actions">Akcja</string>
|
||||
<string name="settings_gesture_description_back">Przycisk cofnięcia / akcja cofnięcia</string>
|
||||
<string name="settings_gesture_up">W górę</string>
|
||||
<string name="settings_gesture_description_up">Przeciągnij w górę</string>
|
||||
<string name="settings_gesture_tap_up">Kliknij + W górę</string>
|
||||
<string name="settings_gesture_description_tap_up">Kliknij i przeciągnij w górę</string>
|
||||
<string name="settings_gesture_double_up">Dwoma w górę</string>
|
||||
<string name="settings_gesture_description_double_up">Przeciągnij dwoma palcami w górę</string>
|
||||
<string name="settings_gesture_down">W dół</string>
|
||||
<string name="settings_gesture_description_down">Przeciągnij w dół</string>
|
||||
<string name="settings_gesture_tap_down">Kliknij + W dół</string>
|
||||
<string name="settings_gesture_double_down">Dwoma w dół</string>
|
||||
<string name="settings_gesture_description_double_down">Przeciągnij dwoma palcami w dół</string>
|
||||
<string name="settings_gesture_left">W lewo</string>
|
||||
<string name="settings_gesture_description_left">Przeciągnij w lewo</string>
|
||||
<string name="settings_gesture_tap_left">Kliknij + W lewo</string>
|
||||
<string name="settings_gesture_description_tap_left">Kliknij i przeciągnij w lewo</string>
|
||||
<string name="settings_gesture_double_left">Dwoma w lewo</string>
|
||||
<string name="settings_gesture_description_double_left">Przeciągnij dwoma palcami w lewo</string>
|
||||
<string name="settings_gesture_right">W prawo</string>
|
||||
<string name="settings_gesture_tap_right">Kliknij + W prawo</string>
|
||||
<string name="settings_gesture_description_tap_right">Kliknij i przeciągnij w prawo</string>
|
||||
<string name="settings_gesture_double_right">Dwoma w prawo</string>
|
||||
<string name="settings_gesture_description_double_right">Przeciągnij dwoma palcami w prawo</string>
|
||||
<string name="settings_gesture_right_top_edge">W prawo (Góra)</string>
|
||||
<string name="settings_gesture_description_right_bottom_edge">Przeciągnij w prawo, w dolnej części ekranu</string>
|
||||
<string name="settings_gesture_left_bottom_edge">W lewo (Dół)</string>
|
||||
<string name="settings_gesture_description_left_bottom_edge">Przeciągnij w lewo, w dolnej części ekranu</string>
|
||||
<string name="settings_gesture_left_top_edge">W lewo (Góra)</string>
|
||||
<string name="settings_gesture_up_left_edge">W górę (Lewa krawędź)</string>
|
||||
<string name="settings_gesture_description_up_left_edge">Przeciągnij w górę, po lewej krawędzi ekranu</string>
|
||||
<string name="settings_gesture_up_right_edge">W górę (Prawa krawędź)</string>
|
||||
<string name="settings_gesture_description_up_right_edge">Przeciągnij w górę, po prawej krawędzi ekranu</string>
|
||||
<string name="settings_gesture_down_left_edge">W dół (Lewa krawędź)</string>
|
||||
<string name="settings_gesture_down_right_edge">W dół (Prawa krawędź)</string>
|
||||
<string name="settings_gesture_description_down_right_edge">Przeciągnij w dół, po prawej krawędzi ekranu</string>
|
||||
<string name="settings_gesture_description_swipe_larger">Górny lewy -> środek prawo -> dolny lewy</string>
|
||||
<string name="settings_gesture_swipe_larger_reverse"><![CDATA[> (Odwrotnie)]]></string>
|
||||
<string name="settings_gesture_swipe_larger"><![CDATA[>]]></string>
|
||||
<string name="settings_gesture_swipe_v">V</string>
|
||||
<string name="settings_gesture_swipe_lambda">Λ</string>
|
||||
<string name="alert_cant_open_title">Nie można otworzyć aplikacji</string>
|
||||
<string name="settings_gesture_back">Cofnij</string>
|
||||
<string name="alert_cant_open_message">Chcesz zmienić to ustawienie?</string>
|
||||
<string name="settings_gesture_description_right">Przeciągnij w prawo</string>
|
||||
<string name="settings_gesture_description_swipe_larger_reverse">Dolny lewy -> środek prawo -> górny lewy</string>
|
||||
<string name="settings_gesture_description_tap_down">Kliknij i przeciągnij w dół</string>
|
||||
<string name="settings_gesture_description_right_top_edge">Przeciągnij w prawo, w górnej części ekranu</string>
|
||||
<string name="settings_gesture_description_left_top_edge">Przeciągnij w lewo, w górnej części ekranu</string>
|
||||
<string name="dialog_report_bug_button_security">Zgłoś lukę w zabezpieczeniach</string>
|
||||
<string name="list_other_list">Wszystkie aplikacje</string>
|
||||
<string name="tutorial_usage_title">Użytek</string>
|
||||
<string name="toast_private_space_not_available">Przestrzeń prywatna jest niedostępna</string>
|
||||
<string name="settings_clock_flip_date_time">Zamień date i zegar</string>
|
||||
<string name="settings_apps_hide_bound_apps">Nie pokazuje aplikacji przypisanych do gestów w liście aplikacji</string>
|
||||
<string name="dialog_report_bug_info">Dziękujemy za pomoc w udoskonaleniu μLauncher!\nProszę przemyśl dodanie podanych informacji do twojego zgłoszenia błędu:</string>
|
||||
<string name="settings_meta_discord">Dołącz do nas na Discordzie!</string>
|
||||
<string name="list_other_track_previous">Muzyka: Poprzednie</string>
|
||||
<string name="settings_launcher_section_appearance">Wygląd</string>
|
||||
<string name="settings_theme_font_item_system_default">Domyślna systemowa</string>
|
||||
<string name="settings_theme_font_item_serif">Serif</string>
|
||||
<string name="settings_enabled_gestures_double_swipe">Akcje podwójnego przeciągnięcia</string>
|
||||
<string name="settings_tab_launcher">Launcher</string>
|
||||
<string name="settings_tab_meta">Meta</string>
|
||||
<string name="settings_gesture_description_swipe_smaller">Prawy górny -> środek lewo -> prawy dolnym</string>
|
||||
<string name="settings_gesture_swipe_smaller_reverse"><![CDATA[< (Odwrotnie)]]></string>
|
||||
<string name="settings_gesture_description_swipe_smaller_reverse">Prawy dolnym -> środek lewo -> prawy górny</string>
|
||||
<string name="settings_gesture_swipe_v_reverse">V (Odwrotnie)</string>
|
||||
<string name="settings_gesture_description_swipe_lambda">Lewy dolny -> środkowy górny -> prawy dolny</string>
|
||||
<string name="settings_gesture_swipe_lambda_reverse">Λ (Odwrotnie)</string>
|
||||
<string name="settings_gesture_vol_up">Przycisk podgłośnienia</string>
|
||||
<string name="settings_gesture_description_vol_up">Naciśnij przycisk podgłośnienia</string>
|
||||
<string name="settings_gesture_vol_down">Przycisk przyciszenia</string>
|
||||
<string name="settings_gesture_description_vol_down">Naciśnij przycisk przyciszenia</string>
|
||||
<string name="settings_gesture_description_swipe_lambda_reverse">Prawy górny -> środkowy górny -> lewy górny</string>
|
||||
<string name="settings_gesture_double_click">Dwuklik</string>
|
||||
<string name="settings_gesture_description_double_click">Naciśnij dwukrotnie w pustym miejscu</string>
|
||||
<string name="settings_gesture_long_click">Wydłużone kliknięcie</string>
|
||||
<string name="settings_gesture_date">Data</string>
|
||||
<string name="settings_gesture_description_date">Kliknij na date</string>
|
||||
<string name="settings_gesture_time">Zegar</string>
|
||||
<string name="settings_widgets_widgets">Zarządzaj widżetami</string>
|
||||
<string name="settings_widgets_custom_panels">Zarządzaj panelem widżetów</string>
|
||||
<string name="settings_apps_choose">Wybierz aplikacje</string>
|
||||
<string name="settings_apps_install">Zainstaluj aplikacje</string>
|
||||
<string name="settings_gesture_description_time">Kliknij na zegar</string>
|
||||
<string name="settings_apps_toast_store_not_found">Sklep nie został znaleziony</string>
|
||||
<string name="settings_theme_color_theme">Kolor motywu</string>
|
||||
<string name="settings_theme_color_theme_item_default">Domyślne</string>
|
||||
<string name="settings_theme_color_theme_item_dark">Ciemny</string>
|
||||
<string name="settings_theme_color_theme_item_light">Jasny</string>
|
||||
<string name="settings_theme_color_theme_item_dynamic">Dynamiczny</string>
|
||||
<string name="settings_theme_text_shadow">Cień tekstu</string>
|
||||
<string name="settings_theme_background">Tło (lista aplikacji i ustawienia)</string>
|
||||
<string name="settings_theme_background_item_transparent">Przeźroczysty</string>
|
||||
<string name="settings_theme_background_item_dim">Przygaszony</string>
|
||||
<string name="settings_theme_background_item_blur">Rozmazanie</string>
|
||||
<string name="settings_theme_background_item_solid">Jednolity</string>
|
||||
<string name="settings_theme_font">Czcionką</string>
|
||||
<string name="settings_theme_font_item_monospace">Monospace</string>
|
||||
<string name="settings_theme_font_item_sans_serif">Sans serif</string>
|
||||
<string name="settings_theme_font_item_serif_monospace">Serif monospace</string>
|
||||
<string name="settings_theme_monochrome_icons">Monochromatyczne ikony aplikacji</string>
|
||||
<string name="settings_launcher_section_date_time"><![CDATA[Date & time]]></string>
|
||||
<string name="settings_clock_color">Kolor</string>
|
||||
<string name="settings_clock_date_visible">Pokazuj date</string>
|
||||
<string name="settings_clock_show_seconds">Pokazuj sekundy</string>
|
||||
<string name="settings_theme_wallpaper">Wybierz tapetę</string>
|
||||
<string name="settings_launcher_section_display">Wyświetlanie</string>
|
||||
<string name="settings_display_screen_timeout_disabled">Zatrzymaj na ekranie</string>
|
||||
<string name="settings_display_hide_status_bar">Schowaj pasek statusów</string>
|
||||
<string name="settings_display_hide_navigation_bar">Schowaj pasek nawigacji</string>
|
||||
<string name="settings_display_rotate_screen">Obracają ekran</string>
|
||||
<string name="settings_launcher_section_functionality">Funkcjonalność</string>
|
||||
<string name="settings_enabled_gestures_double_swipe_summary">Przeciągnij dwoma palcami</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Przeciąganie na krawędziach</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_summary">Przeciągnij koło krawędź ekranu</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_edge_width">Rozmiary krawędź</string>
|
||||
<string name="settings_functionality_auto_launch">Automatycznie uruchamiaj wyszukiwanie</string>
|
||||
<string name="settings_functionality_search_web">Wyszukuje w sieci</string>
|
||||
<string name="settings_functionality_search_web_summary">Kliknij enter, wyszukując w liście aplikacji, by wyszukać w internecie.</string>
|
||||
<string name="settings_functionality_auto_keyboard">Pokazuje klawiaturę do wyszukiwania</string>
|
||||
<string name="settings_functionality_auto_close_keyboard">Zamknij klawiaturę podczas przewijania</string>
|
||||
<string name="settings_launcher_sensitivity">Czułość</string>
|
||||
<string name="settings_launcher_section_apps">Aplikacje</string>
|
||||
<string name="settings_apps_hidden">Ukryte aplikacje</string>
|
||||
<string name="settings_apps_hide_paused_apps">Ukryj zatrzymane aplikacje</string>
|
||||
<string name="settings_apps_hide_private_space_apps">Ukryj przestrzeń prywatną z listy aplikacji</string>
|
||||
<string name="settings_list_layout">Układ listy aplikacji</string>
|
||||
<string name="settings_list_reverse_layout">Odwróć listę aplikacji</string>
|
||||
<string name="settings_list_layout_item_default">Domyślny</string>
|
||||
<string name="settings_list_layout_item_text">Tekst</string>
|
||||
<string name="settings_list_layout_item_grid">Siatka</string>
|
||||
<string name="settings_meta_cant_select_launcher">Informacje aplikacji</string>
|
||||
<string name="settings_meta_show_tutorial">Zobacz samouczek µLauncher</string>
|
||||
<string name="settings_meta_reset">Zresetuj ustawienia</string>
|
||||
<string name="settings_meta_reset_confirm">Odrzucisz wszystkie swoje preferencje. Czy chcesz kontynuować?</string>
|
||||
<string name="settings_meta_view_code">Zobacz kod źródłowy</string>
|
||||
<string name="settings_meta_report_bug">Zgłoś błąd</string>
|
||||
<string name="dialog_report_bug_title">Zgłoś błąd</string>
|
||||
<string name="dialog_report_bug_button_clipboard">Skopiuj do schowka</string>
|
||||
<string name="dialog_report_bug_security_info">Proszę nie zgłaszaj luk w zabezpieczeniach publicznie na GitHubie, użyj natomiast podanego linku:</string>
|
||||
<string name="dialog_report_bug_create_report">Utwórz zgłoszenie</string>
|
||||
<string name="settings_meta_fork_contact">Skontaktuj się z deweloperem forku</string>
|
||||
<string name="settings_meta_join_chat">Dołącz do czatu μLauncher</string>
|
||||
<string name="settings_meta_donate">Wesprzyj</string>
|
||||
<string name="settings_meta_privacy">Polityka prywatność</string>
|
||||
<string name="settings_meta_contact">Skontaktuj się z deweloperem orginału</string>
|
||||
<string name="list_title_view">Lista aplikacji</string>
|
||||
<string name="list_title_favorite">Ulubione aplikacje</string>
|
||||
<string name="list_title_hidden">Ukryte aplikacje</string>
|
||||
<string name="list_title_private_space">Przestrzeń prywatna</string>
|
||||
<string name="list_title_pick">Wybierz aplikacje</string>
|
||||
<string name="list_tab_app">Aplikacje</string>
|
||||
<string name="list_tab_other">Inne</string>
|
||||
<string name="list_app_delete">Odinstaluj</string>
|
||||
<string name="list_app_info">Informacje aplikacji</string>
|
||||
<string name="list_app_favorite_remove">Usuń z ulubionych</string>
|
||||
<string name="list_app_hidden_add">Ukryj</string>
|
||||
<string name="list_app_hidden_remove">Pokaż</string>
|
||||
<string name="list_app_rename">Zmień nazwę</string>
|
||||
<string name="list_apps_search_hint">Wyszukaj</string>
|
||||
<string name="list_apps_search_hint_no_auto_launch">Wyszukaj (brak automatycznego uruchomienia)</string>
|
||||
<string name="list_other_settings">Ustawienia μLauncher</string>
|
||||
<string name="list_other_list_favorites">Ulubione aplikacje</string>
|
||||
<string name="list_other_list_private_space">Przestrzeń prywatna</string>
|
||||
<string name="list_other_toggle_private_space_lock">Przełącz zamek prywatnej przestrzeni</string>
|
||||
<string name="list_other_volume_up">Podgłośnij</string>
|
||||
<string name="list_other_volume_down">Przycisz</string>
|
||||
<string name="list_other_volume_adjust">Dostosuj głośność</string>
|
||||
<string name="list_other_track_next">Muzyka: Następne</string>
|
||||
<string name="list_other_track_play_pause">Muzyka: Wznów / Wstrzymaj</string>
|
||||
<string name="list_other_expand_notifications_panel">Rozwiń panel powiadomień</string>
|
||||
<string name="list_other_recent_apps">Ostatnio używane aplikacje</string>
|
||||
<string name="list_other_nop">Nie rób nic</string>
|
||||
<string name="list_other_lock_screen">Ekran blokady</string>
|
||||
<string name="list_other_torch">Przełącz latarkę</string>
|
||||
<string name="list_other_launch_other_launcher">Uruchomiono inny ekran główny</string>
|
||||
<string name="pin_shortcut_title">Dodaj skrót</string>
|
||||
<string name="pin_shortcut_button_bind">Przypisz do gestu</string>
|
||||
<string name="pin_shortcut_switch_visible">Pokaż w liście aplikacji</string>
|
||||
<string name="tutorial_title">Samouczek</string>
|
||||
<string name="tutorial_start_text">👋\n\nPoświeć kilka chwil, aby nauczyć się jak używać togo launchera!</string>
|
||||
<string name="tutorial_concept_title">Koncept</string>
|
||||
<string name="tutorial_concept_label_version">Wersja</string>
|
||||
<string name="tutorial_app_list_title">Wszystkie aplikacje</string>
|
||||
<string name="tutorial_setup_title">Konfiguracja</string>
|
||||
<string name="tutorial_finish_title">Gratulacje!</string>
|
||||
<string name="tutorial_finish_button">Start</string>
|
||||
<string name="settings">Ustawienia</string>
|
||||
<string name="ic_menu_alt">Więcej opcji</string>
|
||||
<string name="undo">Cofnij</string>
|
||||
<string name="toast_private_space_unlocked">Przestrzeń prywatna odblokowana</string>
|
||||
<string name="tooltip_lock_private_space">Zablokuj przestrzeń prywatną</string>
|
||||
<string name="tooltip_unlock_private_space">Odblokuj przestrzeń prywatną</string>
|
||||
<string name="accessibility_service_name">μLauncher</string>
|
||||
<string name="screen_lock_method_dialog_title">Wybierz metodę zablokowania</string>
|
||||
<string name="settings_actions_lock_method">Wybierz metodę blokowania ekranu</string>
|
||||
<string name="dialog_rename_title">Zmień nazwę %1$s</string>
|
||||
<string name="dialog_select_color_red">Czerwony</string>
|
||||
<string name="dialog_select_color_alpha">Przezroczystości</string>
|
||||
<string name="dialog_select_color_blue">Niebieski</string>
|
||||
<string name="dialog_select_color_green">Zielony</string>
|
||||
<string name="dialog_choose_color_title">Wybierz kolor</string>
|
||||
<string name="dialog_cancel">Anuluj</string>
|
||||
<string name="toast_activity_not_found_search_web">Nie znaleziono aplikacji do obsługi wyszukiwania.</string>
|
||||
<string name="settings_clock_time_visible">Pokazuj zegar</string>
|
||||
<string name="settings_clock_localized">Użyj lokalnego formatu daty</string>
|
||||
<string name="settings_gesture_description_long_click">Kliknij dłużej w pustym miejscu</string>
|
||||
<string name="settings_gesture_description_swipe_v">Lewy górny -> środkowy dolny -> prawy górny</string>
|
||||
<string name="settings_gesture_description_swipe_v_reverse">Prawy górny -> środkowy dolny -> lewy górny</string>
|
||||
<string name="settings_functionality_auto_launch_summary">Kliknij spacje, by tymczasowo wyłączyć tą funkcje.</string>
|
||||
<string name="list_other_expand_settings_panel">Szybkie ustawienia</string>
|
||||
<string name="toast_private_space_locked">Przestrzeń prywatna zablokowana</string>
|
||||
<string name="settings_general_choose_home_screen">Ustaw μLauncher jako ekran główny</string>
|
||||
<string name="dialog_select_color_color_hex">Kolor</string>
|
||||
<string name="list_app_favorite_add">Dodaj do ulubionych</string>
|
||||
<string name="tutorial_concept_text_2">Jest to darmowe oprogramowanie (na licencji MIT)!\nZachęcamy do odwiedzenia naszego repozytorium!</string>
|
||||
<string name="tutorial_concept_text">μLauncher jest projektowany z uwagą na minimalizm, efektywności i brak rozproszeń. \n\nNie zawiera reklam i nie zbiera twoich danych.</string>
|
||||
<string name="tutorial_usage_text">Twój ekran główny zawiera lokalną datę i czas. Żadnych rozproszeń.</string>
|
||||
<string name="tutorial_usage_text_2">Możesz uruchomić swoje najważniejsze aplikacje za pomocą gestów i użyciem przycisków.</string>
|
||||
<string name="tutorial_app_list_text">Możesz szybko wyszukiwać aplikacje poprzez listę aplikacji.\n\nPrzeciągnij do góry aby ją otworzyć, lub przypisz ją do innego gestu.</string>
|
||||
<string name="tutorial_app_list_text_2">Gdy tylko jedna aplikacja pasuje do twojego wyszukiwania, uruchomi się automatycznie.\nTa opcja może być wyłączona, przez wpisanie spacji przed wyszukaniem.</string>
|
||||
<string name="tutorial_setup_text">Wybraliśmy pare domyślnych aplikacji dla ciebie. Możesz zmienić je teraz jeśli chcesz:</string>
|
||||
<string name="tutorial_setup_text_2">Albo zmień je później.</string>
|
||||
<string name="alert_requires_android_m">Ta funkcja wymaga wersji 6 lub wyższej Androida.</string>
|
||||
<string name="alert_requires_android_v">Ta funkcja wymaga wersji 15 lub wyższej Androida.</string>
|
||||
<string name="snackbar_app_hidden">Aplikacja schowana. Możesz przywrócić jej widoczność z powrotem w ustawieniach.</string>
|
||||
<string name="alert_torch_access_exception">Error: Brak dostępu do latarki.</string>
|
||||
<string name="device_admin_description">Aktywuj akcje zablokowania ekranu</string>
|
||||
<string name="dialog_consent_accessibility_data_collection">Wyrażam zgodę by, μLauncher nie zbierał żadnych moich danych.</string>
|
||||
<string name="toast_activity_not_found_browser">Nie można otworzyć adresu URL: nie znaleziono przeglądarki.</string>
|
||||
<string name="select_widget_title">Wybierz widżet</string>
|
||||
<string name="widget_menu_remove">Usuń</string>
|
||||
<string name="widget_menu_configure">Skonfiguruj</string>
|
||||
<string name="widget_clock_label">Zegar</string>
|
||||
<string name="widget_menu_enable_interaction">Aktywuje interakcje</string>
|
||||
<string name="widget_menu_disable_interaction">Dezaktywuj interakcje</string>
|
||||
<string name="manage_widget_panels_delete">Usuń</string>
|
||||
<string name="widget_clock_description">Domyślny zegar μLauncher</string>
|
||||
<string name="manage_widget_panels_rename">Zmień nazwę</string>
|
||||
<string name="widget_panel_default_name">Panel widżetów #%1$d</string>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="one">Zawiera %1$d widżet.</item>
|
||||
<item quantity="few">Zawiera %1$d widżety.</item>
|
||||
<item quantity="many">Zawiera %1$d widżetów.</item>
|
||||
<item quantity="other">Zawiera %1$d widżetów.</item>
|
||||
</plurals>
|
||||
<string name="legal_info_title">Licencje Open Source</string>
|
||||
<string name="settings_meta_licenses">Licencje Open Source</string>
|
||||
<string name="dialog_ok">Okej</string>
|
||||
<string name="widget_panels_title">Panel widżetów</string>
|
||||
<string name="dialog_select_widget_panel_title">Wybierz panel widżetów</string>
|
||||
<string name="dialog_create_widget_panel_title">Stwórz nowy panel widżetów</string>
|
||||
<string name="list_other_open_widget_panel">Otwórz panel widżetów</string>
|
||||
<string name="settings_launcher_section_widgets">Widżety</string>
|
||||
<string name="alert_widget_panel_not_found">Ten panel widżetów już nie istnieje.</string>
|
||||
<string name="alert_no_torch_found">Nie wykryto aparatu z latarką.</string>
|
||||
<string name="toast_device_admin_not_enabled">μLauncher musi być administratorem urządzenia, aby zablokować ekran.</string>
|
||||
<string name="alert_cant_expand_status_bar_panel">Błąd: Nie można rozszerzyć paska stanu. Ta akcja wykorzystuje funkcjonalność, która nie jest częścią opublikowanego interfejsu API Androida. Niestety, wydaje się, że nie działa na Twoim urządzeniu.</string>
|
||||
<string name="device_admin_explanation">Jest to wymagane do działania blokady ekranu.</string>
|
||||
<string name="alert_recent_apps_failed">Błąd: Nie udało się wyświetlić ostatnich aplikacji. (Jeśli właśnie zaktualizowałeś aplikację, spróbuj wyłączyć i ponownie włączyć usługę dostępności w ustawieniach telefonu)</string>
|
||||
<string name="alert_enable_accessibility_failed">Błąd: Nie udało się włączyć usługi ułatwień dostępu.</string>
|
||||
<string name="toast_private_space_default_home_screen">μLauncher musi być domyślnym ekranem głównym, aby uzyskać dostęp do przestrzeni prywatnej.</string>
|
||||
<string name="toast_lock_screen_not_supported">Błąd: Blokowanie ekranu za pomocą funkcji ułatwień dostępu nie jest obsługiwane na tym urządzeniu. Zamiast tego użyj opcji administratora urządzenia.</string>
|
||||
<string name="screen_lock_method_use_accessibility">Skorzystaj z usługi dostępności</string>
|
||||
<string name="screen_lock_method_use_device_admin">Użyj opcji administratora urządzenia</string>
|
||||
<string name="dialog_consent_accessibility_privileges">Zdaję sobie sprawę, że nada to μLauncherowi rozległe uprawnienia.</string>
|
||||
<string name="dialog_consent_accessibility_other_options">Wiem, że istnieją inne opcje (użycie uprawnień administratora urządzenia lub przycisku zasilania).</string>
|
||||
<string name="alert_lock_screen_failed">Błąd: Nie udało się zablokować ekranu. (Jeśli właśnie zaktualizowałeś aplikację, spróbuj wyłączyć i ponownie włączyć usługę dostępności w ustawieniach telefonu)</string>
|
||||
<string name="toast_accessibility_service_not_enabled">Usługa dostępności μLauncher nie jest włączona. Proszę włączyć ją w ustawieniach</string>
|
||||
<string name="tutorial_finish_text">Wszystko gotowe!\n\nMam nadzieję, że będzie to dla ciebie bardzo wartościowe!\n\n- Finn (twórca Launchera) i Josia (wprowadziła pewne ulepszenia i utrzymuje fork μLauncher)</string>
|
||||
<string name="accessibility_service_description">Ustawienie μLauncher jako usługi ułatwień dostępu umożliwia zablokowanie ekranu i otwarcie menu ostatnich aplikacji. Należy pamiętać, że wymagane są nadmierne uprawnienia. Nigdy nie należy udzielać takich uprawnień bez powodu żadnej aplikacji. μLauncher będzie korzystał z usługi ułatwień dostępu wyłącznie w celu wykonania następujących czynności na żądanie użytkownika: * zablokuj ekran * otwórz ostatnio używane aplikacje μLauncher nigdy nie będzie korzystał z usługi ułatwień dostępu w celu zbierania danych. Możesz sprawdzić kod źródłowy, aby się upewnić. Należy pamiętać, że zablokowanie ekranu można również osiągnąć poprzez przyznanie aplikacji uprawnień administratora urządzenia. Jednak ta metoda nie działa w przypadku odblokowywania przy użyciu odcisku palca i skanu twarzy.</string>
|
||||
</resources>
|
|
@ -102,7 +102,7 @@
|
|||
<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_previous">Música: Anterior</string>
|
||||
<string name="list_other_nop">Não faça nada</string>
|
||||
<string name="list_other_nop">Não fazer nada</string>
|
||||
<!--
|
||||
-
|
||||
- Tutorial
|
||||
|
@ -319,4 +319,30 @@
|
|||
<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>
|
||||
<string name="settings_widgets_widgets">Gerenciar widgets</string>
|
||||
<string name="select_widget_title">Escolha widget</string>
|
||||
<string name="settings_widgets_custom_panels">Gerenciar painéis de widgets</string>
|
||||
<string name="widget_menu_configure">Configurar</string>
|
||||
<string name="widget_menu_enable_interaction">Ativar interação</string>
|
||||
<string name="widget_clock_label">Relógio</string>
|
||||
<string name="widget_clock_description">O relógio padrão do μLauncher</string>
|
||||
<string name="manage_widget_panels_delete">Apagar</string>
|
||||
<string name="manage_widget_panels_rename">Renomear</string>
|
||||
<string name="widget_panel_default_name">Painel do widget #%1$d</string>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="one">Contém %d widget.</item>
|
||||
<item quantity="many">Contém %d widgets.</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<string name="dialog_ok">Ok</string>
|
||||
<string name="widget_panels_title">Painéis de widget</string>
|
||||
<string name="dialog_create_widget_panel_title">Criar novo painel de widget</string>
|
||||
<string name="list_other_open_widget_panel">Abrir painel de widget</string>
|
||||
<string name="alert_widget_panel_not_found">Esse painel de widget não existe mais.</string>
|
||||
<string name="settings_launcher_section_widgets">Widgets</string>
|
||||
<string name="widget_menu_remove">Remover</string>
|
||||
<string name="widget_menu_disable_interaction">Desativar interação</string>
|
||||
<string name="dialog_select_widget_panel_title">Selecione um painel de widget</string>
|
||||
<string name="dialog_select_widget_panel_info_no_panels"><![CDATA[Nenhum painel de widget encontrado. Você pode criar painéis de widgets em Configurações > Launcher > Gerenciar painéis de widget.]]></string>
|
||||
<string name="settings_functionality_auto_close_keyboard">Esconder o teclado durante a rolagem</string>
|
||||
</resources>
|
||||
|
|
|
@ -260,7 +260,7 @@
|
|||
<string name="settings_gesture_swipe_v_reverse">V(反向)</string>
|
||||
<string name="settings_gesture_swipe_larger_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="pin_shortcut_button_bind">绑定到手势</string>
|
||||
<string name="list_other_track_play_pause">音乐:播放 / 暂停</string>
|
||||
|
@ -284,4 +284,53 @@
|
|||
<string name="alert_enable_accessibility_failed">错误:启用“无障碍”服务失败。</string>
|
||||
<string name="alert_recent_apps_failed">错误:无法展示最近应用屏幕。(如果您刚刚升级了本启动器,请尝试在手机设置中手动禁用再重新启用“无障碍”服务。)</string>
|
||||
<string name="list_other_launch_other_launcher">启动其他启动器</string>
|
||||
<string name="settings_functionality_auto_close_keyboard">滚动应用程序列表时自动隐藏键盘</string>
|
||||
<string name="settings_widgets_widgets">设置小部件</string>
|
||||
<string name="widget_menu_remove">删除</string>
|
||||
<string name="widget_menu_enable_interaction">启用交互功能</string>
|
||||
<string name="widget_menu_disable_interaction">关闭交互功能</string>
|
||||
<string name="widget_clock_label">时钟</string>
|
||||
<string name="manage_widget_panels_delete">删除</string>
|
||||
<string name="manage_widget_panels_rename">重命名</string>
|
||||
<string name="widget_panel_default_name">小部件面板 #%1$d</string>
|
||||
<string name="widget_panels_title">小部件面板</string>
|
||||
<string name="dialog_select_widget_panel_title">选择小部件面板</string>
|
||||
<string name="list_other_open_widget_panel">打开小部件面板</string>
|
||||
<string name="dialog_create_widget_panel_title">创建新面板</string>
|
||||
<string name="dialog_select_widget_panel_info_no_panels"><![CDATA[未发现小部件面板。您可以在“设置 > 启动器 > 设置小部件面板”中进行创建。]]></string>
|
||||
<string name="settings_launcher_section_widgets">桌面小部件</string>
|
||||
<string name="alert_widget_panel_not_found">该小部件面板不存在</string>
|
||||
<string name="widget_clock_description">μLauncher 默认时钟小部件</string>
|
||||
<string name="select_widget_title">选择小部件</string>
|
||||
<string name="settings_widgets_custom_panels">设置小部件面板</string>
|
||||
<string name="dialog_ok">确认</string>
|
||||
<plurals name="widget_panel_number_of_widgets">
|
||||
<item quantity="other">包含 %1$d 个小部件。</item>
|
||||
</plurals>
|
||||
<string name="notification_crash_title">μLauncher 崩溃了</string>
|
||||
<string name="notification_crash_explanation">抱歉!点击查看更多信息。</string>
|
||||
<string name="report_crash_button_copy">复制崩溃报告到剪贴板</string>
|
||||
<string name="report_crash_button_mail">通过 Email 发送报告</string>
|
||||
<string name="report_crash_title">μLauncher 崩溃了</string>
|
||||
<string name="report_crash_button_report">在 GitHub 上创建错误反馈</string>
|
||||
<string name="send_email">发送 Email</string>
|
||||
<string name="notification_channel_crash">崩溃和调试信息</string>
|
||||
<string name="crash_info"><![CDATA[
|
||||
发生了一些错误,非常抱歉!<br><br>
|
||||
出于保护隐私的考量,崩溃日志不会被自动采集。<br>
|
||||
但是,日志对应用调试非常有帮助,若您原意,请将所附日志文件通过 Email 发送给我们,
|
||||
或在 GitHub 上创建错误报告,非常感谢!<br><br>
|
||||
请注意,崩溃日志可能包含<strong>敏感信息</strong>,如,您尝试启动的应用名称。
|
||||
因此,请在发送报告前,先将此类信息<strong>去除</strong>。
|
||||
<h2>我现在应该怎么做?</h2>
|
||||
如果这个错误重复发生,您可以做如下尝试:
|
||||
<ul>
|
||||
<li>强行停止 μLauncher</li>
|
||||
<li>清空 μLauncher 的存储空间(<strong>您的设置将被重置!</strong>)</li>
|
||||
<li>安装旧版本(<a href=\"https://github.com/jrpie/Launcher/releases\">GitHub</a>, <a href=\"https://f-droid.org/en/packages/de.jrpie.android.launcher\">F-Droid</a>)</li>
|
||||
</ul>
|
||||
]]></string>
|
||||
<string name="content_description_add_widget">添加小部件</string>
|
||||
<string name="content_description_add_widget_panel">添加小部件面板</string>
|
||||
<string name="settings_meta_view_docs">文档</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
<dimen name="appbar_padding">16dp</dimen>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
<dimen name="appbar_padding_top">8dp</dimen>
|
||||
|
||||
<dimen name="app_icon_side">40dip</dimen>
|
||||
<dimen name="app_action_height">48dip</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
<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_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_hidden_key" translatable="false">apps.hidden</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_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_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>
|
||||
|
@ -158,7 +161,9 @@
|
|||
-
|
||||
-->
|
||||
<string name="settings_meta_link_github" translatable="false">https://github.com/jrpie/Launcher</string>
|
||||
<string name="settings_meta_link_docs" translatable="false">https://launcher.jrpie.de/</string>
|
||||
<string name="settings_meta_report_bug_link" translatable="false">https://github.com/jrpie/Launcher/issues/new?template=bug_report.yaml</string>
|
||||
<string name="settings_meta_report_bug_mail" translatable="false">android-launcher-crash@jrpie.de</string>
|
||||
<string name="settings_meta_report_vulnerability_link" translatable="false">https://github.com/jrpie/Launcher/security/policy</string>
|
||||
<string name="settings_meta_fork_contact_url" translatable="false">https://s.jrpie.de/contact</string>
|
||||
<string name="settings_meta_privacy_url" translatable="false">https://s.jrpie.de/android-legal</string>
|
||||
|
|
|
@ -98,6 +98,9 @@
|
|||
<string name="settings_gesture_time">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>
|
||||
|
||||
|
@ -156,9 +159,9 @@
|
|||
|
||||
<string name="settings_launcher_section_functionality">Functionality</string>
|
||||
|
||||
<string name="settings_enabled_gestures_double_swipe">Double swipe actions</string>
|
||||
<string name="settings_enabled_gestures_double_swipe">Double swipe gestures</string>
|
||||
<string name="settings_enabled_gestures_double_swipe_summary">Swipe with two fingers</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Edge swipe actions</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe">Edge swipe gestures</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_summary">Swipe at the edge of the screen</string>
|
||||
<string name="settings_enabled_gestures_edge_swipe_edge_width">Edge width</string>
|
||||
<string name="settings_functionality_auto_launch">Launch search results</string>
|
||||
|
@ -167,6 +170,7 @@
|
|||
<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_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>
|
||||
|
||||
|
@ -251,12 +255,12 @@
|
|||
<string name="list_other_track_next">Music: Next</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_expand_notifications_panel">Expand notifications panel</string>
|
||||
<string name="list_other_expand_notifications_panel">Expand Notifications Panel</string>
|
||||
<string name="list_other_recent_apps">Recent Apps</string>
|
||||
<string name="list_other_nop">Do nothing</string>
|
||||
<string name="list_other_nop">Do Nothing</string>
|
||||
<string name="list_other_lock_screen">Lock Screen</string>
|
||||
<string name="list_other_torch">Toggle Torch</string>
|
||||
<string name="list_other_launch_other_launcher">Launch other Home Screen</string>
|
||||
<string name="list_other_launch_other_launcher">Launch Other Home Screen</string>
|
||||
|
||||
<!-- Pin shortcuts -->
|
||||
<string name="pin_shortcut_title">Add Shortcut</string>
|
||||
|
@ -387,5 +391,69 @@
|
|||
<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_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 %1$d widget.</item>
|
||||
<item quantity="other">Contains %1$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>
|
||||
<string name="notification_crash_title">μLauncher crashed</string>
|
||||
<string name="notification_crash_explanation">Sorry! Click for more information.</string>
|
||||
<string name="crash_info"><![CDATA[
|
||||
Looks like something went wrong, sorry about that!<br><br>
|
||||
For privacy reasons, crash logs are not collected automatically.<br>
|
||||
However logs are very useful for debugging, so I would be very grateful if you could send me the attached log by mail
|
||||
or create a bug report on github.<br><br>
|
||||
Note that crash logs might contain <strong>sensitive information</strong>, e.g. the name of an app you tried to launch.
|
||||
Please <strong>redact</strong> such information before sending the report.
|
||||
<h2>What can I do now?</h2>
|
||||
If this bug appears again and again, you can try several things:
|
||||
<ul>
|
||||
<li>Force stop μLauncher</li>
|
||||
<li>Clear μLauncher\'s storage (<strong>Your settings will be lost!</strong>)</li>
|
||||
<li>Install an older version (<a href=\"https://github.com/jrpie/Launcher/releases\">GitHub</a>, <a href=\"https://f-droid.org/en/packages/de.jrpie.android.launcher\">F-Droid</a>)</li>
|
||||
</ul>
|
||||
]]>
|
||||
</string>
|
||||
<string name="report_crash_button_copy">Copy crash report to clipboard</string>
|
||||
<string name="report_crash_button_mail">Send report by mail</string>
|
||||
<string name="report_crash_button_report">Create bug report on GitHub</string>
|
||||
<string name="report_crash_title">μLauncher crashed</string>
|
||||
<string name="send_email">Send Email</string>
|
||||
<string name="notification_channel_crash">Crashes and Debug Information</string>
|
||||
<string name="settings_meta_view_docs">Documentation</string>
|
||||
<!--
|
||||
-
|
||||
- Content Descriptions
|
||||
-
|
||||
-->
|
||||
<string name="content_description_add_widget">Add widget</string>
|
||||
<string name="content_description_add_widget_panel">Add widget panel</string>
|
||||
<string name="content_description_close">Close</string>
|
||||
<string name="content_description_navigate_back">Navigate back</string>
|
||||
<string name="content_description_navigate_next">Navigate next</string>
|
||||
<string name="content_description_lock">Lock</string>
|
||||
<string name="content_description_settings_actions_row_button_remove">Remove binding</string>
|
||||
</resources>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
<item name="android:buttonStyle">@style/Widget.AppCompat.Button.Colored</item>
|
||||
<item name="colorButtonNormal">?colorAccent</item>
|
||||
<item name="cardBackgroundColor">@color/cardview_dark_background</item>
|
||||
|
||||
<!--<item name="android:popupMenuStyle">@style/PopupMenuCustom</item>-->
|
||||
|
||||
|
@ -32,6 +33,7 @@
|
|||
<item name="colorPrimaryDark">@color/darkTheme_background_color</item>
|
||||
<item name="colorAccent">@color/darkTheme_accent_color</item>
|
||||
<item name="android:colorBackground">@color/darkTheme_background_color</item>
|
||||
<item name="cardBackgroundColor">@color/cardview_dark_background</item>
|
||||
<item name="android:textColor">@color/darkTheme_text_color</item>
|
||||
</style>
|
||||
|
||||
|
@ -40,6 +42,7 @@
|
|||
<item name="colorPrimaryDark">@color/finnmglasTheme_background_color</item>
|
||||
<item name="colorAccent">@color/finnmglasTheme_accent_color</item>
|
||||
<item name="android:colorBackground">@color/finnmglasTheme_background_color</item>
|
||||
<item name="cardBackgroundColor">@color/cardview_dark_background</item>
|
||||
<item name="android:textColor">@color/finnmglasTheme_text_color</item>
|
||||
</style>
|
||||
|
||||
|
@ -48,6 +51,7 @@
|
|||
<item name="colorPrimaryDark">@color/lightTheme_background_color</item>
|
||||
<item name="colorAccent">@color/lightTheme_accent_color</item>
|
||||
<item name="android:colorBackground">@color/lightTheme_background_color</item>
|
||||
<item name="cardBackgroundColor">@color/cardview_light_background</item>
|
||||
<item name="android:textColor">@color/lightTheme_text_color</item>
|
||||
</style>
|
||||
|
||||
|
@ -57,6 +61,7 @@
|
|||
<item name="colorPrimaryDark">@color/material_dynamic_primary50</item>
|
||||
<item name="colorAccent">@color/material_dynamic_tertiary50</item>
|
||||
<item name="android:colorBackground">@color/material_dynamic_neutral10</item>
|
||||
<item name="cardBackgroundColor">@color/cardview_dark_background</item>
|
||||
<item name="android:textColor">@color/material_dynamic_neutral_variant90</item>
|
||||
</style>
|
||||
|
||||
|
@ -66,12 +71,12 @@
|
|||
<item name="android:shadowDy">0</item>
|
||||
<item name="android:shadowRadius">2</item>
|
||||
</style>
|
||||
|
||||
<style name="textShadowLight" parent="textShadow">
|
||||
<item name="android:shadowColor">#aaa</item>
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
<style name="backgroundWallpaper">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
|
@ -81,26 +86,30 @@
|
|||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="backgroundSolid">
|
||||
</style>
|
||||
<style name="backgroundSolid"></style>
|
||||
|
||||
|
||||
<style name="fontSystemDefault">
|
||||
<!--<item name="android:textSize">18sp</item>-->
|
||||
</style>
|
||||
|
||||
<style name="fontHack">
|
||||
<item name="android:fontFamily">@font/hack</item>
|
||||
<!--<item name="android:textSize">18sp</item>-->
|
||||
</style>
|
||||
|
||||
<style name="fontMonospace">
|
||||
<item name="android:fontFamily">monospace</item>
|
||||
</style>
|
||||
|
||||
<style name="fontSerifMonospace">
|
||||
<item name="android:fontFamily">serif-monospace</item>
|
||||
</style>
|
||||
|
||||
<style name="fontSansSerif">
|
||||
<item name="android:fontFamily">sans-serif</item>
|
||||
</style>
|
||||
|
||||
<style name="fontSerif" tools:keep="@style/fontSerif">
|
||||
<item name="android:fontFamily">serif</item>
|
||||
</style>
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceCategory
|
||||
app:allowDividerAbove="false" > <!-- general -->
|
||||
|
||||
<Preference
|
||||
android:key="@string/settings_general_choose_home_screen_key"
|
||||
android:title="@string/settings_general_choose_home_screen"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
app:allowDividerAbove="false"
|
||||
|
@ -104,6 +104,10 @@
|
|||
android:key="@string/settings_functionality_search_auto_open_keyboard_key"
|
||||
android:defaultValue="true"
|
||||
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
|
||||
android:key="@string/settings_enabled_gestures_double_swipe_key"
|
||||
android:summary="@string/settings_enabled_gestures_double_swipe_summary"
|
||||
|
@ -170,6 +174,16 @@
|
|||
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
|
||||
android:title="@string/settings_launcher_section_display"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
buildscript {
|
||||
ext.kotlin_version = '2.0.0'
|
||||
ext.android_plugin_version = '8.9.1'
|
||||
ext.android_plugin_version = '8.10.0'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
|
@ -10,7 +10,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.9.1'
|
||||
classpath 'com.android.tools.build:gradle:8.10.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "com.android.tools.build:gradle:$android_plugin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
|
|
0
docs/_index.md
Normal file
0
docs/_index.md
Normal file
75
docs/actions-and-gestures.md
Normal file
75
docs/actions-and-gestures.md
Normal file
|
@ -0,0 +1,75 @@
|
|||
+++
|
||||
weight = 10
|
||||
+++
|
||||
|
||||
# Actions and Gestures
|
||||
|
||||
µLauncher's central mechanism for accessing important functionality quickly
|
||||
is to bind actions (e.g., launching an app) to gestures (e.g., swiping up).
|
||||
These bindings can be configured in µLauncher Settings > ACTIONS.
|
||||
|
||||
|
||||
## Available Gestures
|
||||
|
||||
### Swipes
|
||||
|
||||
- Basic swipes: Swipe up, down, left, or right
|
||||
- Double swipes: Swipe up, down, left, or right with two fingers
|
||||
- Edge swipes:
|
||||
- Swipe up or down on the left or right edge
|
||||
- Swipe left or right on the top or bottom edge
|
||||
|
||||
The size of the edges is configurable in settings.
|
||||
For a swipe to be detected as an edge swipe, the finger must not leave the respective edge region while swiping.
|
||||
|
||||
### Taps
|
||||
|
||||
- Tap on date or time
|
||||
- Double tap
|
||||
- Long click
|
||||
|
||||
### Tap-then-Swipes
|
||||
|
||||
- Tap then swipe up, down, left, or right
|
||||
|
||||
To execute these gestures consistently, it is helpful to think of them as double taps,
|
||||
where the finger stays on the screen after the second tap and then does a swipe.
|
||||
The swipe must start very shortly after the tap ended.
|
||||
|
||||
### Complex Gestures
|
||||
|
||||
- Draw <, >, V, or Λ
|
||||
- Draw <, >, V, or Λ in reverse direction
|
||||
|
||||
### Hardware Buttons as Gestures
|
||||
|
||||
- Back button (or back gesture if gesture navigation is enabled)
|
||||
- Volume buttons
|
||||
|
||||
***
|
||||
|
||||
## Available Actions
|
||||
|
||||
To any of the available gestures, one of the following actions can be bound:
|
||||
|
||||
- Launch an app (or a pinned shortcut)
|
||||
- Open a widget panel.
|
||||
Widget panels can hold widgets that are not needed on the home screen itself.
|
||||
They can be created and managed in µLauncher Settings > Manage Widget Panels
|
||||
- Open a list of all, favorite, or private apps (hidden apps are excluded).
|
||||
Actions related to private space are only shown if private space is set up on the device.
|
||||
µLauncher's settings can be accessed from those lists.
|
||||
If private space is set up, an icon to (un)lock it is shown on the top right.
|
||||
- Open µLauncher's settings
|
||||
- Toggle private space lock
|
||||
- Lock the screen: This allows you to lock the screen.
|
||||
There are two mechanisms by which the screen can be locked: accessibility service and device admin.
|
||||
- Toggle the flashlight
|
||||
- Raise, lower, or adjust volume
|
||||
- Play or pause media playback
|
||||
- Skip to previous or next audio track
|
||||
- Open notifications panel: Might be useful if the top of your screen is broken.
|
||||
- Open quick settings panel: Why swipe down twice?
|
||||
- Open [recent apps](https://developer.android.com/guide/components/activities/recents): Requires accessibility service. It can be used as a workaround for an Android bug.
|
||||
- Launch another home screen: Allows using another installed home screen temporarily.
|
||||
- Do nothing: Simply prevents showing the message that no action is bound to this gesture.
|
452
docs/alternatives.md
Normal file
452
docs/alternatives.md
Normal file
|
@ -0,0 +1,452 @@
|
|||
+++
|
||||
weight = 100
|
||||
+++
|
||||
|
||||
# FOSS Launchers
|
||||
|
||||
This is a comparison of open-source home screens for Android.
|
||||
|
||||
**Inclusion criteria:** Apps in this list must be [open source](https://opensource.org/licenses) and maintained
|
||||
|
||||
<!-- New contributors, please reference https://www.markdownguide.org/basic-syntax/ -->
|
||||
|
||||
<!-- TEMPLATE
|
||||
|
||||
### <launcher name>
|
||||
|
||||
**License:** `<license type>`
|
||||
[Website](<launcher website url>) | [Repository](<github or other repo url>) | [F-Droid](<fdroid url>)
|
||||
|
||||
<notes can go here>
|
||||
|
||||
**Main mode of interaction:** `<Search | Gestures | App grid>`
|
||||
|
||||
#### Features:
|
||||
:white_check_mark: | :x: | :grey_question: Search: <list what you can search: e.g., apps, contacts, call history, ...>
|
||||
:white_check_mark: | :x: | :grey_question: Search history
|
||||
:white_check_mark: | :x: | :grey_question: Customizable gestures: <list usable gestures: e.g., up, down, tap+up, ...>
|
||||
:white_check_mark: | :x: | :grey_question: Folders
|
||||
:white_check_mark: | :x: | :grey_question: Tags
|
||||
:white_check_mark: | :x: | :grey_question: Rename apps
|
||||
:white_check_mark: | :x: | :grey_question: Widgets
|
||||
:white_check_mark: | :x: | :grey_question: Private space
|
||||
:white_check_mark: | :x: | :grey_question: Work profile
|
||||
:white_check_mark: | :x: | :grey_question: Pinned shortcuts
|
||||
:white_check_mark: | :x: | :grey_question: Icon packs
|
||||
:white_check_mark: | :x: | :grey_question: Material You
|
||||
|
||||
---
|
||||
|
||||
-->
|
||||
|
||||
## Grid-Based Launchers
|
||||
|
||||
### Discreet Launcher
|
||||
|
||||
**License:** `GPL-3.0`
|
||||
[Website](https://vincent-falzon.com/) | [Repository](https://github.com/falzonv/discreet-launcher) | [F-Droid](https://f-droid.org/en/packages/com.vincent_falzon.discreetlauncher/)
|
||||
|
||||
**Main mode of interaction:** `app grid`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps`
|
||||
:x: Search history
|
||||
:x: Customizable gestures
|
||||
:white_check_mark:Folders
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:x: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:white_check_mark: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
### Fossify
|
||||
|
||||
**License:** `GPL-3.0`
|
||||
[Website](https://www.fossify.org/) | [Repository](https://github.com/FossifyOrg/Launcher) | [F-Droid](https://f-droid.org/en/packages/org.fossify.home/)
|
||||
|
||||
**Main mode of interaction:** `app grid`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps`
|
||||
:x: Search history
|
||||
:x: Customizable gestures
|
||||
:white_check_mark: Folders
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:white_check_mark: Widgets
|
||||
:grey_question: Private space
|
||||
:x: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:x: Icon packs
|
||||
:white_check_mark: Material You
|
||||
|
||||
---
|
||||
|
||||
### Lawnchair
|
||||
|
||||
**License:** `Apache License 2.0`
|
||||
[Website](https://lawnchair.app/) | [Repository](https://github.com/LawnchairLauncher/lawnchair)
|
||||
|
||||
Seems to be a regular (grid of apps) launcher.
|
||||
|
||||
**Main mode of interaction:** App grid
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `Apps & Shortcuts` `Web suggestions` `People` `Files` `Android Settings` `Calculator`
|
||||
:white_check_mark: Search history
|
||||
:white_check_mark: Customizable gestures: `double tap` `swipe up` `swipe down` `home button` `back button`
|
||||
:white_check_mark: Folders
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:white_check_mark: Widgets
|
||||
:grey_question: Private space
|
||||
:grey_question: Work profile
|
||||
:x: Pinned shortcuts
|
||||
:white_check_mark: Icon packs
|
||||
:white_check_mark: Material You
|
||||
|
||||
---
|
||||
|
||||
### Rootless Pixel Launcher
|
||||
|
||||
> **Abandoned**
|
||||
|
||||
**License:** `Apache License 2.0`
|
||||
[Repository](https://github.com/amirzaidi/Launcher3)
|
||||
|
||||
**Main mode of interaction:** `App grid`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `Apps`
|
||||
:x: Search history
|
||||
:x: Customizable gestures
|
||||
:x: Folders
|
||||
:x: Tags
|
||||
:x: Rename apps
|
||||
:warning: Widgets `buggy/broken`
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:white_check_mark: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
## Search-Based
|
||||
|
||||
### Aster Launcher
|
||||
|
||||
> **Abandoned**
|
||||
>
|
||||
**License:** `GPL-3.0`
|
||||
[Repository](https://github.com/neophtex/AsterLauncher) | [F-Droid](https://f-droid.org/en/packages/com.series.aster.launcher/)
|
||||
|
||||
**Main mode of interaction:** `search`
|
||||
|
||||
#### Features:
|
||||
|
||||
:warning: Search: `apps` (apps list is buggy/broken) `web`
|
||||
:x: Search history
|
||||
:x: Customizable gestures
|
||||
:x: Folders
|
||||
:x: Tags
|
||||
:x: Rename apps
|
||||
:x: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:x: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
### KISS Launcher
|
||||
|
||||
**License:** `GPL-3.0`
|
||||
[Website](https://kisslauncher.com/) | [Repository](https://github.com/Neamar/KISS) | [F-Droid](https://f-droid.org/packages/fr.neamar.kiss/)
|
||||
|
||||
**Main mode of interaction:** `Search` `Some gestures available`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `Apps` `Contacts` `Call history`
|
||||
:white_check_mark: Search history
|
||||
:white_check_mark: Customizable gestures: `swipe left` `swipe right` `swipe up` `swipe down` `long press` `double tap`
|
||||
:x: Folders
|
||||
:white_check_mark: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:white_check_mark: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:white_check_mark: Icon packs
|
||||
:grey_question: Material You
|
||||
|
||||
---
|
||||
|
||||
### Lunar Launcher
|
||||
**License:** `GPL-3.0`
|
||||
[Repository](https://github.com/iamrasel/lunar-launcher) | [F-Droid](https://f-droid.org/en/packages/rasel.lunar.launcher/)
|
||||
|
||||
Even natively supports RSS feeds to the homescreen?
|
||||
|
||||
**Main mode of interaction:** `alphabet scroller`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `swipe up` `swipe down` `swipe left` `swipe right` `tap and hold battery indicator/clock` `tap and hold lower part of screen` `double tap` `tap and hold favorite item`
|
||||
:x: Search history
|
||||
:x: Customizable gestures
|
||||
:x: Folders
|
||||
:x: Tags
|
||||
:x: Rename apps
|
||||
:x: Widgets
|
||||
:grey_question: Private space
|
||||
:x: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:x: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
### OLauncher
|
||||
|
||||
**License:** `GPL-3.0`
|
||||
[Repository](https://github.com/tanujnotes/Olauncher) | [F-Droid](https://f-droid.org/en/packages/app.olauncher/)
|
||||
|
||||
Extremely minimal launcher with lots of forks.
|
||||
|
||||
**Main mode of interaction:** `Search`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps`
|
||||
:x: Search history.
|
||||
:white_check_mark: Customizable gestures: `swipe left` `swipe right` `double tap`
|
||||
:x: Folders
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:x: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:grey_question: Pinned shortcuts
|
||||
:x: Icon packs
|
||||
:grey_question: Material You
|
||||
|
||||
#### Forks:
|
||||
|
||||
* [Olauncher Clutter Free](https://f-droid.org/en/packages/app.olaunchercf/)
|
||||
* [mLauncher](https://f-droid.org/en/packages/app.mlauncher/)
|
||||
* [CLauncher](https://f-droid.org/en/packages/app.clauncher/) (even more minimalistic, search without feedback)
|
||||
* [CCLauncher](https://f-droid.org/en/packages/app.cclauncher/) (rewrite using compose)
|
||||
|
||||
---
|
||||
|
||||
### TinyBit Launcher
|
||||
|
||||
**License:** `GPL-3.0`
|
||||
[Repository](https://github.com/TBog/TBLauncher) | [F-Droid](https://f-droid.org/en/packages/rocks.tbog.tblauncher/)
|
||||
|
||||
**Main mode of interaction:** `search` `some gestures`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps` `contacts` `web` `maps` `playstore` `youtube`
|
||||
:white_check_mark: Search history
|
||||
:white_check_mark: Customizable gestures: `tap` `double tap` `swipe up` `swipe left` `swipe right` `swipe down on left` `swipe down on right`
|
||||
:x: Folders
|
||||
:white_check_mark: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:white_check_mark: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:white_check_mark: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
### YAM Launcher
|
||||
|
||||
**License:** `MIT`
|
||||
[Repository](https://codeberg.org/ottoptj/yamlauncher) | [F-Droid](https://f-droid.org/en/packages/eu.ottop.yamlauncher/)
|
||||
|
||||
Similar to OLauncher?
|
||||
|
||||
**Main mode of interaction:** `search` `home screen text buttons`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps` `contacts (optional)`
|
||||
:x: Search history
|
||||
:white_check_mark: Customizable gestures: `swipe left` `swipe right`
|
||||
:x: Folders
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:x: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:x: Icon packs
|
||||
:white_check_mark: Material You
|
||||
|
||||
---
|
||||
|
||||
## Directory-Based
|
||||
|
||||
### folder launcher
|
||||
|
||||
**License:** `MIT`
|
||||
[Repository](https://github.com/Robby-Blue/SimpleFolderLauncher) | [F-Droid](https://f-droid.org/en/packages/me.robbyblue.mylauncher/)
|
||||
|
||||
**Main mode of interaction:** `directory navigation`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps`
|
||||
:x: Search history
|
||||
:x: Customizable gestures
|
||||
:white_check_mark: Folders
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:white_check_mark: Widgets
|
||||
:grey_question: Private space
|
||||
:x: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:x: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
### Ion Launcher
|
||||
|
||||
**License:** `GPL-3.0`
|
||||
[Repository](https://codeberg.org/zagura/ion-launcher) | [F-Droid](https://f-droid.org/en/packages/one.zagura.IonLauncher/)
|
||||
|
||||
**Main mode of interaction:** `App grid` `Search`
|
||||
|
||||
#### Features:
|
||||
|
||||
:warning: Search: `apps` `contacts: buggy/broken`
|
||||
:white_check_mark: Search history: `shows recently launched apps`
|
||||
:x: Customizable gestures
|
||||
:warning: Folders `prebuilt` `not customizable`
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:x: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:white_check_mark: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
## Gesture-Based
|
||||
|
||||
### Pie Launcher
|
||||
|
||||
**License:** `MIT`
|
||||
[Repository](https://github.com/markusfisch/PieLauncher)
|
||||
|
||||
**Main mode of interaction:** `Selection wheel`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps`
|
||||
:x: Search history
|
||||
:x: Customizable gestures
|
||||
:x: Folders
|
||||
:x: Tags
|
||||
:x: Rename apps
|
||||
:x: Widgets
|
||||
:grey_question: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:x: Icon packs
|
||||
:x: Material You
|
||||
|
||||
---
|
||||
|
||||
### µLauncher
|
||||
|
||||
**License:** `MIT`
|
||||
[Repository](https://github.com/jrpie/launcher) | [F-Droid](https://f-droid.org/en/packages/de.jrpie.android.launcher/)
|
||||
|
||||
**Main mode of interaction:** `Gestures` `Search`
|
||||
|
||||
#### Features:
|
||||
|
||||
:white_check_mark: Search: `apps`
|
||||
:x: Search history
|
||||
:white_check_mark: Customizable gestures: `35 avilable` [read the docs](https://github.com/jrpie/launcher/blob/master/docs/actions-and-gestures.md)
|
||||
:x: Folders
|
||||
:x: Tags
|
||||
:white_check_mark: Rename apps
|
||||
:white_check_mark: Widgets
|
||||
:white_check_mark: Private space
|
||||
:white_check_mark: Work profile
|
||||
:white_check_mark: Pinned shortcuts
|
||||
:x:Icon packs
|
||||
:white_check_mark: Material You
|
||||
|
||||
---
|
||||
|
||||
### Tabular Summary
|
||||
|
||||
#### Legend:
|
||||
|
||||
:white_check_mark: = Supported
|
||||
:x: = Unsupported
|
||||
:warning: = Buggy/Broken; check this launcher's notes above
|
||||
|
||||
| Launcher | Search | Search history | Customizable gestures | Folders | Tags | Rename apps | Widgets | Private space | Work profile | Pinned shortcuts | Icon packs | Material You |
|
||||
|------------------------------------------------------|--------------------|--------------------|-----------------------|--------------------|--------------------|--------------------|--------------------|--------------------|--------------------|--------------------|--------------------|--------------------|
|
||||
| [µLauncher](#µLauncher) | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
|
||||
| [Fossify](#Fossify) | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :grey_question: | :x: | :white_check_mark: | :x: | :white_check_mark: |
|
||||
| [Lawnchair](#Lawnchair) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :grey_question: | :grey_question: | :x: | :white_check_mark: | :white_check_mark: |
|
||||
| [Rootless Pixel Launcher](#Rootless-Pixel-Launcher) | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :warning: | :grey_question: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
|
||||
| [KISS Launcher](#KISS-Launcher) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :grey_question: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :grey_question: |
|
||||
| [Lunar Launcher](#Lunar-Launcher) | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :grey_question: | :x: | :white_check_mark: | :x: | :x: |
|
||||
| [OLauncher](#OLauncher) | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :grey_question: | :white_check_mark: | :grey_question: | :x: | :grey_question: |
|
||||
| [TinyBit Launcher](#TinyBit-Launcher) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :grey_question: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
|
||||
| [YAM Launcher](#YAM-Launcher) | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :grey_question: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: |
|
||||
| [Ion Launcher](#Ion-Launcher) | :warning: | :white_check_mark: | :x: | :warning: | :x: | :white_check_mark: | :x: | :grey_question: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
|
||||
| [Pie Launcher](#Pie-Launcher) | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :grey_question: | :white_check_mark: | :white_check_mark: | :x: | :x: |
|
||||
| [folder launcher](#folder-launcher) | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :grey_question: | :x: | :white_check_mark: | :x: | :x: |
|
||||
| [Discreet Launcher](#Discreet-Launcher) | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :grey_question: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
|
||||
| [Aster Launcher](#Aster-Launcher) | :warning: | :x: | :x: | :x: | :x: | :x: | :x: | :grey_question: | :white_check_mark: | :white_check_mark: | :x: | :x: |
|
||||
|
||||
<!-- Automating checkboxes for the table
|
||||
|
||||
You can use this python script, copy the contents of the Features section for the launcher, and paste it in the fixit() function. Note, since you're pasting in multiple lines, you will need to start and end your paste with triple-quotes.
|
||||
|
||||
import re
|
||||
def fix(features):
|
||||
# Use: fixed("""<paste here>""")
|
||||
fixed = ' | '.join(re.findall('(:[\w\_]*:)', features))
|
||||
return f"| {fixed} |"
|
||||
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
## Not Tested
|
||||
Feel free to test these and add
|
||||
https://f-droid.org/en/packages/app.easy.launcher/
|
||||
https://f-droid.org/en/packages/de.nodomain.tobihille.seniorlauncher/
|
||||
https://f-droid.org/en/packages/com.mrmannwood.hexlauncher/
|
||||
https://f-droid.org/en/packages/com.simplemobiletools.applauncher/
|
||||
https://f-droid.org/en/packages/peterfajdiga.fastdraw/
|
||||
https://f-droid.org/en/packages/de.mm20.launcher2.release/
|
||||
|
||||
[Even more launchers](https://docs.arcticons.com/faq/supported-launchers) (most of them don't seem to be FOSS)
|
52
docs/app-drawer.md
Normal file
52
docs/app-drawer.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
+++
|
||||
weight = 10
|
||||
+++
|
||||
|
||||
# App Drawer
|
||||
|
||||
Apps that are not needed all the time are shown in the app drawer.
|
||||
There are several such drawers, but the basic concept is the same.
|
||||
Besides regular apps, app drawers also show [pinned shortcuts](https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts)[^1].
|
||||
μLauncher treats apps and shortcuts in the same way.
|
||||
|
||||
The idea of the app drawer is to search for apps using the keyboard.
|
||||
By default[^2], an app is launched automatically once it is the only app matching the query.
|
||||
This can be prevented by typing a space.
|
||||
Usually, only two or three characters are needed, which is much faster than scrolling to find an app.
|
||||
|
||||
[^1]: A pinned shortcut is created, for example, when pinning a website to the home screen.
|
||||
[^2]: There are [several settings](/docs/settings/#functionality) available to modify the behavior.
|
||||
|
||||
When long-pressing an app, additional options are shown:
|
||||
* Rename the app
|
||||
* Add to / remove from Favorites: Adds the app to the [Favorite Apps](#favorite-apps) list or removes it from there.
|
||||
* Hide / Show: This hides the app from all drawers (except from [Hidden Apps](#hidden-apps)) or makes it visible again if it was hidden.
|
||||
* App Info: Opens the system settings page for the app.
|
||||
* Uninstall: Tries to uninstall the app or remove the shortcut.
|
||||
|
||||
## All Apps
|
||||
|
||||
This lists all apps except hidden apps.
|
||||
By default, it is bound to `Swipe up`.
|
||||
|
||||
## Favorite Apps
|
||||
|
||||
Only shows favorite apps.
|
||||
Pressing the star icon on the bottom right of any app drawer toggles whether only favorite apps should be shown.
|
||||
Additionally, the `Favorite Apps` action can be used to launch this drawer directly.
|
||||
By default, it is bound to `Swipe up (left edge)`.
|
||||
|
||||
## Private Space
|
||||
|
||||
When [private space](/docs/profiles/#private-space) is available, this drawer
|
||||
shows only apps from the private space.
|
||||
It can be opened using the `Private Space` action.
|
||||
If the private space is locked, instead of showing the list, the unlock dialog is shown.
|
||||
|
||||
By default, apps from the private space are shown in All Apps as well; however, this is [configurable](/docs/settings/#hide-private-space-from-app-list).
|
||||
|
||||
## Hidden Apps
|
||||
|
||||
This list shows hidden apps.
|
||||
It is only accessible through the settings.
|
||||
The feature is intended to be used only for apps that are not needed at all but [can not be uninstalled](https://en.wikipedia.org/wiki/Software_bloat#Bloatware).
|
|
@ -1,21 +1,27 @@
|
|||
# Building µLauncher
|
||||
+++
|
||||
weight = 50
|
||||
+++
|
||||
|
||||
|
||||
# Building from Source
|
||||
|
||||
## Using the command line
|
||||
|
||||
Install JDK 17 and the Android Sdk.
|
||||
Install JDK 17 and the Android SDK.
|
||||
Make sure that `JAVA_HOME` and `ANDROID_HOME` are set correctly.
|
||||
|
||||
```
|
||||
```bash
|
||||
git clone https://github.com/jrpie/Launcher
|
||||
cd Launcher
|
||||
|
||||
./gradlew assembleDefaultRelease
|
||||
```
|
||||
|
||||
This will create an apk file at `app/build/outputs/apk/default/release/app-default-release-unsigned.apk`.
|
||||
This will create an APK file at `app/build/outputs/apk/default/release/app-default-release-unsigned.apk`.
|
||||
|
||||
Note that you need to sign it:
|
||||
```
|
||||
|
||||
```bash
|
||||
apksigner sign --ks "$YOUR_KEYSTORE" \
|
||||
--ks-key-alias "$YOUR_ALIAS" \
|
||||
--ks-pass="pass:$YOUR_PASSWORD" \
|
||||
|
@ -28,13 +34,21 @@ apksigner sign --ks "$YOUR_KEYSTORE" \
|
|||
app-default-release-unsigned.apk
|
||||
```
|
||||
|
||||
|
||||
See [this guide](https://developer.android.com/build/building-cmdline)
|
||||
for further instructions.
|
||||
|
||||
|
||||
## Using Android Studio
|
||||
|
||||
Install [Android Studio](https://developer.android.com/studio), import this project and build it.
|
||||
|
||||
See [this guide](https://developer.android.com/studio/run)
|
||||
for further instructions.
|
||||
|
||||
## CI Pipeline
|
||||
|
||||
The [CI pipeline](https://github.com/jrpie/Launcher/actions) automatically creates debug builds.
|
||||
|
||||
{{% hint warning %}}
|
||||
Note: These builds are not signed.
|
||||
They are built in debug mode and are only suitable for testing.
|
||||
{{% /hint %}}
|
||||
|
|
|
@ -1,50 +1,59 @@
|
|||
# Notable changes compared to [Finn's Launcher][original-repo]:
|
||||
+++
|
||||
title = 'Differences to the original Launcher'
|
||||
+++
|
||||
|
||||
µLauncher is a fork of [finnmglas's app Launcher][original-repo].
|
||||
# Notable changes compared to Finn's Launcher
|
||||
|
||||
µLauncher is a fork of [finnmglas's app Launcher](https://github.com/finnmglas/Launcher).
|
||||
Here is an incomplete list of changes:
|
||||
<!--The last commit of the original project is [340ee731](https://github.com/jrpie/launcher/commit/340ee7315293b028c060638e058516435bca296a)
|
||||
The first commit of µLauncher is [cc2e7710](https://github.com/jrpie/launcher/commit/cc2e7710c824549c367d97a81a1646d27c6c8993),
|
||||
which at the time was still intended as a patch for launcher.
|
||||
which at the time was still intended as a patch for the launcher.
|
||||
The decision to create a hard fork was made two years later.-->
|
||||
|
||||
|
||||
- Additional gestures:
|
||||
- Back
|
||||
- V,Λ,<,>
|
||||
- Edge gestures: There is a setting to allow distinguishing swiping at the edges of the screen from swiping in the center.
|
||||
- Back
|
||||
- V, Λ, <, >
|
||||
- Edge gestures: There is a setting to allow distinguishing swiping at the edges of the screen from swiping in the center.
|
||||
|
||||
- Compatible with [work profile](https://www.android.com/enterprise/work-profile/), so apps like [Shelter](https://gitea.angry.im/PeterCxy/Shelter) can be used.
|
||||
- Compatible with [private space](https://source.android.com/docs/security/features/private-space)
|
||||
- Support for [app widgets](https://developer.android.com/develop/ui/views/appwidgets/overview)
|
||||
- Support for [pinned shortcuts](https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts)
|
||||
- Option to rename apps
|
||||
- Option to hide apps
|
||||
- Favorite apps
|
||||
- New actions:
|
||||
- Toggle Torch
|
||||
- Lock screen
|
||||
- Open a widget panel
|
||||
- The home button now works as expected.
|
||||
- Improved gesture detection.
|
||||
|
||||
### Visual
|
||||
## Visual
|
||||
|
||||
- This app uses the system wallpaper instead of a custom solution.
|
||||
- The font has been changed to [Hack][hack-font], other fonts can be selected.
|
||||
- Font Awesome Icons were replaced by Material icons.
|
||||
- The gear button on the home screen was removed. A smaller button is show at the top right when necessary.
|
||||
- The gear button on the home screen was removed. A smaller button is shown at the top right when necessary.
|
||||
|
||||
## Search
|
||||
|
||||
### Search
|
||||
- The search algorithm was modified to prefer matches at the beginning of the app name, i.e. when searching for `"te"`, `"termux"` is sorted before `"notes"`.
|
||||
- The search algorithm was modified to prefer matches at the beginning of the app name, i.e., when searching for `"te"`, `"termux"` is sorted before `"notes"`.
|
||||
- The search bar was moved to the bottom of the screen.
|
||||
|
||||
### Technical
|
||||
- Improved gesture detection.
|
||||
- Different apps set as default.
|
||||
- Package name was changed to `de.jrpie.android.launcher` to avoid clashing with the original app.
|
||||
- Dropped support for API < 21 (i.e. pre Lollypop)
|
||||
- Fixed some bugs
|
||||
- Some refactoring
|
||||
## Technical
|
||||
|
||||
- Improved gesture detection.
|
||||
- Different apps are set as the defaults.
|
||||
- Package name was changed to `de.jrpie.android.launcher` to avoid clashing with the original app.
|
||||
- Dropped support for API < 21 (i.e., pre Lollypop).
|
||||
- Fixed some bugs.
|
||||
- Some refactoring.
|
||||
|
||||
The complete list of changes can be viewed [here](https://github.com/jrpie/launcher/compare/340ee731...master).
|
||||
|
||||
---
|
||||
[original-repo]: https://github.com/finnmglas/Launcher
|
||||
[hack-font]: https://sourcefoundry.org/hack/
|
||||
|
||||
[original-repo]: https://github.com/finnmglas/Launcher
|
||||
[hack-font]: https://sourcefoundry.org/hack/
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue