diff --git a/docs/build.md b/BUILD.md
similarity index 100%
rename from docs/build.md
rename to BUILD.md
diff --git a/README.md b/README.md
index 016b362..b29b44d 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,12 @@
µLauncher is an Android home screen that lets you launch apps using swipe gestures and button presses.
It is *minimal, efficient and free of distraction*.
+Your home screen only displays the date, time and a wallpaper.
+Pressing back or swiping up (this can be configured) opens a list
+of all installed apps, which can be searched efficiently.
+
+This is a fork of [finnmglas's app Launcher][original-repo].
+
@@ -45,45 +51,6 @@ You can also [get it on Google Play](https://play.google.com/store/apps/details?
height="400">
-µLauncher is a fork of [finnmglas's app Launcher][original-repo].
-An incomplete list of changes can be found [here](docs/launcher.md).
-
-## Features
-
-µLauncher only displays the date, time and a wallpaper.
-Pressing back or swiping up (this can be configured) opens a list
-of all installed apps, which can be searched efficiently.
-
-The following gestures are available:
- - volume up / down,
- - swipe up / down / left / right,
- - swipe with two fingers,
- - swipe on the left / right resp. top / bottom edge,
- - draw < / > / V / Λ
- - click on date / time,
- - double click,
- - long click,
- - back button.
-
-To every gesture you can bind one of the following actions:
- - launch an app,
- - open a list of all / favorite / private apps,
- - open µLauncher settings,
- - toggle private space lock,
- - lock the screen,
- - toggle the torch,
- - volume up / down,
- - go to previous / next audio track.
-
-
-
-µLauncher is compatible with [work profile](https://www.android.com/enterprise/work-profile/),
-so apps like [Shelter](https://gitea.angry.im/PeterCxy/Shelter) can be used.
-
-By default the font is set to [Hack][hack-font], but other fonts can be selected.
-
-
-
## Contributing
There are several ways to contribute to this app:
@@ -96,10 +63,34 @@ There are several ways to contribute to this app:
- Open a new pull request.
-See [build.md](docs/build.md) for instructions how to build this project.
+See [BUILD.md](BUILD.md) for instructions how to build this project.
The [CI pipeline](https://github.com/jrpie/Launcher/actions) automatically creates debug builds.
Note that those are not signed.
+## Notable changes compared to [Finn's Launcher][original-repo]:
+
+* 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.
+* The home button now works as expected.
+
+### Visual
+* This app uses the system wallpaper instead of a custom solution.
+* The font has been changed to [Hack][hack-font].
+* Font Awesome Icons were replaced by Material icons.
+* The gear button on the home screen was removed. Instead pressing back opens the list of applications and the app settings are accessible from there.
+
+
+### Search
+* The search algorithm was modified to prefer matches at the beginning of the app name, i.e. when searching for `"te"`, `"termux"` is sorted before `"notes"`.
+* The search bar was moved to the bottom of the screen.
+
+### Technical
+* Small improvements to the 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)
+* Some refactoring
+---
---
[hack-font]: https://sourcefoundry.org/hack/
[original-repo]: https://github.com/finnmglas/Launcher
diff --git a/app/src/main/java/de/jrpie/android/launcher/actions/Gesture.kt b/app/src/main/java/de/jrpie/android/launcher/actions/Gesture.kt
index a4f25b4..34e053e 100644
--- a/app/src/main/java/de/jrpie/android/launcher/actions/Gesture.kt
+++ b/app/src/main/java/de/jrpie/android/launcher/actions/Gesture.kt
@@ -1,7 +1,6 @@
package de.jrpie.android.launcher.actions
import android.content.Context
-import android.util.Log
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.preferences.LauncherPreferences
@@ -170,54 +169,6 @@ enum class Gesture(
R.array.default_double_right,
R.anim.left_right
),
- SWIPE_LARGER(
- "action.larger",
- R.string.settings_gesture_swipe_larger,
- R.string.settings_gesture_description_swipe_larger,
- R.array.no_default
- ),
- SWIPE_LARGER_REVERSE(
- "action.larger_reverse",
- R.string.settings_gesture_swipe_larger_reverse,
- R.string.settings_gesture_description_swipe_larger_reverse,
- R.array.no_default
- ),
- SWIPE_SMALLER(
- "action.smaller",
- R.string.settings_gesture_swipe_smaller,
- R.string.settings_gesture_description_swipe_smaller,
- R.array.no_default
- ),
- SWIPE_SMALLER_REVERSE(
- "action.smaller_reverse",
- R.string.settings_gesture_swipe_smaller_reverse,
- R.string.settings_gesture_description_swipe_smaller_reverse,
- R.array.no_default
- ),
- SWIPE_LAMBDA(
- "action.lambda",
- R.string.settings_gesture_swipe_lambda,
- R.string.settings_gesture_description_swipe_lambda,
- R.array.no_default
- ),
- SWIPE_LAMBDA_REVERSE(
- "action.lambda_reverse",
- R.string.settings_gesture_swipe_lambda_reverse,
- R.string.settings_gesture_description_swipe_lambda_reverse,
- R.array.no_default
- ),
- SWIPE_V(
- "action.v",
- R.string.settings_gesture_swipe_v,
- R.string.settings_gesture_description_swipe_v,
- R.array.no_default
- ),
- SWIPE_V_REVERSE(
- "action.v_reverse",
- R.string.settings_gesture_swipe_v_reverse,
- R.string.settings_gesture_description_swipe_v_reverse,
- R.array.no_default
- ),
BACK(
"action.back",
R.string.settings_gesture_back,
@@ -316,7 +267,6 @@ enum class Gesture(
}
operator fun invoke(context: Context) {
- Log.i("Launcher", "Detected gesture: $this")
val action = Action.forGesture(this)
Action.launch(action, context, this.animationIn, this.animationOut)
}
diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt
index 973e0ca..b41eff3 100644
--- a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt
+++ b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt
@@ -6,11 +6,14 @@ import android.content.res.Resources
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
+import android.view.GestureDetector
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
+import android.view.ViewConfiguration
import android.window.OnBackInvokedDispatcher
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.GestureDetectorCompat
import androidx.core.view.isVisible
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.actions.Action
@@ -20,6 +23,13 @@ import de.jrpie.android.launcher.databinding.HomeBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
import java.util.Locale
+import java.util.Timer
+import kotlin.concurrent.fixedRateTimer
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.tan
+
/**
* [HomeActivity] is the actual application Launcher,
@@ -33,10 +43,10 @@ import java.util.Locale
* - Setting global variables (preferences etc.)
* - Opening the [TutorialActivity] on new installations
*/
-class HomeActivity : UIObject, AppCompatActivity() {
+class HomeActivity : UIObject, AppCompatActivity(),
+ GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
private lateinit var binding: HomeBinding
- private lateinit var touchGestureDetector: TouchGestureDetector
private var sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, prefKey ->
@@ -51,29 +61,22 @@ class HomeActivity : UIObject, AppCompatActivity() {
}
}
+ private var edgeWidth = 0.15f
+
+ private var bufferedPointerCount = 1 // how many fingers on screen
+ private var pointerBufferTimer = Timer()
+
+ private lateinit var mDetector: GestureDetectorCompat
+
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
super.onCreate()
-
- val displayMetrics = DisplayMetrics()
- windowManager.defaultDisplay.getMetrics(displayMetrics)
-
- val width = displayMetrics.widthPixels
- val height = displayMetrics.heightPixels
-
- touchGestureDetector = TouchGestureDetector(
- this,
- width,
- height,
- LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
- )
-
// Initialise layout
binding = HomeBinding.inflate(layoutInflater)
setContentView(binding.root)
-
// Handle back key / gesture on Android 13+, cf. onKeyDown()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(
@@ -92,6 +95,9 @@ class HomeActivity : UIObject, AppCompatActivity() {
override fun onStart() {
super.onStart()
+ mDetector = GestureDetectorCompat(this, this)
+ mDetector.setOnDoubleTapListener(this)
+
super.onStart()
LauncherPreferences.getSharedPreferences()
@@ -166,8 +172,7 @@ class HomeActivity : UIObject, AppCompatActivity() {
override fun onResume() {
super.onResume()
- touchGestureDetector.edgeWidth =
- LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
+ edgeWidth = LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() / 100f
initClock()
updateSettingsFallbackButtonVisibility()
@@ -206,8 +211,95 @@ class HomeActivity : UIObject, AppCompatActivity() {
return true
}
+ override fun onFling(e1: MotionEvent?, e2: MotionEvent, dX: Float, dY: Float): Boolean {
+
+ if (e1 == null) return false
+
+
+ val displayMetrics = DisplayMetrics()
+ windowManager.defaultDisplay.getMetrics(displayMetrics)
+
+ val width = displayMetrics.widthPixels
+ val height = displayMetrics.heightPixels
+
+ val diffX = e1.x - e2.x
+ val diffY = e1.y - e2.y
+
+ val doubleActions = LauncherPreferences.enabled_gestures().doubleSwipe()
+ val edgeActions = LauncherPreferences.enabled_gestures().edgeSwipe()
+
+ val threshold = ViewConfiguration.get(this).scaledTouchSlop
+ val angularThreshold = tan(Math.PI / 6)
+
+ var gesture = if (angularThreshold * abs(diffX) > abs(diffY)) { // horizontal swipe
+ if (diffX > threshold)
+ Gesture.SWIPE_LEFT
+ else if (diffX < -threshold)
+ Gesture.SWIPE_RIGHT
+ else null
+ } else if (angularThreshold * abs(diffY) > abs(diffX)) { // vertical swipe
+ // Only open if the swipe was not from the phones top edge
+ // TODO: replace 100px by sensible dp value (e.g. twice the height of the status bar)
+ if (diffY < -threshold && e1.y > 100)
+ Gesture.SWIPE_DOWN
+ else if (diffY > threshold)
+ Gesture.SWIPE_UP
+ else null
+ } else null
+
+ if (doubleActions && bufferedPointerCount > 1) {
+ gesture = gesture?.let(Gesture::getDoubleVariant)
+ }
+
+ if (edgeActions) {
+ if (max(e1.x, e2.x) < edgeWidth * width) {
+ gesture = gesture?.getEdgeVariant(Gesture.Edge.LEFT)
+ } else if (min(e1.x, e2.x) > (1 - edgeWidth) * width) {
+ gesture = gesture?.getEdgeVariant(Gesture.Edge.RIGHT)
+ }
+
+ if (max(e1.y, e2.y) < edgeWidth * height) {
+ gesture = gesture?.getEdgeVariant(Gesture.Edge.TOP)
+ } else if (min(e1.y, e2.y) > (1 - edgeWidth) * height) {
+ gesture = gesture?.getEdgeVariant(Gesture.Edge.BOTTOM)
+ }
+ }
+ gesture?.invoke(this)
+
+ return true
+ }
+
+ override fun onLongPress(event: MotionEvent) {
+ Gesture.LONG_CLICK(this)
+ }
+
+ override fun onDoubleTap(event: MotionEvent): Boolean {
+ Gesture.DOUBLE_CLICK(this)
+ return false
+ }
+
+ // Tooltip
+ override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
+
+ return false
+ }
+
override fun onTouchEvent(event: MotionEvent): Boolean {
- return touchGestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
+
+ // Buffer / Debounce the pointer count
+ if (event.pointerCount > bufferedPointerCount) {
+ bufferedPointerCount = event.pointerCount
+ pointerBufferTimer = fixedRateTimer("pointerBufferTimer", true, 300, 1000) {
+ bufferedPointerCount = 1
+ this.cancel() // a non-recurring timer
+ }
+ }
+
+ return if (mDetector.onTouchEvent(event)) {
+ false
+ } else {
+ super.onTouchEvent(event)
+ }
}
override fun setOnClicks() {
@@ -237,4 +329,16 @@ class HomeActivity : UIObject, AppCompatActivity() {
override fun isHomeScreen(): Boolean {
return true
}
+
+
+ /* TODO: Remove those. For now they are necessary
+ * because this inherits from GestureDetector.OnGestureListener */
+ override fun onDoubleTapEvent(event: MotionEvent): Boolean { return false }
+ override fun onDown(event: MotionEvent): Boolean { return false }
+ override fun onScroll(e1: MotionEvent?, e2: MotionEvent, dX: Float, dY: Float): Boolean { return false }
+ override fun onShowPress(event: MotionEvent) {}
+ override fun onSingleTapUp(event: MotionEvent): Boolean { return false }
+
+
+
}
diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/TouchGestureDetector.kt b/app/src/main/java/de/jrpie/android/launcher/ui/TouchGestureDetector.kt
deleted file mode 100644
index 0ddbfd1..0000000
--- a/app/src/main/java/de/jrpie/android/launcher/ui/TouchGestureDetector.kt
+++ /dev/null
@@ -1,246 +0,0 @@
-package de.jrpie.android.launcher.ui
-
-import android.content.Context
-import android.view.MotionEvent
-import android.view.ViewConfiguration
-import de.jrpie.android.launcher.actions.Gesture
-import de.jrpie.android.launcher.preferences.LauncherPreferences
-import kotlin.math.abs
-import kotlin.math.max
-import kotlin.math.min
-import kotlin.math.tan
-
-class TouchGestureDetector(
- private val context: Context,
- val width: Int,
- val height: Int,
- var edgeWidth: Float
-) {
- private val ANGULAR_THRESHOLD = tan(Math.PI / 6)
- private val TOUCH_SLOP: Int
- private val TOUCH_SLOP_SQUARE: Int
- private val DOUBLE_TAP_SLOP: Int
- private val DOUBLE_TAP_SLOP_SQUARE: Int
- private val LONG_PRESS_TIMEOUT: Int
- private val TAP_TIMEOUT: Int
- private val DOUBLE_TAP_TIMEOUT: Int
-
- private val MIN_TRIANGLE_HEIGHT = 250
-
-
- data class Vector(val x: Float, val y: Float) {
- fun absSquared(): Float {
- return this.x * this.x + this.y * this.y
- }
- fun plus(vector: Vector): Vector {
- return Vector(this.x + vector.x, this.y + vector.y)
- }
- fun max(other: Vector): Vector {
- return Vector(max(this.x, other.x), max(this.y, other.y))
- }
- fun min(other: Vector): Vector {
- return Vector(min(this.x, other.x), min(this.y, other.y))
- }
- operator fun minus(vector: Vector): Vector {
- return Vector(this.x - vector.x, this.y - vector.y)
- }
- }
-
-
- class PointerPath(
- val number: Int,
- val start: Vector,
- var last: Vector = start
- ) {
- var min = Vector(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
- var max = Vector(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY)
- fun sizeSquared(): Float {
- return (max - min).absSquared()
- }
- fun getDirection(): Vector {
- return last - start
- }
- fun update(vector: Vector) {
- min = min.min(vector)
- max = max.max(vector)
- last = vector
- }
- }
- private fun PointerPath.isTap(): Boolean {
- return sizeSquared() < TOUCH_SLOP_SQUARE
- }
-
- init {
- val configuration = ViewConfiguration.get(context)
- TOUCH_SLOP = configuration.scaledTouchSlop
- TOUCH_SLOP_SQUARE = TOUCH_SLOP * TOUCH_SLOP
- DOUBLE_TAP_SLOP = configuration.scaledDoubleTapSlop
- DOUBLE_TAP_SLOP_SQUARE = DOUBLE_TAP_SLOP * DOUBLE_TAP_SLOP
-
- LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout()
- TAP_TIMEOUT = ViewConfiguration.getTapTimeout()
- DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout()
- }
-
- private var paths = HashMap()
-
- private var lastTappedTime = 0L
- private var lastTappedLocation: Vector? = null
-
- fun onTouchEvent(event: MotionEvent): Boolean {
- val pointerIdToIndex =
- (0.. abs(direction.y)) { // horizontal swipe
- if (direction.x > TOUCH_SLOP)
- Gesture.SWIPE_RIGHT
- else if (direction.x < -TOUCH_SLOP)
- Gesture.SWIPE_LEFT
- else null
- } else if (ANGULAR_THRESHOLD * abs(direction.y) > abs(direction.x)) { // vertical swipe
- if (direction.y < -TOUCH_SLOP)
- Gesture.SWIPE_UP
- else if (direction.y > TOUCH_SLOP)
- Gesture.SWIPE_DOWN
- else null
- } else null
- }
-
- private fun classifyPaths(paths: Map, timeStart: Long, timeEnd: Long) {
- val duration = timeEnd - timeStart
- val pointerCount = paths.entries.size
- if (paths.entries.isEmpty()) {
- return
- }
-
- val mainPointerPath = paths.entries.firstOrNull { it.value.number == 0 }?.value ?: return
-
- // Ignore swipes at the very top, since this interferes with the status bar.
- // TODO: replace 100px by sensible dp value (e.g. twice the height of the status bar)
- if (paths.entries.any { it.value.start.y < 100 }) {
- return
- }
-
- if (pointerCount == 1 && mainPointerPath.isTap()) {
- // detect taps
-
- if (duration in 0..TAP_TIMEOUT) {
- if (timeStart - lastTappedTime < DOUBLE_TAP_TIMEOUT &&
- lastTappedLocation?.let {
- (mainPointerPath.last - it).absSquared() < DOUBLE_TAP_SLOP_SQUARE} == true
- ) {
- Gesture.DOUBLE_CLICK.invoke(context)
- } else {
- lastTappedTime = timeEnd
- lastTappedLocation = mainPointerPath.last
- }
- } else if (duration > LONG_PRESS_TIMEOUT) {
- // TODO: Don't wait until the finger is lifted.
- // Instead set a timer to start long click as soon as LONG_PRESS_TIMEOUT is reached
- Gesture.LONG_CLICK.invoke(context)
- }
- } else {
- // detect swipes
-
- val doubleActions = LauncherPreferences.enabled_gestures().doubleSwipe()
- val edgeActions = LauncherPreferences.enabled_gestures().edgeSwipe()
-
- var gesture = getGestureForDirection(mainPointerPath.getDirection())
-
- if (doubleActions && pointerCount > 1) {
- if (paths.entries.any { getGestureForDirection(it.value.getDirection()) != gesture }) {
- // the directions of the pointers don't match
- return
- }
- gesture = gesture?.let(Gesture::getDoubleVariant)
- }
-
- // detect triangles
- val startEndMin = mainPointerPath.start.min(mainPointerPath.last)
- val startEndMax = mainPointerPath.start.max(mainPointerPath.last)
- when (gesture) {
- Gesture.SWIPE_DOWN -> {
- if(startEndMax.x + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.x) {
- gesture = Gesture.SWIPE_LARGER
- } else if (startEndMin.x - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.x) {
- gesture = Gesture.SWIPE_SMALLER
- }
- }
- Gesture.SWIPE_UP -> {
- if(startEndMax.x + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.x) {
- gesture = Gesture.SWIPE_LARGER_REVERSE
- } else if (startEndMin.x - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.x) {
- gesture = Gesture.SWIPE_SMALLER_REVERSE
- }
- }
- Gesture.SWIPE_RIGHT -> {
- if(startEndMax.y + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.y) {
- gesture = Gesture.SWIPE_V
- } else if (startEndMin.y - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.y) {
- gesture = Gesture.SWIPE_LAMBDA
- }
- }
- Gesture.SWIPE_LEFT -> {
- if(startEndMax.y + MIN_TRIANGLE_HEIGHT < mainPointerPath.max.y) {
- gesture = Gesture.SWIPE_V_REVERSE
- } else if (startEndMin.y - MIN_TRIANGLE_HEIGHT > mainPointerPath.min.y) {
- gesture = Gesture.SWIPE_LAMBDA_REVERSE
- }
- }
- else -> { }
- }
-
- if (edgeActions) {
- if (mainPointerPath.max.x < edgeWidth * width) {
- gesture = gesture?.getEdgeVariant(Gesture.Edge.LEFT)
- } else if (mainPointerPath.min.x > (1 - edgeWidth) * width) {
- gesture = gesture?.getEdgeVariant(Gesture.Edge.RIGHT)
- }
-
- if (mainPointerPath.max.y < edgeWidth * height) {
- gesture = gesture?.getEdgeVariant(Gesture.Edge.TOP)
- } else if (mainPointerPath.min.y > (1 - edgeWidth) * height) {
- gesture = gesture?.getEdgeVariant(Gesture.Edge.BOTTOM)
- }
- }
- gesture?.invoke(context)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/res/values/defaults.xml b/app/src/main/res/values/defaults.xml
index cee201e..276651d 100644
--- a/app/src/main/res/values/defaults.xml
+++ b/app/src/main/res/values/defaults.xml
@@ -2,8 +2,6 @@
-
-
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b61c1b0..97d7384 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -59,24 +59,6 @@
Swipe down at the left edge of the screen
Down (Right Edge)
Swipe down at the right edge of the screen
-
- ]]>
- Top left -> mid right -> bottom left
- (reverse)]]>
- Bottom left -> mid right -> top left
-
- Top right -> mid left -> bottom right
-
- Bottom right -> mid left -> top right
- V
- Top left -> bottom mid -> top right
- V (reverse)
- Top right -> bottom mid -> top left
- Λ
- Bottom left -> top mid -> bottom right
- Λ (reverse)
- Bottom right -> top mid -> bottom left
-
Volume Up
Press the volume up button
Volume Down
diff --git a/docs/launcher.md b/docs/launcher.md
deleted file mode 100644
index 37b24a4..0000000
--- a/docs/launcher.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Notable changes compared to [Finn's Launcher][original-repo]:
-
-µLauncher is a fork of [finnmglas's app Launcher][original-repo].
-Here is an incomplete list of changes:
-
-
-
-- Additional gestures:
- - Back
- - V,Λ,<,>
- - Edge gestures: There is a setting to allow distinguishing swiping at the edges of the screen from swiping in the center.
-- 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)
-- Option to rename apps
-- Option to hide apps
-- Favorite apps
-- New actions:
- - Toggle Torch
- - Lock screen
-- The home button now works as expected.
-- Improved gesture detection.
-
-### Visual
-- This app uses the system wallpaper instead of a custom solution.
-- The font has been changed to [Hack][hack-font], other fonts can be selected.
-- Font Awesome Icons were replaced by Material icons.
-- The gear button on the home screen was removed. A smaller button is show at the top right when necessary.
-
-
-### Search
-- 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
-
-
-The complete list of changes can be viewed [here](https://github.com/jrpie/launcher/compare/340ee731...master).
-
----
- [original-repo]: https://github.com/finnmglas/Launcher
diff --git a/fastlane/metadata/android/tr-TR/changelogs/21.txt b/fastlane/metadata/android/tr-TR/changelogs/21.txt
deleted file mode 100644
index 91667e5..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/21.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-- Çince çeviri (teşekkürler, yzqzss!)
-- Fransızca çeviri iyileştirildi (teşekkürler, toby-bro!)
-- Almanca çeviri iyileştirildi
-
-Tüm Uygulamalar:
-- Uygulama listesindeki üç nokta kaldırıldı (bunun yerine uzun tıklama kullanın)
-- Enter'a basıldığında sorguyla eşleşen ilk uygulama açılıyor
-- Klavyeyi tam ekran modunda açarken oluşan hata için geçici çözüm düzeltildi
-- Sistem uygulamaları için kaldırma seçeneği kaldırıldı
-- Ana Sayfa Düğmesi artık düzgün çalışıyor
-
-Ayarlar:
-- Küçük ekranlar için ayarlar düzeltildi
-- Hassasiyet ayarı kaldırıldı (herkes zaten maksimuma ayarlıyordu)
-- Tarih ve saat ayarları yeniden düzenlendi
diff --git a/fastlane/metadata/android/tr-TR/changelogs/24.txt b/fastlane/metadata/android/tr-TR/changelogs/24.txt
deleted file mode 100644
index 63f5cde..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/24.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-* Renk teması, yazı tipi, arka plan, monokrom simgeler için seçenekler eklendi
-* Tarih ve saat için seçenekler eklendi
-* Döndürmeye izin verme seçeneği eklendi
-* İyileştirilmiş arama algoritması
-* Brezilya Portekizcesine çeviri - teşekkürler, Jonatas de Almeida Barros!
-* Ayarlardan seçilen uygulamaların kaybolmasına neden olan bir hata düzeltildi
-* İyileştirilmiş kod kalitesi
-* Güncellenmiş çeviriler
diff --git a/fastlane/metadata/android/tr-TR/changelogs/25.txt b/fastlane/metadata/android/tr-TR/changelogs/25.txt
deleted file mode 100644
index 6aa3565..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/25.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-* Favori uygulamalar
-* Uygulamaları gizleme seçeneği
-* Birden fazla ana aktiviteye sahip uygulamalar için destek
-* Küçük ekranlarda ayarların düzeni düzeltildi
diff --git a/fastlane/metadata/android/tr-TR/changelogs/26.txt b/fastlane/metadata/android/tr-TR/changelogs/26.txt
deleted file mode 100644
index 9174cd3..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/26.txt
+++ /dev/null
@@ -1 +0,0 @@
-hata düzeltme
diff --git a/fastlane/metadata/android/tr-TR/changelogs/27.txt b/fastlane/metadata/android/tr-TR/changelogs/27.txt
deleted file mode 100644
index ec73839..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/27.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-* Matrix ve Discord'da sohbet
-* Hareket algılama iyileştirildi
-* Hareket açıklamaları iyileştirildi
-* Yeni eylem: Ekranı kilitle - teşekkürler, yzqzss!
-* Yeni eylem: Meşaleyi aç
-* Yeni eylem: Hızlı ayarları aç
-* Fransızca çevirisi iyileştirildi - teşekkürler, toby-bro!
-* Portekizce çevirisi iyileştirildi - teşekkürler, "Vossa Excelencia"!
-* Bazı hatalar düzeltildi
diff --git a/fastlane/metadata/android/tr-TR/changelogs/29.txt b/fastlane/metadata/android/tr-TR/changelogs/29.txt
deleted file mode 100644
index 4f318eb..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/29.txt
+++ /dev/null
@@ -1 +0,0 @@
-Ekranı kilitlemek için Cihaz Yöneticisi yerine Erişilebilirlik Hizmetini kullanma seçeneği eklendi.
diff --git a/fastlane/metadata/android/tr-TR/changelogs/32.txt b/fastlane/metadata/android/tr-TR/changelogs/32.txt
deleted file mode 100644
index 0499004..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/32.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-* Uygulamaları yeniden adlandırma seçeneği
-* Uygulama listesinden hareketlere bağlı uygulamaları otomatik olarak gizleme seçeneği
-* Uygulama listesinden µLauncher'ı varsayılan olarak gizle
-* Varsayılan uygulamaların seçimi iyileştirildi
-* Açık tema (deneysel)
-
-* Aramadaki hata düzeltildi
-* Kilit ekranı iletişim kutusundaki hata düzeltildi (teşekkürler, yzqzss ve jeroen!)
-
-* Portekizce çeviri güncellendi (teşekkürler, "Vossa Excelencia"!)
-* Almanca çeviri güncellendi
diff --git a/fastlane/metadata/android/tr-TR/changelogs/33.txt b/fastlane/metadata/android/tr-TR/changelogs/33.txt
deleted file mode 100644
index 64bea01..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/33.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-* Uygulama listesi için alternatif düzenler (ızgara, metin)
-* Hata düzeltildi: Uygulamaların yeniden adlandırılması artık düzgün çalışıyor
-
-* Çince çeviri güncellendi (teşekkürler, yzqzss!)
-* Portekizce çeviri güncellendi (teşekkürler, "Vossa Excelencia"!)
diff --git a/fastlane/metadata/android/tr-TR/changelogs/34.txt b/fastlane/metadata/android/tr-TR/changelogs/34.txt
deleted file mode 100644
index c1b80a1..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/34.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-* Saat rengini seçme seçeneği
-* Dinamik renk teması eklendi; açık tema kaldırıldı
-* Erişilebilirlik hizmeti için onay iletişim kutusu eklendi
-
-* Türkçe çeviri eklendi (teşekkürler, Ahmet Çeliker!)
-* İtalyanca çeviri eklendi (teşekkürler, Samantha!)
-* Portekizce çeviri iyileştirildi (teşekkürler, "Vossa Excelencia"!)
-
-* Uygulama çekmecesinde hareketle gezinmeyle ilgili hata düzeltildi. Artık geri basıldığında çekmece hemen kapanıyor.
diff --git a/fastlane/metadata/android/tr-TR/changelogs/35.txt b/fastlane/metadata/android/tr-TR/changelogs/35.txt
deleted file mode 100644
index cfd9c1e..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/35.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-* Ayarlar için depolama biçimi yeniden düzenlendi. Eski biçim otomatik olarak dönüştürülecek.
-* Uygulama listesinden web'de arama yapma seçeneği eklendi.
-* Ekranı kilitlemek için tercih edilen yöntem olarak cihaz yöneticisini ayarlayın.
-* Bir erişilebilirlik hizmetini etkinleştirmenin şifrelemeyle çakışabileceğine dair bir uyarı eklendi.
-* Yeniden adlandırma iletişim kutusundaki bir hata düzeltildi.
-* Kilit ekranı iletişim kutusu kaydırılabilir hale getirildi.
diff --git a/fastlane/metadata/android/tr-TR/changelogs/36.txt b/fastlane/metadata/android/tr-TR/changelogs/36.txt
deleted file mode 100644
index a8b448e..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/36.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-* yeni özellik: otomatik başlatmayı geçici olarak devre dışı bırakmak için boşluk içeren önek sorgusu
-* iyileştirilmiş arama: sorguda görünmedikleri sürece diakritik işaretler artık yok sayılıyor. (Android 7+)
-* açık kaynak lisanslarının listesi eklendi
-* erişilebilirlik hizmeti uyarısı güncellendi
-* iyileştirilmiş Fransızca çeviri (teşekkürler, Alexandre Ancel ve Nin Dan!)
-* iyileştirilmiş Portekizce çeviri (teşekkürler, "Vossa Excelencia"!)
diff --git a/fastlane/metadata/android/tr-TR/changelogs/37.txt b/fastlane/metadata/android/tr-TR/changelogs/37.txt
deleted file mode 100644
index 914b7d5..0000000
--- a/fastlane/metadata/android/tr-TR/changelogs/37.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-* private space için temel destek (Android 15)
-* light tema yeniden tanıtıldı
-* Portekizce çeviri iyileştirildi (teşekkürler, "Vossa Excelencia"!)
-* Almanca çeviri iyileştirildi
-* ayarlara sürüm adı eklendi
-* hata raporları için iletişim kutusu
-* saat performansı iyileştirildi
-* bazı hatalar düzeltildi
diff --git a/fastlane/metadata/android/tr-TR/title.txt b/fastlane/metadata/android/tr-TR/title.txt
deleted file mode 100644
index ad88d66..0000000
--- a/fastlane/metadata/android/tr-TR/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-µBaşlatıcı