From 3d30dac6dc6b9bb30e6af8672923025f9f94f41a Mon Sep 17 00:00:00 2001 From: Jonas Wischeropp Date: Sun, 23 Jun 2024 21:23:03 +0200 Subject: [PATCH 1/3] Added ability to delay the launch of apps --- .../main/java/app/olauncher/data/Constants.kt | 3 + app/src/main/java/app/olauncher/data/Prefs.kt | 7 +++ .../java/app/olauncher/ui/AppDrawerAdapter.kt | 41 ++++++++++-- .../app/olauncher/ui/AppDrawerFragment.kt | 26 ++++++-- .../java/app/olauncher/ui/HomeFragment.kt | 24 +++++-- .../java/app/olauncher/ui/TimerFragment.kt | 63 +++++++++++++++++++ app/src/main/res/drawable/ic_delay_launch.xml | 12 ++++ .../main/res/layout/adapter_app_drawer.xml | 61 +++++++++++++++++- app/src/main/res/layout/fragment_timer.xml | 49 +++++++++++++++ app/src/main/res/navigation/nav_graph.xml | 34 +++++++++- app/src/main/res/values-de/strings.xml | 8 +++ app/src/main/res/values/strings.xml | 8 ++- 12 files changed, 315 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/app/olauncher/ui/TimerFragment.kt create mode 100644 app/src/main/res/drawable/ic_delay_launch.xml create mode 100644 app/src/main/res/layout/fragment_timer.xml diff --git a/app/src/main/java/app/olauncher/data/Constants.kt b/app/src/main/java/app/olauncher/data/Constants.kt index 10509a98..3d9efe0d 100644 --- a/app/src/main/java/app/olauncher/data/Constants.kt +++ b/app/src/main/java/app/olauncher/data/Constants.kt @@ -5,6 +5,9 @@ object Constants { object Key { const val FLAG = "flag" const val RENAME = "rename" + const val LAUNCH = "launch" + const val APP_NAME = "app_name" + const val LAUNCH_DELAY = "launch_delay" } object Dialog { diff --git a/app/src/main/java/app/olauncher/data/Prefs.kt b/app/src/main/java/app/olauncher/data/Prefs.kt index c281b8cf..1a82f1d8 100644 --- a/app/src/main/java/app/olauncher/data/Prefs.kt +++ b/app/src/main/java/app/olauncher/data/Prefs.kt @@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatDelegate class Prefs(context: Context) { private val PREFS_FILENAME = "app.olauncher" + private val LAUNCH_DELAYS_PREFS_FILENAME = "app.olauncher.launchdelays" private val FIRST_OPEN = "FIRST_OPEN" private val FIRST_OPEN_TIME = "FIRST_OPEN_TIME" @@ -88,6 +89,8 @@ class Prefs(context: Context) { private val CALENDAR_APP_CLASS_NAME = "CALENDAR_APP_CLASS_NAME" private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_FILENAME, 0); + private val launchDelayPrefs: SharedPreferences = + context.getSharedPreferences(LAUNCH_DELAYS_PREFS_FILENAME, 0) var firstOpen: Boolean get() = prefs.getBoolean(FIRST_OPEN, true) @@ -448,4 +451,8 @@ class Prefs(context: Context) { fun getAppRenameLabel(appPackage: String): String = prefs.getString(appPackage, "").toString() fun setAppRenameLabel(appPackage: String, renameLabel: String) = prefs.edit().putString(appPackage, renameLabel).apply() + + fun getAppLaunchDelay(appPackage: String): Int = launchDelayPrefs.getInt(appPackage, 0) + + fun setAppLaunchDelay(appPackage: String, time: Int) = launchDelayPrefs.edit().putInt(appPackage, time).apply() } \ No newline at end of file diff --git a/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt b/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt index 55dd9736..cacfe282 100644 --- a/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt +++ b/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt @@ -31,6 +31,7 @@ class AppDrawerAdapter( private val appDeleteListener: (AppModel) -> Unit, private val appHideListener: (AppModel, Int) -> Unit, private val appRenameListener: (AppModel, String) -> Unit, + private val appChangeLaunchDelayListener: (AppModel, Int) -> Unit, ) : ListAdapter(DIFF_CALLBACK), Filterable { companion object { @@ -67,7 +68,8 @@ class AppDrawerAdapter( appDeleteListener, appInfoListener, appHideListener, - appRenameListener + appRenameListener, + appChangeLaunchDelayListener ) } catch (e: Exception) { e.printStackTrace() @@ -152,10 +154,12 @@ class AppDrawerAdapter( appInfoListener: (AppModel) -> Unit, appHideListener: (AppModel, Int) -> Unit, appRenameListener: (AppModel, String) -> Unit, + appChangeLaunchDelayListener: (AppModel, Int) -> Unit, ) = with(binding) { appHideLayout.visibility = View.GONE renameLayout.visibility = View.GONE + changeLaunchDelayLayout.visibility = View.GONE appTitle.text = appModel.appLabel appTitle.gravity = appLabelGravity otherProfileIndicator.isVisible = appModel.user != myUserHandle @@ -184,12 +188,20 @@ class AppDrawerAdapter( etAppRename.imeOptions = EditorInfo.IME_ACTION_DONE; } } - etAppRename.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus -> - if (hasFocus) - appTitle.visibility = View.INVISIBLE - else - appTitle.visibility = View.VISIBLE + appDelayLaunch.setOnClickListener { + if (appModel.appPackage.isNotEmpty()) { + etLaunchDelay.setText("") + changeLaunchDelayLayout.visibility = View.VISIBLE + renameLayout.visibility = View.GONE + appHideLayout.visibility = View.GONE + etLaunchDelay.showKeyboard() + } + } + val onFocusChangeListener = View.OnFocusChangeListener {_, hasFocus -> + appTitle.visibility = if (hasFocus) View.INVISIBLE else View.VISIBLE } + etAppRename.onFocusChangeListener = onFocusChangeListener + etLaunchDelay.onFocusChangeListener = onFocusChangeListener etAppRename.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { etAppRename.hint = getAppName(etAppRename.context, appModel.appPackage) @@ -240,6 +252,23 @@ class AppDrawerAdapter( renameLayout.visibility = View.GONE } } + val stopLaunchDelayModification = { + val input = etLaunchDelay.text.toString() + val seconds = if (input.isEmpty()) 0 else input.toInt() + appChangeLaunchDelayListener(appModel, seconds) + changeLaunchDelayLayout.visibility = View.GONE + } + etLaunchDelay.setOnEditorActionListener { _, actionCode, _ -> + if (actionCode == EditorInfo.IME_ACTION_DONE) { + stopLaunchDelayModification() + true + } + false + } + tvSaveLaunchDelay.setOnClickListener { + etLaunchDelay.hideKeyboard() + stopLaunchDelayModification() + } appInfo.setOnClickListener { appInfoListener(appModel) } appDelete.setOnClickListener { appDeleteListener(appModel) } appHideLayout.setOnClickListener { appHideLayout.visibility = View.GONE } diff --git a/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt b/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt index b6a766a6..b69ea142 100644 --- a/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt +++ b/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt @@ -7,6 +7,7 @@ import android.view.ViewGroup import android.view.animation.AnimationUtils import android.widget.TextView import androidx.appcompat.widget.SearchView +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController @@ -107,11 +108,25 @@ class AppDrawerFragment : Fragment() { appClickListener = { if (it.appPackage.isEmpty()) return@AppDrawerAdapter - viewModel.selectedApp(it, flag) - if (flag == Constants.FLAG_LAUNCH_APP || flag == Constants.FLAG_HIDDEN_APPS) - findNavController().popBackStack(R.id.mainFragment, false) + val launch = { + viewModel.selectedApp(it, flag) + if (flag == Constants.FLAG_LAUNCH_APP || flag == Constants.FLAG_HIDDEN_APPS) + findNavController().popBackStack(R.id.mainFragment, false) + else + findNavController().popBackStack() + } + val launchDelay = prefs.getAppLaunchDelay(it.appPackage) + if ((flag == Constants.FLAG_LAUNCH_APP || flag == Constants.FLAG_HIDDEN_APPS) && launchDelay > 0) + findNavController().navigate( + R.id.action_appListFragment_to_timerFragment, + bundleOf( + Constants.Key.LAUNCH to launch, + Constants.Key.LAUNCH_DELAY to launchDelay, + Constants.Key.APP_NAME to it.appLabel + ) + ) else - findNavController().popBackStack() + launch() }, appInfoListener = { openAppInfo( @@ -155,6 +170,9 @@ class AppDrawerFragment : Fragment() { appRenameListener = { appModel, renameLabel -> prefs.setAppRenameLabel(appModel.appPackage, renameLabel) viewModel.getAppList() + }, + appChangeLaunchDelayListener = { appModel, startDelay -> + prefs.setAppLaunchDelay(appModel.appPackage, startDelay) } ) diff --git a/app/src/main/java/app/olauncher/ui/HomeFragment.kt b/app/src/main/java/app/olauncher/ui/HomeFragment.kt index e64ecd4d..89b994c6 100644 --- a/app/src/main/java/app/olauncher/ui/HomeFragment.kt +++ b/app/src/main/java/app/olauncher/ui/HomeFragment.kt @@ -327,16 +327,30 @@ class HomeFragment : Fragment(), View.OnClickListener, View.OnLongClickListener } private fun launchApp(appName: String, packageName: String, activityClassName: String?, userString: String) { - viewModel.selectedApp( - AppModel( + val launch = { + viewModel.selectedApp( + AppModel( appName, null, packageName, activityClassName, getUserHandleFromString(requireContext(), userString) - ), - Constants.FLAG_LAUNCH_APP - ) + ), + Constants.FLAG_LAUNCH_APP + ) + } + val launchDelay = prefs.getAppLaunchDelay(packageName) + if (launchDelay > 0) + findNavController().navigate( + R.id.action_mainFragment_to_timerFragment, + bundleOf( + Constants.Key.LAUNCH to launch, + Constants.Key.LAUNCH_DELAY to launchDelay, + Constants.Key.APP_NAME to appName + ) + ) + else + launch() } private fun showAppList(flag: Int, rename: Boolean = false, includeHiddenApps: Boolean = false) { diff --git a/app/src/main/java/app/olauncher/ui/TimerFragment.kt b/app/src/main/java/app/olauncher/ui/TimerFragment.kt new file mode 100644 index 00000000..a89fa58d --- /dev/null +++ b/app/src/main/java/app/olauncher/ui/TimerFragment.kt @@ -0,0 +1,63 @@ +package app.olauncher.ui + +import android.os.Bundle +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextWatcher +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import androidx.activity.OnBackPressedCallback +import androidx.core.view.isVisible +import androidx.navigation.fragment.findNavController +import app.olauncher.R +import app.olauncher.data.Constants +import app.olauncher.data.Prefs +import app.olauncher.databinding.FragmentTimerBinding +import app.olauncher.helper.hideKeyboard +import app.olauncher.helper.isSystemApp +import app.olauncher.helper.showKeyboard + +class TimerFragment : Fragment() { + private var _binding: FragmentTimerBinding? = null + private val binding get() = _binding!! + + private lateinit var timer: CountDownTimer + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = FragmentTimerBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val launchAction = arguments?.getSerializable(Constants.Key.LAUNCH) as () -> Unit + val launchDelay = arguments?.getInt(Constants.Key.LAUNCH_DELAY, 0)!! + val appName = arguments?.getString(Constants.Key.APP_NAME, "unknown")!! + + binding.appnameText.text = getString(R.string.launch_delay_question, appName) + + timer = object : CountDownTimer(launchDelay * 1000L, 1000L) { + override fun onTick(millisUntilFinish: Long) { + val secondsLeft = (millisUntilFinish + 999) / 1000 + binding.timeText.text = getString(R.string.launch_delay_launch_message, secondsLeft) + } + + override fun onFinish() { + launchAction() + } + } + timer.start() + + binding.cancel.setOnClickListener { + findNavController().navigate(R.id.action_timerFragment_to_mainFragment) + } + } + + override fun onStop() { + timer.cancel() + super.onStop() + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delay_launch.xml b/app/src/main/res/drawable/ic_delay_launch.xml new file mode 100644 index 00000000..4bdb4a04 --- /dev/null +++ b/app/src/main/res/drawable/ic_delay_launch.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/adapter_app_drawer.xml b/app/src/main/res/layout/adapter_app_drawer.xml index 9fe11754..a52a81ab 100644 --- a/app/src/main/res/layout/adapter_app_drawer.xml +++ b/app/src/main/res/layout/adapter_app_drawer.xml @@ -84,6 +84,21 @@ android:textSize="12sp" app:drawableTopCompat="@drawable/ic_hide" /> + + + android:visibility="gone"> + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_timer.xml b/app/src/main/res/layout/fragment_timer.xml new file mode 100644 index 00000000..cf9d4302 --- /dev/null +++ b/app/src/main/res/layout/fragment_timer.xml @@ -0,0 +1,49 @@ + + + + + + + + + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index d8bbc8c7..10934d35 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -24,6 +24,13 @@ app:exitAnim="@anim/fade_exit" app:popEnterAnim="@anim/fade_enter" app:popExitAnim="@anim/fade_exit" /> + + - - \ No newline at end of file + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 12865b01..c1b1f641 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -79,6 +79,8 @@ Verstecken Zeige Statusleiste Umbenennen + Verzögern + Übernehemen Datum und Uhrzeit anzeigen Aussehen Gesten @@ -121,9 +123,15 @@ App nach rechts wischen deaktiviert Benutzen Sie Ihr Telefon, oder nutzt Ihr Telefon Sie? Über Olauncher + Digitales Wohlbefinden Erfahren Sie mehr Wussten Sie? Rezension Olauncher ist und bleibt völlig kostenlos. Es gibt keine Werbung. Es werden keine Daten erfasst. Am wichtigsten ist, dass es Ihnen dabei hilft, Ihre Bildschirmzeit zu verkürzen und ein gesünderes digitales Leben zu führen. \n\nWir glauben, dass der Wechsel zu einem Minimal Launcher eine ausgezeichnete Entscheidung ist. Obwohl wir offensichtlich voreingenommen sind, hoffen wir, dass Ihnen die Erfahrung gefällt. Teilen Sie uns gerne Ihre Gedanken mit! + Ausrichtung geändert + Sekunden + Bist du sicher, dass du\n%1$s\nbenutzen möchtest? + Die app wird in\n%1$d\nSekunden geöffnet. + Abbrechen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76c6d653..72e926d6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -60,6 +60,8 @@ Hide Status bar on top Rename + Delay + Change Show date time Appearance Gestures @@ -144,4 +146,8 @@ Olauncher is free and always will be. It has no ads. It collects no data. Most importantly, it helps you in reducing your screen time and live a healthier digital life. \n\nWe believe that switching to a minimal launcher is an excellent decision. While we\'re obviously biased, we hope you\'re enjoying the experience. Feel free to share your thoughts with us! Alignment changed ✅ - \ No newline at end of file + Seconds + Are you sure you want to use\n%1$s? + The app will open in\n%1$d\nseconds. + Cancel + From cdabcbf5c8f497b7dcfc0588bab90c4b88c3d6b1 Mon Sep 17 00:00:00 2001 From: Jonas Wischeropp Date: Sun, 23 Jun 2024 21:47:42 +0200 Subject: [PATCH 2/3] App version bumped to 79 (v4.3.0) --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e31ba8e6..25e32df3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "app.olauncher" minSdkVersion 23 targetSdkVersion 33 - versionCode 78 - versionName "v4.2.2" + versionCode 79 + versionName "v4.3.0" resourceConfigurations += ["en", "ar", "de", "es-rES", "es-rUS", "fr", "hr", "hu", "in", "it", "ja", "pl", "pt-rBR", "ru-rRU", "sv", "tr", "uk", "zh"] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -62,4 +62,4 @@ dependencies { //Material dependency implementation 'com.google.android.material:material:1.9.0' -} \ No newline at end of file +} From 92ab1a98c2c3d7ca6b39b8da871df6c131899ced Mon Sep 17 00:00:00 2001 From: Jonas Wischeropp Date: Fri, 28 Jun 2024 11:51:55 +0200 Subject: [PATCH 3/3] fixed launcher crashes + empty seconds input will leave delay unchanged --- app/build.gradle | 4 ++-- app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt | 4 ++-- app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 25e32df3..0518986b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "app.olauncher" minSdkVersion 23 targetSdkVersion 33 - versionCode 79 - versionName "v4.3.0" + versionCode 80 + versionName "v4.3.1" resourceConfigurations += ["en", "ar", "de", "es-rES", "es-rUS", "fr", "hr", "hu", "in", "it", "ja", "pl", "pt-rBR", "ru-rRU", "sv", "tr", "uk", "zh"] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt b/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt index cacfe282..fd5dd435 100644 --- a/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt +++ b/app/src/main/java/app/olauncher/ui/AppDrawerAdapter.kt @@ -254,8 +254,8 @@ class AppDrawerAdapter( } val stopLaunchDelayModification = { val input = etLaunchDelay.text.toString() - val seconds = if (input.isEmpty()) 0 else input.toInt() - appChangeLaunchDelayListener(appModel, seconds) + if (input.isNotEmpty()) + appChangeLaunchDelayListener(appModel, input.toInt()) changeLaunchDelayLayout.visibility = View.GONE } etLaunchDelay.setOnEditorActionListener { _, actionCode, _ -> diff --git a/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt b/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt index b69ea142..d8304883 100644 --- a/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt +++ b/app/src/main/java/app/olauncher/ui/AppDrawerFragment.kt @@ -108,12 +108,13 @@ class AppDrawerFragment : Fragment() { appClickListener = { if (it.appPackage.isEmpty()) return@AppDrawerAdapter + val navigationController = findNavController() val launch = { viewModel.selectedApp(it, flag) if (flag == Constants.FLAG_LAUNCH_APP || flag == Constants.FLAG_HIDDEN_APPS) - findNavController().popBackStack(R.id.mainFragment, false) + navigationController.popBackStack(R.id.mainFragment, false) else - findNavController().popBackStack() + navigationController.popBackStack() } val launchDelay = prefs.getAppLaunchDelay(it.appPackage) if ((flag == Constants.FLAG_LAUNCH_APP || flag == Constants.FLAG_HIDDEN_APPS) && launchDelay > 0)