code cleanup

This commit is contained in:
Josia Pietsch 2024-07-06 21:14:06 +02:00
parent 33021edc37
commit 57ccc589d6
Signed by: jrpie
GPG key ID: E70B571D66986A2D
25 changed files with 171 additions and 225 deletions

View file

@ -1,7 +1,6 @@
<!-- Shields from shields.io --> <!-- Shields from shields.io -->
<!--[![][shield-release]][latest-release] --> <!--[![][shield-release]][latest-release] -->
[![][shield-license]][license] [![][shield-license]][license]
[![][shield-contribute]][issues]
<!-- ENGLISH README --> <!-- ENGLISH README -->

View file

@ -3,11 +3,15 @@ package de.jrpie.android.launcher
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.* import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.media.AudioManager import android.media.AudioManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -19,7 +23,8 @@ import android.view.KeyEvent
import android.view.View import android.view.View
import android.view.Window import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import android.view.animation.* import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.Button import android.widget.Button
import android.widget.ImageView import android.widget.ImageView
@ -31,7 +36,6 @@ import de.jrpie.android.launcher.list.apps.AppsRecyclerAdapter
import de.jrpie.android.launcher.settings.SettingsActivity import de.jrpie.android.launcher.settings.SettingsActivity
import de.jrpie.android.launcher.settings.intendedSettingsPause import de.jrpie.android.launcher.settings.intendedSettingsPause
import de.jrpie.android.launcher.tutorial.TutorialActivity import de.jrpie.android.launcher.tutorial.TutorialActivity
import kotlin.math.roundToInt
/* Preferences (global, initialised when app is started) */ /* Preferences (global, initialised when app is started) */
@ -103,10 +107,10 @@ var volumeDownApp = ""
var doubleClickApp = "" var doubleClickApp = ""
var longClickApp = "" var longClickApp = ""
var timeApp = "" var timeApp = ""
var dateApp = "" var dateApp = ""
var background : Bitmap? = null
var dominantColor = 0 var dominantColor = 0
var vibrantColor = 0 var vibrantColor = 0
@ -137,62 +141,6 @@ fun View.blink(
}) })
} }
fun View.fadeIn(duration: Long = 300L) {
startAnimation(AlphaAnimation(0f, 1f).also {
it.interpolator = DecelerateInterpolator()
it.duration = duration
})
}
fun View.fadeOut(duration: Long = 300L) {
startAnimation(AlphaAnimation(1f, 0f).also {
it.interpolator = DecelerateInterpolator()
it.duration = duration
})
}
fun View.fadeRotateIn(duration: Long = 500L) {
val combined = AnimationSet(false)
combined.addAnimation(
AlphaAnimation(0f, 1F).also {
it.interpolator = DecelerateInterpolator()
it.duration = duration
}
)
combined.addAnimation(
RotateAnimation(
0F, 180F, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f
).also {
it.duration = duration * 2
it.interpolator = DecelerateInterpolator()
}
)
startAnimation(combined)
}
fun View.fadeRotateOut(duration: Long = 500L) {
val combined = AnimationSet(false)
combined.addAnimation(
AlphaAnimation(1F, 0F).also {
it.interpolator = AccelerateInterpolator()
it.duration = duration
}
)
combined.addAnimation(
RotateAnimation(
0F, 180F, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f
).also {
it.duration = duration
it.interpolator = AccelerateInterpolator()
}
)
startAnimation(combined)
}
/* Activity related */ /* Activity related */
fun isInstalled(uri: String, context: Context): Boolean { fun isInstalled(uri: String, context: Context): Boolean {
@ -201,7 +149,7 @@ fun isInstalled(uri: String, context: Context): Boolean {
try { try {
context.packageManager.getPackageInfo(uri, PackageManager.GET_ACTIVITIES) context.packageManager.getPackageInfo(uri, PackageManager.GET_ACTIVITIES)
return true return true
} catch (e: PackageManager.NameNotFoundException) { } catch (_: PackageManager.NameNotFoundException) {
} }
return false return false
} }
@ -212,17 +160,6 @@ private fun getIntent(packageName: String, context: Context): Intent? {
return intent return intent
} }
fun canReachSettings(): Boolean {
var availableActions = ACTIONS;
if(!launcherPreferences.getBoolean(PREF_DOUBLE_ACTIONS_ENABLED, false)){
availableActions = listOf(
ACTION_UP, ACTION_DOWN, ACTION_RIGHT, ACTION_LEFT, ACTION_VOL_UP,
ACTION_VOL_DOWN, ACTION_DOUBLE_CLICK, ACTION_LONG_CLICK, ACTION_DATE, ACTION_TIME
)
}
return availableActions.contains("launcher:settings") || availableActions.contains("launcher:choose")
}
fun launch( fun launch(
data: String, activity: Activity, data: String, activity: Activity,
animationIn: Int = android.R.anim.fade_in, animationOut: Int = android.R.anim.fade_out animationIn: Int = android.R.anim.fade_in, animationOut: Int = android.R.anim.fade_out
@ -246,22 +183,19 @@ fun launch(
/* Media player actions */ /* Media player actions */
fun audioNextTrack(activity: Activity) { fun audioNextTrack(activity: Activity) {
if (Build.VERSION.SDK_INT >= 19) { // requires Android KitKat +
val mAudioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager val mAudioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val eventTime: Long = SystemClock.uptimeMillis() val eventTime: Long = SystemClock.uptimeMillis()
val downEvent = val downEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
mAudioManager.dispatchMediaKeyEvent(downEvent) mAudioManager.dispatchMediaKeyEvent(downEvent)
val upEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0) val upEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0)
mAudioManager.dispatchMediaKeyEvent(upEvent) mAudioManager.dispatchMediaKeyEvent(upEvent)
} }
}
fun audioPreviousTrack(activity: Activity) { fun audioPreviousTrack(activity: Activity) {
if (Build.VERSION.SDK_INT >= 19) { // requires Android KitKat +
val mAudioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager val mAudioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val eventTime: Long = SystemClock.uptimeMillis() val eventTime: Long = SystemClock.uptimeMillis()
@ -273,7 +207,6 @@ fun audioPreviousTrack(activity: Activity) {
val upEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0) val upEvent = KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0)
mAudioManager.dispatchMediaKeyEvent(upEvent) mAudioManager.dispatchMediaKeyEvent(upEvent)
} }
}
fun audioVolumeUp(activity: Activity) { fun audioVolumeUp(activity: Activity) {
val audioManager = val audioManager =
@ -313,14 +246,14 @@ fun launchApp(packageName: String, context: Context) {
) )
.setTitle(context.getString(R.string.alert_cant_open_title)) .setTitle(context.getString(R.string.alert_cant_open_title))
.setMessage(context.getString(R.string.alert_cant_open_message)) .setMessage(context.getString(R.string.alert_cant_open_message))
.setPositiveButton(android.R.string.yes, .setPositiveButton(android.R.string.ok
DialogInterface.OnClickListener { dialog, which -> ) { _, _ ->
openAppSettings( openAppSettings(
packageName, packageName,
context context
) )
}) }
.setNegativeButton(android.R.string.no, null) .setNegativeButton(android.R.string.cancel, null)
.setIcon(android.R.drawable.ic_dialog_info) .setIcon(android.R.drawable.ic_dialog_info)
.show() .show()
} else { } else {
@ -344,7 +277,7 @@ fun openNewTabWindow(urls: String, context: Context) {
/* Settings related functions */ /* Settings related functions */
fun getSavedTheme(context: Context) : String { fun getSavedTheme() : String {
return launcherPreferences.getString(PREF_THEME, "finn").toString() return launcherPreferences.getString(PREF_THEME, "finn").toString()
} }
@ -569,20 +502,6 @@ fun setSwitchColor(sw: Switch, trackColor: Int) {
} }
} }
// Taken from: https://stackoverflow.com/a/33072575/12787264
fun manipulateColor(color: Int, factor: Float): Int {
val a = Color.alpha(color)
val r = (Color.red(color) * factor).roundToInt()
val g = (Color.green(color) * factor).roundToInt()
val b = (Color.blue(color) * factor).roundToInt()
return Color.argb(
a,
r.coerceAtMost(255),
g.coerceAtMost(255),
b.coerceAtMost(255)
)
}
// Taken from: https://stackoverflow.com/a/30340794/12787264 // Taken from: https://stackoverflow.com/a/30340794/12787264
fun transformGrayscale(imageView: ImageView){ fun transformGrayscale(imageView: ImageView){
val matrix = ColorMatrix() val matrix = ColorMatrix()

View file

@ -2,20 +2,20 @@ package de.jrpie.android.launcher
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.AsyncTask import android.os.AsyncTask
import android.os.Bundle import android.os.Bundle
import android.provider.MediaStore import android.view.GestureDetector
import android.view.* import android.view.KeyEvent
import android.view.MotionEvent
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
import de.jrpie.android.launcher.BuildConfig.VERSION_NAME
import de.jrpie.android.launcher.tutorial.TutorialActivity import de.jrpie.android.launcher.tutorial.TutorialActivity
import kotlinx.android.synthetic.main.home.* import kotlinx.android.synthetic.main.home.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.concurrent.fixedRateTimer import kotlin.concurrent.fixedRateTimer
import kotlin.math.abs import kotlin.math.abs
import de.jrpie.android.launcher.BuildConfig.VERSION_NAME
/** /**
* [HomeActivity] is the actual application Launcher, * [HomeActivity] is the actual application Launcher,
@ -39,9 +39,6 @@ class HomeActivity: UIObject, AppCompatActivity(),
// timers // timers
private var clockTimer = Timer() private var clockTimer = Timer()
private var tooltipTimer = Timer()
private var settingsIconShown = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -69,7 +66,7 @@ class HomeActivity: UIObject, AppCompatActivity(),
* were not stored anywhere. Now they have to be stored: * were not stored anywhere. Now they have to be stored:
* -> we just reset them using newly implemented functions * -> we just reset them using newly implemented functions
*/ */
when (getSavedTheme(this)) { when (getSavedTheme()) {
"finn" -> resetToDefaultTheme(this) "finn" -> resetToDefaultTheme(this)
"dark" -> resetToDarkTheme(this) "dark" -> resetToDarkTheme(this)
} }
@ -131,12 +128,12 @@ class HomeActivity: UIObject, AppCompatActivity(),
} }
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK) { when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
launch("launcher:choose", this) } launch("launcher:choose", this) }
else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) KeyEvent.KEYCODE_VOLUME_UP -> launch(volumeUpApp, this,0, 0)
launch(volumeUpApp, this,0, 0) KeyEvent.KEYCODE_VOLUME_DOWN -> launch(volumeDownApp, this,0, 0)
else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) }
launch(volumeDownApp, this,0, 0)
return true return true
} }
@ -212,14 +209,14 @@ class HomeActivity: UIObject, AppCompatActivity(),
override fun setOnClicks() { override fun setOnClicks() {
home_upper_view.setOnClickListener() { home_upper_view.setOnClickListener {
when (launcherPreferences.getInt(PREF_DATE_FORMAT, 0)) { when (launcherPreferences.getInt(PREF_DATE_FORMAT, 0)) {
0 -> launch(dateApp, this) 0 -> launch(dateApp, this)
else -> launch(timeApp,this) else -> launch(timeApp,this)
} }
} }
home_lower_view.setOnClickListener() { home_lower_view.setOnClickListener {
when (launcherPreferences.getInt(PREF_DATE_FORMAT, 0)) { when (launcherPreferences.getInt(PREF_DATE_FORMAT, 0)) {
0 -> launch(timeApp, this) 0 -> launch(timeApp, this)
else -> launch(dateApp,this) else -> launch(dateApp,this)

View file

@ -1,7 +1,6 @@
package de.jrpie.android.launcher package de.jrpie.android.launcher
import android.app.Activity import android.app.Activity
import android.view.WindowManager
/** /**
* An interface implemented by every [Activity], Fragment etc. in Launcher. * An interface implemented by every [Activity], Fragment etc. in Launcher.

View file

@ -1,24 +1,26 @@
package de.jrpie.android.launcher.list package de.jrpie.android.launcher.list
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager.widget.ViewPager
import de.jrpie.android.launcher.*
import de.jrpie.android.launcher.settings.intendedSettingsPause
import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.list.*
import android.content.Context
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_UNINSTALL
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.launch
import de.jrpie.android.launcher.list.apps.ListFragmentApps import de.jrpie.android.launcher.list.apps.ListFragmentApps
import de.jrpie.android.launcher.list.other.ListFragmentOther import de.jrpie.android.launcher.list.other.ListFragmentOther
import kotlinx.android.synthetic.main.home.* import de.jrpie.android.launcher.settings.intendedSettingsPause
import kotlinx.android.synthetic.main.list_apps.* import de.jrpie.android.launcher.vibrantColor
import kotlinx.android.synthetic.main.list.*
var intendedChoosePause = false // know when to close var intendedChoosePause = false // know when to close
@ -41,7 +43,7 @@ class ListActivity : AppCompatActivity(), UIObject {
// Initialise layout // Initialise layout
setContentView(R.layout.list) setContentView(R.layout.list)
list_settings.setOnClickListener() { list_settings.setOnClickListener {
launch("launcher:settings", this, R.anim.bottom_up) launch("launcher:settings", this, R.anim.bottom_up)
} }
} }
@ -82,7 +84,7 @@ class ListActivity : AppCompatActivity(), UIObject {
} }
override fun setOnClicks() { override fun setOnClicks() {
list_close.setOnClickListener() { finish() } list_close.setOnClickListener { finish() }
} }
override fun adjustLayout() { override fun adjustLayout() {
@ -127,12 +129,12 @@ class ListSectionsPagerAdapter(private val context: Context, fm: FragmentManager
override fun getItem(position: Int): Fragment { override fun getItem(position: Int): Fragment {
return when (position){ return when (position){
0 -> ListFragmentApps() 0 -> ListFragmentApps()
1 -> de.jrpie.android.launcher.list.other.ListFragmentOther() 1 -> ListFragmentOther()
else -> Fragment() else -> Fragment()
} }
} }
override fun getPageTitle(position: Int): CharSequence? { override fun getPageTitle(position: Int): CharSequence {
return context.resources.getString(TAB_TITLES[position]) return context.resources.getString(TAB_TITLES[position])
} }

View file

@ -3,7 +3,6 @@ package de.jrpie.android.launcher.list.apps
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.AsyncTask import android.os.AsyncTask
import android.view.LayoutInflater import android.view.LayoutInflater
@ -14,10 +13,19 @@ import android.widget.ImageView
import android.widget.PopupMenu import android.widget.PopupMenu
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import de.jrpie.android.launcher.* import de.jrpie.android.launcher.PREF_SEARCH_AUTO_LAUNCH
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.REQUEST_UNINSTALL
import de.jrpie.android.launcher.appsList
import de.jrpie.android.launcher.getSavedTheme
import de.jrpie.android.launcher.launch
import de.jrpie.android.launcher.launcherPreferences
import de.jrpie.android.launcher.list.intendedChoosePause import de.jrpie.android.launcher.list.intendedChoosePause
import de.jrpie.android.launcher.loadApps
import de.jrpie.android.launcher.openAppSettings
import de.jrpie.android.launcher.transformGrayscale
import java.util.* import java.util.*
import kotlin.collections.ArrayList
/** /**
* A [RecyclerView] (efficient scrollable list) containing all apps on the users device. * A [RecyclerView] (efficient scrollable list) containing all apps on the users device.
@ -37,7 +45,7 @@ class AppsRecyclerAdapter(val activity: Activity,
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener { View.OnClickListener {
var textView: TextView = itemView.findViewById(R.id.list_apps_row_name) var textView: TextView = itemView.findViewById(R.id.list_apps_row_name)
var img: ImageView = itemView.findViewById(R.id.list_apps_row_icon) as ImageView var img: ImageView = itemView.findViewById(R.id.list_apps_row_icon)
var menuDots: ImageView = itemView.findViewById(R.id.list_apps_row_menu) var menuDots: ImageView = itemView.findViewById(R.id.list_apps_row_menu)
override fun onClick(v: View) { override fun onClick(v: View) {
@ -73,7 +81,7 @@ class AppsRecyclerAdapter(val activity: Activity,
viewHolder.textView.text = appLabel viewHolder.textView.text = appLabel
viewHolder.img.setImageDrawable(appIcon) viewHolder.img.setImageDrawable(appIcon)
if (getSavedTheme(activity) == "dark") transformGrayscale( if (getSavedTheme() == "dark") transformGrayscale(
viewHolder.img viewHolder.img
) )
@ -95,6 +103,7 @@ class AppsRecyclerAdapter(val activity: Activity,
} }
} }
@Suppress("SameReturnValue")
private fun showOptionsPopup(viewHolder: ViewHolder, appPackageName: String): Boolean { private fun showOptionsPopup(viewHolder: ViewHolder, appPackageName: String): Boolean {
//create the popup menu //create the popup menu
@ -163,10 +172,10 @@ class AppsRecyclerAdapter(val activity: Activity,
if (text.isEmpty()) { if (text.isEmpty()) {
appsListDisplayed.addAll(appsList) appsListDisplayed.addAll(appsList)
} else { } else {
var appsSecondary: MutableList<AppInfo> = ArrayList(); val appsSecondary: MutableList<AppInfo> = ArrayList()
var normalizedText: String = normalize(text); val normalizedText: String = normalize(text)
for (item in appsList) { for (item in appsList) {
var itemLabel: String = normalize(item.label.toString()); val itemLabel: String = normalize(item.label.toString())
if (itemLabel.startsWith(normalizedText)) { if (itemLabel.startsWith(normalizedText)) {
appsListDisplayed.add(item) appsListDisplayed.add(item)
@ -174,7 +183,7 @@ class AppsRecyclerAdapter(val activity: Activity,
appsSecondary.add(item) appsSecondary.add(item)
} }
} }
appsListDisplayed.addAll(appsSecondary); appsListDisplayed.addAll(appsSecondary)
} }
// Launch apps automatically if only one result is found and the user wants it // Launch apps automatically if only one result is found and the user wants it

View file

@ -6,10 +6,13 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import de.jrpie.android.launcher.* import de.jrpie.android.launcher.PREF_SEARCH_AUTO_KEYBOARD
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.launcherPreferences
import de.jrpie.android.launcher.list.forApp import de.jrpie.android.launcher.list.forApp
import de.jrpie.android.launcher.list.intention import de.jrpie.android.launcher.list.intention
import kotlinx.android.synthetic.main.list.* import de.jrpie.android.launcher.openSoftKeyboard
import kotlinx.android.synthetic.main.list_apps.* import kotlinx.android.synthetic.main.list_apps.*
@ -53,12 +56,12 @@ class ListFragmentApps : Fragment(), UIObject {
androidx.appcompat.widget.SearchView.OnQueryTextListener { androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {
appsRViewAdapter.filter(query); appsRViewAdapter.filter(query)
return false return false
} }
override fun onQueryTextChange(newText: String): Boolean { override fun onQueryTextChange(newText: String): Boolean {
appsRViewAdapter.filter(newText); appsRViewAdapter.filter(newText)
return false return false
} }
}) })

View file

@ -7,8 +7,6 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.dominantColor
import de.jrpie.android.launcher.getSavedTheme
import kotlinx.android.synthetic.main.list_other.* import kotlinx.android.synthetic.main.list_other.*
/** /**
@ -29,7 +27,7 @@ class ListFragmentOther : Fragment() {
override fun onStart() { override fun onStart() {
// set up the list / recycler // set up the list / recycler
val viewManager = LinearLayoutManager(context) val viewManager = LinearLayoutManager(context)
val viewAdapter = de.jrpie.android.launcher.list.other.OtherRecyclerAdapter(activity!!) val viewAdapter = OtherRecyclerAdapter(activity!!)
list_other_rview.apply { list_other_rview.apply {
// improve performance (since content changes don't change the layout size) // improve performance (since content changes don't change the layout size)

View file

@ -8,8 +8,7 @@ package de.jrpie.android.launcher.list.other
* *
* @param data - a string identifying the thing to be launched * @param data - a string identifying the thing to be launched
*/ */
class OtherInfo(label: String, data: String, icon: Int) { class OtherInfo(label: String, data: String, var icon: Int) {
var label: CharSequence? = label var label: CharSequence? = label
var data: CharSequence? = data var data: CharSequence? = data
var icon: Int = icon
} }

View file

@ -23,7 +23,7 @@ import de.jrpie.android.launcher.list.forApp
class OtherRecyclerAdapter(val activity: Activity): class OtherRecyclerAdapter(val activity: Activity):
RecyclerView.Adapter<OtherRecyclerAdapter.ViewHolder>() { RecyclerView.Adapter<OtherRecyclerAdapter.ViewHolder>() {
private val othersList: MutableList<OtherInfo> private val othersList: MutableList<OtherInfo> = ArrayList()
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener { View.OnClickListener {
@ -58,7 +58,6 @@ class OtherRecyclerAdapter(val activity: Activity):
} }
init { init {
othersList = ArrayList()
othersList.add( othersList.add(
OtherInfo(activity.getString(R.string.list_other_settings), OtherInfo(activity.getString(R.string.list_other_settings),
"launcher:settings", "launcher:settings",
@ -98,7 +97,7 @@ class OtherRecyclerAdapter(val activity: Activity):
} }
} }
private fun returnChoiceIntent(forAction: String, value: String) { private fun returnChoiceIntent(forApp: String, value: String) {
val returnIntent = Intent() val returnIntent = Intent()
returnIntent.putExtra("value", value) returnIntent.putExtra("value", value)
returnIntent.putExtra("forApp", forApp) returnIntent.putExtra("forApp", forApp)

View file

@ -67,7 +67,7 @@ class SettingsActivity: AppCompatActivity(), UIObject {
override fun setOnClicks(){ override fun setOnClicks(){
// As older APIs somehow do not recognize the xml defined onClick // As older APIs somehow do not recognize the xml defined onClick
settings_close.setOnClickListener() { finish() } settings_close.setOnClickListener { finish() }
// open device settings (see https://stackoverflow.com/a/62092663/12787264) // open device settings (see https://stackoverflow.com/a/62092663/12787264)
settings_system.setOnClickListener { settings_system.setOnClickListener {
intendedSettingsPause = true intendedSettingsPause = true
@ -101,7 +101,7 @@ class SettingsSectionsPagerAdapter(private val context: Context, fm: FragmentMan
} }
} }
override fun getPageTitle(position: Int): CharSequence? { override fun getPageTitle(position: Int): CharSequence {
return context.resources.getString(TAB_TITLES[position]) return context.resources.getString(TAB_TITLES[position])
} }

View file

@ -7,8 +7,5 @@ package de.jrpie.android.launcher.settings.actions
* *
* @param data - a string identifying the app / action / intent to be launched * @param data - a string identifying the app / action / intent to be launched
*/ */
class ActionInfo(actionText: CharSequence, actionName: CharSequence, data: CharSequence) { class ActionInfo(val actionText: CharSequence, val actionName: CharSequence, val data: CharSequence) {
val actionName: CharSequence? = actionName
val actionText: CharSequence? = actionText
val data: CharSequence? = data
} }

View file

@ -60,7 +60,7 @@ class ActionsRecyclerAdapter(val activity: Activity):
View.OnClickListener { View.OnClickListener {
var textView: TextView = itemView.findViewById(R.id.settings_actions_row_name) var textView: TextView = itemView.findViewById(R.id.settings_actions_row_name)
var actionIcon: ImageView = itemView.findViewById(R.id.settings_actions_row_icon) var actionIcon: ImageView = itemView.findViewById(R.id.settings_actions_row_icon)
var img: ImageView = itemView.findViewById(R.id.settings_actions_row_icon_img) as ImageView var img: ImageView = itemView.findViewById(R.id.settings_actions_row_icon_img)
var chooseButton: Button = itemView.findViewById(R.id.settings_actions_row_button_choose) var chooseButton: Button = itemView.findViewById(R.id.settings_actions_row_button_choose)
var removeAction: ImageView = itemView.findViewById(R.id.settings_actions_row_remove) var removeAction: ImageView = itemView.findViewById(R.id.settings_actions_row_remove)
@ -93,7 +93,7 @@ class ActionsRecyclerAdapter(val activity: Activity):
setButtonColor(viewHolder.chooseButton, vibrantColor) setButtonColor(viewHolder.chooseButton, vibrantColor)
} }
if (content!!.startsWith("launcher")) { if (content.startsWith("launcher")) {
// Set fontAwesome icon // Set fontAwesome icon
viewHolder.actionIcon.visibility = View.VISIBLE viewHolder.actionIcon.visibility = View.VISIBLE
viewHolder.actionIcon.setOnClickListener{ chooseApp(actionName.toString()) } viewHolder.actionIcon.setOnClickListener{ chooseApp(actionName.toString()) }
@ -118,7 +118,7 @@ class ActionsRecyclerAdapter(val activity: Activity):
viewHolder.img.setImageDrawable(activity.packageManager.getApplicationIcon(content.toString())) viewHolder.img.setImageDrawable(activity.packageManager.getApplicationIcon(content.toString()))
viewHolder.img.setOnClickListener{ chooseApp(actionName.toString()) } viewHolder.img.setOnClickListener{ chooseApp(actionName.toString()) }
if (getSavedTheme(activity) == "dark") transformGrayscale( if (getSavedTheme() == "dark") transformGrayscale(
viewHolder.img viewHolder.img
) )

View file

@ -1,28 +1,33 @@
package de.jrpie.android.launcher.settings.launcher package de.jrpie.android.launcher.settings.launcher
import android.Manifest
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.MediaStore
import android.text.TextUtils
import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.palette.graphics.Palette import de.jrpie.android.launcher.PREF_DATE_FORMAT
import de.jrpie.android.launcher.* import de.jrpie.android.launcher.PREF_DOUBLE_ACTIONS_ENABLED
import de.jrpie.android.launcher.PREF_SCREEN_FULLSCREEN
import de.jrpie.android.launcher.PREF_SCREEN_TIMEOUT_DISABLED
import de.jrpie.android.launcher.PREF_SEARCH_AUTO_KEYBOARD
import de.jrpie.android.launcher.PREF_SEARCH_AUTO_LAUNCH
import de.jrpie.android.launcher.PREF_SLIDE_SENSITIVITY
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.getSavedTheme
import de.jrpie.android.launcher.launcherPreferences
import de.jrpie.android.launcher.resetToDarkTheme
import de.jrpie.android.launcher.resetToDefaultTheme
import de.jrpie.android.launcher.setButtonColor
import de.jrpie.android.launcher.setSwitchColor
import de.jrpie.android.launcher.setWindowFlags
import de.jrpie.android.launcher.settings.intendedSettingsPause import de.jrpie.android.launcher.settings.intendedSettingsPause
import de.jrpie.android.launcher.vibrantColor
import kotlinx.android.synthetic.main.settings_launcher.* import kotlinx.android.synthetic.main.settings_launcher.*
@ -55,7 +60,7 @@ class SettingsFragmentLauncher : Fragment(), UIObject {
setSwitchColor(settings_launcher_switch_enable_double, vibrantColor) setSwitchColor(settings_launcher_switch_enable_double, vibrantColor)
setButtonColor(settings_launcher_button_choose_wallpaper, vibrantColor) setButtonColor(settings_launcher_button_choose_wallpaper, vibrantColor)
settings_seekbar_sensitivity.progressDrawable.setColorFilter(vibrantColor, PorterDuff.Mode.SRC_IN); settings_seekbar_sensitivity.progressDrawable.setColorFilter(vibrantColor, PorterDuff.Mode.SRC_IN)
} }
override fun setOnClicks() { override fun setOnClicks() {
@ -66,7 +71,7 @@ class SettingsFragmentLauncher : Fragment(), UIObject {
//.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) //.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.putExtra("com.android.wallpaper.LAUNCH_SOURCE", "app_launched_launcher") .putExtra("com.android.wallpaper.LAUNCH_SOURCE", "app_launched_launcher")
.putExtra("com.android.launcher3.WALLPAPER_FLAVOR", "focus_wallpaper") .putExtra("com.android.launcher3.WALLPAPER_FLAVOR", "focus_wallpaper")
startActivity(intent); startActivity(intent)
} }
settings_launcher_switch_screen_timeout.isChecked = launcherPreferences.getBoolean(PREF_SCREEN_TIMEOUT_DISABLED, false) settings_launcher_switch_screen_timeout.isChecked = launcherPreferences.getBoolean(PREF_SCREEN_TIMEOUT_DISABLED, false)
@ -123,12 +128,6 @@ class SettingsFragmentLauncher : Fragment(), UIObject {
) )
} }
fun resetToCustomTheme(context: Activity) {
intendedSettingsPause = true
saveTheme("custom") // TODO: Fix the bug this creates (displays custom theme without chosen img)
}
override fun adjustLayout() { override fun adjustLayout() {
// Load values into the date-format spinner // Load values into the date-format spinner
@ -159,19 +158,19 @@ class SettingsFragmentLauncher : Fragment(), UIObject {
staticThemeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) staticThemeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
settings_launcher_theme_spinner.adapter = staticThemeAdapter settings_launcher_theme_spinner.adapter = staticThemeAdapter
val themeInt = when (getSavedTheme(activity!!)) { val themeInt = when (getSavedTheme()) {
"finn" -> 0 "finn" -> 0
"dark" -> 1 "dark" -> 1
else -> 0 else -> 0
}; }
settings_launcher_theme_spinner.setSelection(themeInt) settings_launcher_theme_spinner.setSelection(themeInt)
settings_launcher_theme_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { settings_launcher_theme_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
when (position) { when (position) {
0 -> if (getSavedTheme(activity!!) != "finn") resetToDefaultTheme(activity!!) 0 -> if (getSavedTheme() != "finn") resetToDefaultTheme(activity!!)
1 -> if (getSavedTheme(activity!!) != "dark") resetToDarkTheme(activity!!) 1 -> if (getSavedTheme() != "dark") resetToDarkTheme(activity!!)
} }
} }
override fun onNothingSelected(parent: AdapterView<*>?) { } override fun onNothingSelected(parent: AdapterView<*>?) { }

View file

@ -1,20 +1,22 @@
package de.jrpie.android.launcher.settings.meta package de.jrpie.android.launcher.settings.meta
import android.app.AlertDialog import android.app.AlertDialog
import android.content.ActivityNotFoundException
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import de.jrpie.android.launcher.* import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.tutorial.TutorialActivity import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.openNewTabWindow
import de.jrpie.android.launcher.resetSettings
import de.jrpie.android.launcher.setButtonColor
import de.jrpie.android.launcher.settings.intendedSettingsPause import de.jrpie.android.launcher.settings.intendedSettingsPause
import de.jrpie.android.launcher.tutorial.TutorialActivity
import de.jrpie.android.launcher.vibrantColor
import kotlinx.android.synthetic.main.settings_meta.* import kotlinx.android.synthetic.main.settings_meta.*
/** /**

View file

@ -1,18 +1,26 @@
package de.jrpie.android.launcher.tutorial package de.jrpie.android.launcher.tutorial
import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.*
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import de.jrpie.android.launcher.*
import de.jrpie.android.launcher.tutorial.tabs.*
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.tutorial.* import de.jrpie.android.launcher.PREF_STARTED
import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.UIObject
import de.jrpie.android.launcher.launcherPreferences
import de.jrpie.android.launcher.loadSettings
import de.jrpie.android.launcher.resetSettings
import de.jrpie.android.launcher.saveListActivityChoice
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentConcept
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentFinish
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentSetup
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentStart
import de.jrpie.android.launcher.tutorial.tabs.TutorialFragmentUsage
/** /**
* The [TutorialActivity] is displayed automatically on new installations. * The [TutorialActivity] is displayed automatically on new installations.
@ -36,7 +44,7 @@ class TutorialActivity: AppCompatActivity(), UIObject {
loadSettings() loadSettings()
// set up tabs and swiping in settings // set up tabs and swiping in settings
val sectionsPagerAdapter = TutorialSectionsPagerAdapter(this, supportFragmentManager) val sectionsPagerAdapter = TutorialSectionsPagerAdapter(supportFragmentManager)
val viewPager: ViewPager = findViewById(R.id.tutorial_viewpager) val viewPager: ViewPager = findViewById(R.id.tutorial_viewpager)
viewPager.adapter = sectionsPagerAdapter viewPager.adapter = sectionsPagerAdapter
val tabs: TabLayout = findViewById(R.id.tutorial_tabs) val tabs: TabLayout = findViewById(R.id.tutorial_tabs)
@ -69,7 +77,7 @@ class TutorialActivity: AppCompatActivity(), UIObject {
* *
* Tabs: (Start | Concept | Usage | Setup | Finish) * Tabs: (Start | Concept | Usage | Setup | Finish)
*/ */
class TutorialSectionsPagerAdapter(private val context: Context, fm: FragmentManager) class TutorialSectionsPagerAdapter(fm: FragmentManager)
: FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment { override fun getItem(position: Int): Fragment {
@ -84,6 +92,6 @@ class TutorialSectionsPagerAdapter(private val context: Context, fm: FragmentMan
} }
/* We don't use titles here, as we have the dots */ /* We don't use titles here, as we have the dots */
override fun getPageTitle(position: Int): CharSequence? { return "" } override fun getPageTitle(position: Int): CharSequence { return "" }
override fun getCount(): Int { return 5 } override fun getCount(): Int { return 5 }
} }

View file

@ -1,19 +1,19 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import de.jrpie.android.launcher.* import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.tutorial_concept.* import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject
/** /**
* The [TutorialFragmentConcept] is a used as a tab in the TutorialActivity. * The [TutorialFragmentConcept] is a used as a tab in the TutorialActivity.
* *
* It is used to display info about Launchers concept (open source, efficiency ...) * It is used to display info about Launchers concept (open source, efficiency ...)
*/ */
class TutorialFragmentConcept(): Fragment(), UIObject { class TutorialFragmentConcept : Fragment(), UIObject {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,

View file

@ -14,7 +14,7 @@ import kotlinx.android.synthetic.main.tutorial_finish.*
* *
* It is used to display further resources and let the user start Launcher * It is used to display further resources and let the user start Launcher
*/ */
class TutorialFragmentFinish(): Fragment(), UIObject { class TutorialFragmentFinish : Fragment(), UIObject {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,

View file

@ -1,19 +1,19 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import de.jrpie.android.launcher.* import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.tutorial_setup.* import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.UIObject
/** /**
* The [TutorialFragmentSetup] is a used as a tab in the TutorialActivity. * The [TutorialFragmentSetup] is a used as a tab in the TutorialActivity.
* *
* It is used to display info in the tutorial * It is used to display info in the tutorial
*/ */
class TutorialFragmentSetup(): Fragment(), UIObject { class TutorialFragmentSetup : Fragment(), UIObject {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,

View file

@ -13,7 +13,7 @@ import kotlinx.android.synthetic.main.tutorial_start.*
* *
* It displays info about the app and gets the user into the tutorial * It displays info about the app and gets the user into the tutorial
*/ */
class TutorialFragmentStart(): Fragment(), UIObject { class TutorialFragmentStart : Fragment(), UIObject {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,

View file

@ -1,10 +1,10 @@
package de.jrpie.android.launcher.tutorial.tabs package de.jrpie.android.launcher.tutorial.tabs
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import de.jrpie.android.launcher.* import de.jrpie.android.launcher.*
import kotlinx.android.synthetic.main.tutorial_usage.* import kotlinx.android.synthetic.main.tutorial_usage.*
@ -13,7 +13,7 @@ import kotlinx.android.synthetic.main.tutorial_usage.*
* *
* Tells the user how his screen will look and how the app can be used * Tells the user how his screen will look and how the app can be used
*/ */
class TutorialFragmentUsage(): Fragment(), UIObject { class TutorialFragmentUsage : Fragment(), UIObject {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,

View file

@ -158,4 +158,7 @@
<string name="tutorial_finish_text">Du bist bereit loszulegen!\n\nIch hoffe diese App ist sehr wertvoll für dich!\n\n- Finn (der Entwickler)</string> <string name="tutorial_finish_text">Du bist bereit loszulegen!\n\nIch hoffe diese App ist sehr wertvoll für dich!\n\n- Finn (der Entwickler)</string>
<string name="tutorial_finish_button">Starten</string> <string name="tutorial_finish_button">Starten</string>
<string name="settings">Einstellungen</string>
<string name="ic_menu_alt">Mehr Optionen</string>
</resources> </resources>

View file

@ -181,4 +181,8 @@
<string name="tutorial_finish_text">Estás listo para iniciar!\n\n Esperamos que esto te sea de gran ayuda!\n\n- Finn M Glas\n(el desarrollador)</string> <string name="tutorial_finish_text">Estás listo para iniciar!\n\n Esperamos que esto te sea de gran ayuda!\n\n- Finn M Glas\n(el desarrollador)</string>
<string name="tutorial_finish_button">Iniciar</string> <string name="tutorial_finish_button">Iniciar</string>
<string name="settings">Configuración</string>
<string name="ic_menu_alt">Más opciones</string>
</resources> </resources>

View file

@ -160,4 +160,8 @@
<string name="tutorial_finish_text">Vous êtes prêt à commencer!\n\nJ\'espère que cette application vous sera très précieuse!\n\n- Finn M Glas\n(le développeur)</string> <string name="tutorial_finish_text">Vous êtes prêt à commencer!\n\nJ\'espère que cette application vous sera très précieuse!\n\n- Finn M Glas\n(le développeur)</string>
<string name="tutorial_finish_button">Ouvrir</string> <string name="tutorial_finish_button">Ouvrir</string>
<string name="settings">Réglages</string>
<string name="ic_menu_alt">Plus d\'options</string>
</resources> </resources>

View file

@ -121,7 +121,7 @@
<string name="settings_meta_reset">Reset Settings</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> <string name="settings_meta_reset_confirm">You are going to discard all your preferences. Continue?</string>
<string name="settings_meta_link_github">https://github.com/jrpie/Launcher</string> <string name="settings_meta_link_github" translatable="false">https://github.com/jrpie/Launcher</string>
<string name="settings_meta_report_bug">Report a bug</string> <string name="settings_meta_report_bug">Report a bug</string>
<string name="settings_meta_report_bug_link" translatable="false">https://github.com/jrpie/Launcher/issues/new</string> <string name="settings_meta_report_bug_link" translatable="false">https://github.com/jrpie/Launcher/issues/new</string>
@ -185,6 +185,11 @@
<string name="tutorial_finish_title">Let\'s go!</string> <string name="tutorial_finish_title">Let\'s go!</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)</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)</string>
<string name="tutorial_finish_button">Start</string> <string name="tutorial_finish_button">Start</string>
<string name="settings">Settings</string> <string name="settings">Settings</string>
<string name="ic_menu_alt">More options</string>
<string name="swipe" translatable="false"><![CDATA[>>>>>>]]></string>
</resources> </resources>