merge #124 - improve tutorial
Some checks are pending
Android CI / build (push) Waiting to run

* Add new "app list" section
* Rename fragments
* Replace screenshots
* Replace ViewPager by ViewPager2
* Add navigation buttons

Co-authored-by: Luke Wass <wassupluke@gmail.com>
This commit is contained in:
Josia Pietsch 2025-03-15 03:11:08 +01:00
parent 3597baee1f
commit c1511cd475
Signed by: jrpie
GPG key ID: E70B571D66986A2D
22 changed files with 298 additions and 104 deletions

View file

@ -4,23 +4,26 @@ import android.content.Intent
import android.content.res.Resources
import android.os.Build
import android.os.Bundle
import android.view.View
import android.window.OnBackInvokedDispatcher
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout
import de.jrpie.android.launcher.R
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.databinding.TutorialBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.saveListActivityChoice
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentConcept
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentFinish
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentSetup
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentStart
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentUsage
import de.jrpie.android.launcher.ui.blink
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragment0Start
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragment1Concept
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragment2Usage
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragment3AppList
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragment4Setup
import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragment5Finish
/**
* The [TutorialActivity] is displayed automatically on new installations.
@ -31,10 +34,16 @@ import de.jrpie.android.launcher.ui.tutorial.tabs.TutorialFragmentUsage
*/
class TutorialActivity : AppCompatActivity(), UIObject {
private lateinit var binding: TutorialBinding
override fun onCreate(savedInstanceState: Bundle?) {
super<AppCompatActivity>.onCreate(savedInstanceState)
super<UIObject>.onCreate()
// Initialise layout
binding = TutorialBinding.inflate(layoutInflater)
setContentView(binding.root)
// Handle back key / gesture on Android 13+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
onBackInvokedDispatcher.registerOnBackInvokedCallback(
@ -48,15 +57,51 @@ class TutorialActivity : AppCompatActivity(), UIObject {
}
}
// Initialise layout
setContentView(R.layout.tutorial)
// set up tabs and swiping in settings
val sectionsPagerAdapter = TutorialSectionsPagerAdapter(supportFragmentManager)
val viewPager: ViewPager = findViewById(R.id.tutorial_viewpager)
viewPager.adapter = sectionsPagerAdapter
val tabs: TabLayout = findViewById(R.id.tutorial_tabs)
tabs.setupWithViewPager(viewPager)
val sectionsPagerAdapter = TutorialSectionsPagerAdapter(this)
binding.tutorialViewpager.apply {
adapter = sectionsPagerAdapter
currentItem = 0
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
binding.tutorialButtonNext.apply {
val lastItem = sectionsPagerAdapter.itemCount - 1
visibility = if (position == lastItem) {
View.INVISIBLE
} else {
View.VISIBLE
}
if (position == 0) {
blink()
} else {
clearAnimation()
}
}
binding.tutorialButtonBack.apply {
visibility = if (position == 0) {
View.INVISIBLE
} else {
View.VISIBLE
}
}
}
})
}
TabLayoutMediator(binding.tutorialTabs, binding.tutorialViewpager) { _, _ -> }.attach()
binding.tutorialButtonNext.setOnClickListener {
binding.tutorialViewpager.apply {
setCurrentItem(
(currentItem + 1).coerceAtMost(sectionsPagerAdapter.itemCount - 1),
true
)
}
}
binding.tutorialButtonBack.setOnClickListener {
binding.tutorialViewpager.apply {
setCurrentItem((currentItem - 1).coerceAtLeast(0), true)
}
}
}
override fun getTheme(): Resources.Theme {
@ -89,26 +134,22 @@ class TutorialActivity : AppCompatActivity(), UIObject {
*
* Tabs: (Start | Concept | Usage | Setup | Finish)
*/
class TutorialSectionsPagerAdapter(fm: FragmentManager) :
FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
class TutorialSectionsPagerAdapter(activity: FragmentActivity) :
FragmentStateAdapter(activity) {
override fun getItem(position: Int): Fragment {
override fun getItemCount(): Int {
return 6
}
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> TutorialFragmentStart()
1 -> TutorialFragmentConcept()
2 -> TutorialFragmentUsage()
3 -> TutorialFragmentSetup()
4 -> TutorialFragmentFinish()
0 -> TutorialFragment0Start()
1 -> TutorialFragment1Concept()
2 -> TutorialFragment2Usage()
3 -> TutorialFragment3AppList()
4 -> TutorialFragment4Setup()
5 -> TutorialFragment5Finish()
else -> Fragment()
}
}
/* We don't use titles here, as we have the dots */
override fun getPageTitle(position: Int): CharSequence {
return ""
}
override fun getCount(): Int {
return 5
}
}

View file

@ -5,24 +5,22 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.databinding.TutorialStartBinding
import de.jrpie.android.launcher.databinding.Tutorial0StartBinding
import de.jrpie.android.launcher.ui.UIObject
import de.jrpie.android.launcher.ui.blink
/**
* The [TutorialFragmentStart] is a used as a tab in the TutorialActivity.
* The [TutorialFragment0Start] is a used as a tab in the TutorialActivity.
*
* It displays info about the app and gets the user into the tutorial
*/
class TutorialFragmentStart : Fragment(), UIObject {
class TutorialFragment0Start : Fragment(), UIObject {
private lateinit var binding: TutorialStartBinding
private lateinit var binding: Tutorial0StartBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = TutorialStartBinding.inflate(inflater, container, false)
binding.tutorialStartIconRight.blink()
binding = Tutorial0StartBinding.inflate(inflater, container, false)
return binding.root
}

View file

@ -6,22 +6,22 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.BuildConfig
import de.jrpie.android.launcher.databinding.TutorialConceptBinding
import de.jrpie.android.launcher.databinding.Tutorial1ConceptBinding
import de.jrpie.android.launcher.ui.UIObject
/**
* The [TutorialFragmentConcept] is a used as a tab in the TutorialActivity.
* The [TutorialFragment1Concept] is a used as a tab in the TutorialActivity.
*
* It is used to display info about Launchers concept (open source, efficiency ...)
*/
class TutorialFragmentConcept : Fragment(), UIObject {
private lateinit var binding: TutorialConceptBinding
class TutorialFragment1Concept : Fragment(), UIObject {
private lateinit var binding: Tutorial1ConceptBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = TutorialConceptBinding.inflate(inflater, container, false)
binding = Tutorial1ConceptBinding.inflate(inflater, container, false)
binding.tutorialConceptBadgeVersion.text = BuildConfig.VERSION_NAME
return binding.root
}

View file

@ -9,17 +9,17 @@ import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.ui.UIObject
/**
* The [TutorialFragmentUsage] is a used as a tab in the TutorialActivity.
* The [TutorialFragment2Usage] is a used as a tab in the TutorialActivity.
*
* Tells the user how his screen will look and how the app can be used
*/
class TutorialFragmentUsage : Fragment(), UIObject {
class TutorialFragment2Usage : Fragment(), UIObject {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.tutorial_usage, container, false)
return inflater.inflate(R.layout.tutorial_2_usage, container, false)
}
override fun onStart() {

View file

@ -0,0 +1,30 @@
package de.jrpie.android.launcher.ui.tutorial.tabs
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.ui.UIObject
/**
* The [TutorialFragment3AppList] is a used as a tab in the TutorialActivity.
*
* Tells the user how his screen will look and how the app can be used
*/
class TutorialFragment3AppList : Fragment(), UIObject {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.tutorial_3_app_list, container, false)
}
override fun onStart() {
super<Fragment>.onStart()
super<UIObject>.onStart()
}
}

View file

@ -9,17 +9,17 @@ import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.ui.UIObject
/**
* The [TutorialFragmentSetup] is a used as a tab in the TutorialActivity.
* The [TutorialFragment4Setup] is a used as a tab in the TutorialActivity.
*
* It is used to display info in the tutorial
*/
class TutorialFragmentSetup : Fragment(), UIObject {
class TutorialFragment4Setup : Fragment(), UIObject {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.tutorial_setup, container, false)
return inflater.inflate(R.layout.tutorial_4_setup, container, false)
}
override fun onStart() {

View file

@ -6,25 +6,25 @@ 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.TutorialFinishBinding
import de.jrpie.android.launcher.databinding.Tutorial5FinishBinding
import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.setDefaultHomeScreen
import de.jrpie.android.launcher.ui.UIObject
/**
* The [TutorialFragmentFinish] is a used as a tab in the TutorialActivity.
* The [TutorialFragment5Finish] is a used as a tab in the TutorialActivity.
*
* It is used to display further resources and let the user start Launcher
*/
class TutorialFragmentFinish : Fragment(), UIObject {
class TutorialFragment5Finish : Fragment(), UIObject {
private lateinit var binding: TutorialFinishBinding
private lateinit var binding: Tutorial5FinishBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = TutorialFinishBinding.inflate(inflater, container, false)
binding = Tutorial5FinishBinding.inflate(inflater, container, false)
return binding.root
}

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z" />
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://stackoverflow.com/a/30692466 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -10,7 +10,7 @@
tools:context=".ui.tutorial.TutorialActivity">
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/tutorial_viewpager"
android:layout_width="0dp"
android:layout_height="0dp"
@ -22,15 +22,37 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<ImageView
android:id="@+id/tutorial_button_back"
android:layout_width="50dp"
android:layout_height="50dp"
android:gravity="center"
android:alpha="0.5"
android:src="@drawable/baseline_navigate_before_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tutorial_viewpager" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tutorial_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_height="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tutorial_button_next"
app:layout_constraintStart_toEndOf="@+id/tutorial_button_back"
app:tabBackground="@drawable/tutorial_tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"
app:tabIndicatorHeight="0dp" />
<ImageView
android:id="@+id/tutorial_button_next"
android:layout_width="50dp"
android:layout_height="50dp"
android:gravity="center"
android:src="@drawable/baseline_navigate_next_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintTop_toBottomOf="@+id/tutorial_viewpager" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -8,7 +8,7 @@
android:paddingRight="32sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.tutorial.tabs.TutorialFragmentStart">
tools:context=".ui.tutorial.tabs.TutorialFragment0Start">
<TextView
android:id="@+id/tutorial_start_text"
@ -21,16 +21,4 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tutorial_start_icon_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=">>>>>>"
android:textSize="64sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tutorial_start_text" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -8,7 +8,7 @@
android:paddingRight="32sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.tutorial.tabs.TutorialFragmentConcept">
tools:context=".ui.tutorial.tabs.TutorialFragment1Concept">
<TextView
android:id="@+id/tutorial_concept_title"
@ -28,11 +28,10 @@
android:gravity="center"
android:text="@string/tutorial_concept_text"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tutorial_concept_title"
app:layout_constraintVertical_bias="0.19999999" />
app:layout_constraintBottom_toTopOf="@id/tutorial_concept_badge_version_label"/>
<TextView
android:id="@+id/tutorial_concept_text_2"
@ -60,6 +59,22 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tutorial_concept_text"
tools:text="0.0.7"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tutorial_concept_badge_version_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:gravity="center"
android:textSize="18sp"
android:text="@string/tutorial_concept_label_version"
app:layout_constraintBottom_toTopOf="@+id/tutorial_concept_badge_version"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -7,7 +7,7 @@
android:layout_height="match_parent"
android:paddingLeft="32sp"
android:paddingRight="32sp"
tools:context=".ui.tutorial.tabs.TutorialFragmentUsage">
tools:context=".ui.tutorial.tabs.TutorialFragment2Usage">
<TextView
android:id="@+id/tutorial_usage_title"
@ -39,12 +39,12 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerInside"
android:src="@drawable/home_round_screen"
android:src="@drawable/tutorial_home_screen"
app:layout_constraintBottom_toTopOf="@id/tutorial_usage_text_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/tutorial_usage_text"
app:layout_constraintTop_toBottomOf="@id/tutorial_usage_text"
app:srcCompat="@drawable/home_round_screen"
app:srcCompat="@drawable/tutorial_home_screen"
tools:ignore="ContentDescription" />
<TextView

View file

@ -0,0 +1,64 @@
<?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/tutorial_usage_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="32sp"
android:paddingRight="32sp"
tools:context=".ui.tutorial.tabs.TutorialFragment3AppList">
<TextView
android:id="@+id/tutorial_app_list_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/tutorial_app_list_title"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tutorial_app_list_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="32dp"
android:gravity="center"
android:text="@string/tutorial_app_list_text"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/tutorial_app_list_screen"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tutorial_app_list_title" />
<ImageView
android:id="@+id/tutorial_app_list_screen"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerInside"
android:src="@drawable/tutorial_app_list"
app:layout_constraintBottom_toTopOf="@id/tutorial_app_list_text_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/tutorial_app_list_text"
app:layout_constraintTop_toBottomOf="@id/tutorial_app_list_text"
app:srcCompat="@drawable/tutorial_app_list"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tutorial_app_list_text_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:text="@string/tutorial_app_list_text_2"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tutorial_app_list_screen" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -8,7 +8,7 @@
android:layout_height="match_parent"
android:paddingLeft="32sp"
android:paddingRight="32sp"
tools:context=".ui.tutorial.tabs.TutorialFragmentSetup">
tools:context=".ui.tutorial.tabs.TutorialFragment4Setup">
<TextView
android:id="@+id/tutorial_setup_title"

View file

@ -7,7 +7,7 @@
android:paddingRight="32sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.tutorial.tabs.TutorialFragmentFinish">
tools:context=".ui.tutorial.tabs.TutorialFragment5Finish">
<TextView
android:id="@+id/tutorial_finish_title"
@ -24,6 +24,7 @@
android:id="@+id/tutorial_finish_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/tutorial_finish_text"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@id/tutorial_finish_button_start"

View file

@ -176,7 +176,7 @@
<!-- Legal -->
<string name="legal_info_text"><![CDATA[
<h2>µLauncher</h2>
<h2>μLauncher</h2>
Modifications to Launcher.
<p><a href=\"https://github.com/jrpie/launcher\">github.com/jrpie/launcher</a></p>

View file

@ -193,7 +193,7 @@
<string name="settings_general_choose_home_screen">Set μLauncher as home screen</string>
<string name="settings_meta_cant_select_launcher">App Info</string>
<string name="settings_meta_show_tutorial">View Launcher Tutorial</string>
<string name="settings_meta_show_tutorial">View µLauncher Tutorial</string>
<string name="settings_meta_reset">Reset Settings</string>
<string name="settings_meta_reset_confirm">You are going to discard all your preferences. Continue?</string>
@ -202,14 +202,14 @@
<string name="settings_meta_report_bug">Report a bug</string>
<string name="dialog_report_bug_title">Report a bug</string>
<string name="dialog_report_bug_info">Thank you for helping to improve µLauncher!\nPlease consider adding the following information to your bug report:</string>
<string name="dialog_report_bug_info">Thank you for helping to improve μLauncher!\nPlease consider adding the following information to your bug report:</string>
<string name="dialog_report_bug_button_clipboard">Copy to clipboard</string>
<string name="dialog_report_bug_security_info">Please do not report security vulnerabilities publicly on GitHub, but use the following instead:</string>
<string name="dialog_report_bug_button_security">Report a security vulnerability</string>
<string name="dialog_report_bug_create_report">Create report</string>
<string name="settings_meta_fork_contact">Contact the developer of the fork</string>
<string name="settings_meta_join_chat">Join µLauncher chat</string>
<string name="settings_meta_join_chat">Join μLauncher chat</string>
<string name="settings_meta_donate">Donate</string>
<string name="settings_meta_privacy">Privacy Policy</string>
@ -246,7 +246,7 @@
<string name="list_apps_search_hint">Search</string>
<string name="list_apps_search_hint_no_auto_launch">Search (no auto launch)</string>
<string name="list_other_settings">µLauncher Settings</string>
<string name="list_other_settings">μLauncher Settings</string>
<string name="list_other_list">All Applications</string>
<string name="list_other_list_favorites">Favorite Applications</string>
<string name="list_other_list_private_space">Private Space</string>
@ -274,22 +274,29 @@
-
-->
<string name="tutorial_title">Tutorial</string>
<string name="tutorial_start_text">Take a few seconds to learn how to use this Launcher!</string>
<string name="tutorial_start_text">👋\n\nTake a few seconds to learn how to use this Launcher!</string>
<string name="tutorial_concept_title">Concept</string>
<string name="tutorial_concept_text">Launcher is designed to be minimal, efficient and free of distraction. It is free of payments, ads and tracking services.</string>
<string name="tutorial_concept_text_2">The app is open-source (MIT license) and available on GitHub! Make sure to check out the repository!</string>
<string name="tutorial_concept_text">μLauncher is designed to be minimal, efficient and free of distraction.
\n\nIt contains no ads and collects no data.</string>
<string name="tutorial_concept_text_2">It is free software (MIT license)!\nMake sure to check out the repository!</string>
<string name="tutorial_concept_label_version">Version</string>
<string name="tutorial_usage_title">Usage</string>
<string name="tutorial_usage_text">Your home screen contains the local date and time. No distraction.</string>
<string name="tutorial_usage_text_2">You can launch your apps with a single swipe or button press. Choose some in the next slide.</string>
<string name="tutorial_usage_text_2">You can launch your most important apps with touch gestures or button presses.</string>
<string name="tutorial_app_list_title">All Apps</string>
<string name="tutorial_app_list_text">You can quickly search through all apps in the app list.\n\nSwipe up to open it, or bind it to a different gesture.</string>
<string name="tutorial_app_list_text_2">Once only one app matches, it launches automatically.\nThis can be disabled by prefixing the query with a space.</string>
<string name="tutorial_setup_title">Setup</string>
<string name="tutorial_setup_text">We chose some default apps for you. You can change them now if you want to:</string>
<string name="tutorial_setup_text_2">You can also change your selection later.</string>
<string name="tutorial_finish_title">Let\'s go!</string>
<string name="tutorial_finish_text">You are ready to get started! I hope this is of great value to you! - Finn (who made Launcher) \tand Josia (who made some improvements and maintains the fork μLauncher)</string>
<string name="tutorial_finish_text">You are ready to get started!\n\nI hope this is of great value to you!\n\n- Finn (who made Launcher) and Josia (who made some improvements and maintains the fork μLauncher)</string>
<string name="tutorial_finish_button">Start</string>
@ -301,7 +308,7 @@
<string name="snackbar_app_hidden">App hidden. You can make it visible again in settings.</string>
<string name="undo">Undo</string>
<string name="list_other_expand_settings_panel">Quick Settings</string>
<string name="toast_device_admin_not_enabled">µLauncher needs to be a device admin in order to lock the screen.</string>
<string name="toast_device_admin_not_enabled">μLauncher needs to be a device admin in order to lock the screen.</string>
<string name="device_admin_explanation">This is required for the lock screen action.</string>
<string name="device_admin_description">Enable the lock screen action</string>
<string name="alert_no_torch_found">No camera with torch detected.</string>
@ -311,18 +318,18 @@
<string name="toast_private_space_locked">Private space locked</string>
<string name="toast_private_space_unlocked">Private space unlocked</string>
<string name="toast_private_space_not_available">Private space is not available</string>
<string name="toast_private_space_default_home_screen">µLauncher needs to be the default home screen to access private space.</string>
<string name="toast_private_space_default_home_screen">μLauncher needs to be the default home screen to access private space.</string>
<string name="tooltip_lock_private_space">Lock private space</string>
<string name="tooltip_unlock_private_space">Unlock private space</string>
<string name="toast_lock_screen_not_supported">Error: Locking the screen using accessibility is not supported on this device. Please use device admin instead.</string>
<string name="accessibility_service_name">µLauncher - lock screen</string>
<string name="accessibility_service_name">μLauncher - lock screen</string>
<string name="accessibility_service_description">
Setting µLauncher as an accessibility service allows it to lock the screen.
Setting μLauncher as an accessibility service allows it to lock the screen.
Note that excessive permissions are required. You should never grant such permissions lightly to any app.
µLauncher will use the accessibility service only for locking the screen. You can check the source code to make sure.
μLauncher will use the accessibility service only for locking the screen. You can check the source code to make sure.
Note that locking the screen can also be accomplished by granting µLauncher device administrator permissions. However that method doesn\'t work with fingerprint and face unlock.
Note that locking the screen can also be accomplished by granting μLauncher device administrator permissions. However that method doesn\'t work with fingerprint and face unlock.
</string>
@ -340,7 +347,7 @@
<h3>Accessibility Service</h3>
Requires excessive privileges.
µLauncher will use those privileges only for locking the screen.
μLauncher will use those privileges only for locking the screen.
<br/>
(You really should not trust a random app you just downloaded with such a claim, but you can check the <a href=\"https://github.com/jrpie/Launcher\">source code</a>.)
<br/>
@ -363,11 +370,11 @@
<string name="dialog_select_color_ok">Ok</string>
<string name="dialog_select_color_color_hex">Color</string>
<string name="dialog_choose_color_title">Choose color</string>
<string name="dialog_consent_accessibility_privileges">I am aware that this will grant far-reaching privileges to µLauncher.</string>
<string name="dialog_consent_accessibility_privileges">I am aware that this will grant far-reaching privileges to μLauncher.</string>
<string name="dialog_consent_accessibility_other_options">I am aware that other options exist (using device administrator privileges or the power button).</string>
<string name="dialog_consent_accessibility_consent">I consent to µLauncher using the accessibility service to provide functionality unrelated to accessibility.</string>
<string name="dialog_consent_accessibility_data_collection">I consent to µLauncher not collecting any data.</string>
<string name="dialog_consent_accessibility_text"><![CDATA[You are about to activate the accessibility service. This will grant <strong>far-reaching privileges</strong> to µLauncher.<br/>µLauncher will use these privileges <strong>only to lock the screen</strong>. µLauncher <strong>will never collect any data</strong>. In particular, µLauncher does not use the accessibility service to collect any data.]]></string>
<string name="dialog_consent_accessibility_consent">I consent to μLauncher using the accessibility service to provide functionality unrelated to accessibility.</string>
<string name="dialog_consent_accessibility_data_collection">I consent to μLauncher not collecting any data.</string>
<string name="dialog_consent_accessibility_text"><![CDATA[You are about to activate the accessibility service. This will grant <strong>far-reaching privileges</strong> to μLauncher.<br/>μLauncher will use these privileges <strong>only to lock the screen</strong>. μLauncher <strong>will never collect any data</strong>. In particular, μLauncher does not use the accessibility service to collect any data.]]></string>
<string name="dialog_consent_accessibility_title">Activating the Accessibility Service</string>
<string name="dialog_consent_accessibility_ok">Activate Accessibility Service</string>
<string name="dialog_cancel">Cancel</string>