diff --git a/app/build.gradle b/app/build.gradle
index 50a82e2..854a15a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -37,4 +37,5 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
+ implementation 'androidx.palette:palette:1.0.0'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 587516b..a6ab6d5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
package="com.finnmglas.launcher">
+
+ android:theme="@style/finnmglasTheme">
R.style.darkTheme
+ "finn" -> R.style.finnmglasTheme
+ else -> R.style.finnmglasTheme
+ }
+ )
setContentView(R.layout.activity_choose)
+ if (getSavedTheme(this) == "custom") {
+ activity_choose_container.setBackgroundColor(dominantColor)
+ activity_choose_app_bar.setBackgroundColor(dominantColor)
+ activity_choose_close.setTextColor(vibrantColor)
+ }
+
+ // As older APIs somehow do not recognize the xml defined onClick
+ activity_choose_close.setOnClickListener() { finish() }
+
val bundle = intent.extras
val action = bundle!!.getString("action") // why choose an app
val forApp = bundle.getString("forApp") // which app we choose
if (action == "launch")
- heading.text = getString(R.string.choose_title_launch)
- else if (action == "pick") {
- heading.text = getString(R.string.choose_title)
- }
+ activity_choose_heading.text = getString(R.string.choose_title_launch)
+ else if (action == "pick")
+ activity_choose_heading.text = getString(R.string.choose_title)
else if (action == "uninstall")
- heading.text = getString(R.string.choose_title_remove)
+ activity_choose_heading.text = getString(R.string.choose_title_remove)
/* Build Layout */
@@ -59,7 +73,7 @@ class ChooseActivity : AppCompatActivity() {
returnIntent.putExtra("value", app.packageName)
returnIntent.putExtra("forApp", forApp)
setResult(
- 5000,
+ REQUEST_CHOOSE_APP,
returnIntent
)
finish()
@@ -70,16 +84,18 @@ class ChooseActivity : AppCompatActivity() {
val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE)
intent.data = Uri.parse("package:" + app.packageName)
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
- startActivityForResult(intent, UNINSTALL_REQUEST_CODE)
+ startActivityForResult(intent,
+ REQUEST_UNINSTALL
+ )
}
}
- apps_list.addView(tvdynamic)
+ activity_choose_apps_list.addView(tvdynamic)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- if (requestCode == UNINSTALL_REQUEST_CODE) {
+ if (requestCode == REQUEST_UNINSTALL) {
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, getString(R.string.choose_removed_toast), Toast.LENGTH_LONG).show()
updateAppList(packageManager)
diff --git a/app/src/main/java/com/finnmglas/launcher/FirstStartupActivity.kt b/app/src/main/java/com/finnmglas/launcher/FirstStartupActivity.kt
index 5e8d7b4..be43ead 100644
--- a/app/src/main/java/com/finnmglas/launcher/FirstStartupActivity.kt
+++ b/app/src/main/java/com/finnmglas/launcher/FirstStartupActivity.kt
@@ -5,9 +5,8 @@ import android.content.SharedPreferences
import android.os.Bundle
import android.util.TypedValue
import android.view.*
-import android.view.animation.AlphaAnimation
-import android.view.animation.Animation
import androidx.appcompat.app.AppCompatActivity
+import com.finnmglas.launcher.extern.*
import kotlinx.android.synthetic.main.activity_firststartup.*
@@ -31,9 +30,22 @@ class FirstStartupActivity : AppCompatActivity(){
)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ setTheme(
+ when (getSavedTheme(this)) {
+ "dark" -> R.style.darkTheme
+ "finn" -> R.style.finnmglasTheme
+ else -> R.style.finnmglasTheme
+ }
+ )
setContentView(R.layout.activity_firststartup)
- hintText.blink() // animate
+ if (getSavedTheme(this) == "custom") {
+ activity_firststartup_app_bar.setBackgroundColor(dominantColor)
+ activity_firststartup_container.setBackgroundColor(dominantColor)
+ activity_firststartup_close.setTextColor(vibrantColor)
+ }
+
+ activity_firststartup_hint_text.blink() // animate
loadMenu(this)
val sharedPref = this.getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE)
@@ -42,6 +54,11 @@ class FirstStartupActivity : AppCompatActivity(){
if (isFirstTime)
defaultApps = resetSettings(sharedPref, this) // UP, DOWN, RIGHT, LEFT, VOLUME_UP, VOLUME_DOWN
+ else
+ activity_firststartup_app_bar.visibility = View.VISIBLE
+
+ // As older APIs somehow do not recognize the xml defined onClick
+ activity_firststartup_close.setOnClickListener() { finish() }
}
/** Touch- and Key-related functions to navigate */
@@ -67,6 +84,10 @@ class FirstStartupActivity : AppCompatActivity(){
loadMenu(this)
}
+ fun backToSettings(view: View){
+ finish()
+ }
+
/** Touch- and Key-related functions to navigate */
private fun loadMenu(context :Context) { // Context needed for packageManager
@@ -76,14 +97,16 @@ class FirstStartupActivity : AppCompatActivity(){
if (menuNumber < intro.size){
val entry = intro[menuNumber].split("|").toTypedArray() //heading|infoText|hintText|size
- heading.text = entry[0]
- if (entry[4] == "1" && isFirstTime)infoText.text = String.format(entry[1],
+ activity_firststartup_section_heading.text = entry[0]
+ if (entry[4] == "1" && isFirstTime)
+ activity_firststartup_descriptive_text.text = String.format(entry[1],
defaultApps[0], defaultApps[1], defaultApps[2], defaultApps[3], defaultApps[4], defaultApps[5])
- else if (entry[4] == "1" && !isFirstTime)infoText.text = String.format(entry[1],
+ else if (entry[4] == "1" && !isFirstTime)
+ activity_firststartup_descriptive_text.text = String.format(entry[1],
"-", "-", "-", "-", "-", "-")
- else infoText.text = entry[1]
- hintText.text = entry[2]
- infoText.setTextSize(TypedValue.COMPLEX_UNIT_SP, entry[3].toFloat())
+ else activity_firststartup_descriptive_text.text = entry[1]
+ activity_firststartup_hint_text.text = entry[2]
+ activity_firststartup_descriptive_text.setTextSize(TypedValue.COMPLEX_UNIT_SP, entry[3].toFloat())
} else { // End intro
if (isFirstTime){
@@ -94,7 +117,6 @@ class FirstStartupActivity : AppCompatActivity(){
editor.putLong("firstStartup", System.currentTimeMillis() / 1000L) // record first startup timestamp
editor.apply()
}
-
finish()
}
}
diff --git a/app/src/main/java/com/finnmglas/launcher/MainActivity.kt b/app/src/main/java/com/finnmglas/launcher/MainActivity.kt
index ff61c8e..466abcb 100644
--- a/app/src/main/java/com/finnmglas/launcher/MainActivity.kt
+++ b/app/src/main/java/com/finnmglas/launcher/MainActivity.kt
@@ -2,21 +2,27 @@ package com.finnmglas.launcher
import android.content.Context
import android.content.Intent
+import android.net.Uri
import android.os.AsyncTask
import android.os.Bundle
+import android.provider.MediaStore
import android.util.DisplayMetrics
import android.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GestureDetectorCompat
+import com.finnmglas.launcher.extern.*
import kotlinx.android.synthetic.main.activity_main.*
import java.text.SimpleDateFormat
import java.util.*
import kotlin.concurrent.fixedRateTimer
import kotlin.math.abs
+
class MainActivity : AppCompatActivity(),
GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
+ private var currentTheme = "" // keep track of theme changes
+
/** Variables for this activity */
private lateinit var mDetector: GestureDetectorCompat
@@ -38,10 +44,6 @@ class MainActivity : AppCompatActivity(),
val sharedPref = this.getSharedPreferences(
getString(R.string.preference_file_key), Context.MODE_PRIVATE)
- // First Startup
- if (!sharedPref.getBoolean("startedBefore", false))
- startActivity(Intent(this, FirstStartupActivity::class.java))
-
// Flags
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
@@ -49,17 +51,37 @@ class MainActivity : AppCompatActivity(),
)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ currentTheme = getSavedTheme(this)
+
+ if (currentTheme == "custom") {
+ try {
+ background = MediaStore.Images.Media.getBitmap(this.contentResolver, Uri.parse(sharedPref.getString("background_uri", "")))
+ } catch (e: Exception) { }
+
+ if (background == null)
+ currentTheme = saveTheme(this, "finn")
+ }
+
+ setTheme(
+ when (currentTheme) {
+ "dark" -> R.style.darkTheme
+ "finn" -> R.style.finnmglasTheme
+ else -> R.style.finnmglasTheme
+ }
+ )
setContentView(R.layout.activity_main)
// Start by showing the settings icon
showSettingsIcon()
// As older APIs somehow do not recognize the xml defined onClick
- findViewById(R.id.settingstooltip).setOnClickListener() {
- openSettings()
- true
- }
+ activity_main_settings_icon.setOnClickListener() { openSettings() }
+ // First Startup
+ if (!sharedPref.getBoolean("startedBefore", false)){
+ startActivity(Intent(this, FirstStartupActivity::class.java))
+ tooltipTimer.cancel()
+ }
}
override fun onStart(){
@@ -71,6 +93,10 @@ class MainActivity : AppCompatActivity(),
loadSettings(sharedPref)
+ if (currentTheme == "custom") {
+ activity_main_settings_icon.setTextColor(vibrantColor)
+ }
+
mDetector = GestureDetectorCompat(this, this)
mDetector.setOnDoubleTapListener(this)
@@ -80,13 +106,23 @@ class MainActivity : AppCompatActivity(),
override fun onResume() {
super.onResume()
+ // TODO: do this immediately after changing preferences
+ if (currentTheme != getSavedTheme(this)) recreate()
+ if (activity_main_background_image != null && getSavedTheme(this) == "custom")
+ activity_main_background_image.setImageBitmap(background)
+
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
- clockTimer = fixedRateTimer("clockTimer", true, 0L, 1000) {
+ clockTimer = fixedRateTimer("clockTimer", true, 0L, 100) {
this@MainActivity.runOnUiThread {
- dateView.text = dateFormat.format(Date())
- timeView.text = timeFormat.format(Date())
+ val t = timeFormat.format(Date())
+ if (activity_main_time_view.text != t)
+ activity_main_time_view.text = t
+
+ val d = dateFormat.format(Date())
+ if (activity_main_date_view.text != d)
+ activity_main_date_view.text = d
}
}
@@ -103,15 +139,15 @@ class MainActivity : AppCompatActivity(),
loadAppsTimer.cancel()
}
-
private fun openSettings(){
startActivity(Intent(this, SettingsActivity::class.java))
+ overridePendingTransition(R.anim.bottom_up, android.R.anim.fade_out)
}
/** Touch- and Key-related functions to start activities */
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
- if (keyCode == KeyEvent.KEYCODE_BACK) return true
+ if (keyCode == KeyEvent.KEYCODE_BACK) { if (settingsIconShown) hideSettingsIcon() }
else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) launchApp(volumeUpApp, this)
else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) launchApp(volumeDownApp, this)
return true
@@ -153,8 +189,8 @@ class MainActivity : AppCompatActivity(),
}
private fun showSettingsIcon(){
- settingstooltip.fadeIn()
- settingstooltip.visibility = View.VISIBLE
+ activity_main_settings_icon.fadeRotateIn()
+ activity_main_settings_icon.visibility = View.VISIBLE
settingsIconShown = true
tooltipTimer = fixedRateTimer("tooltipTimer", true, 10000, 1000) {
@@ -164,8 +200,8 @@ class MainActivity : AppCompatActivity(),
private fun hideSettingsIcon(){
tooltipTimer.cancel()
- settingstooltip.fadeOut()
- settingstooltip.visibility = View.INVISIBLE
+ activity_main_settings_icon.fadeRotateOut()
+ activity_main_settings_icon.visibility = View.INVISIBLE
settingsIconShown = false
}
diff --git a/app/src/main/java/com/finnmglas/launcher/SettingsActivity.kt b/app/src/main/java/com/finnmglas/launcher/SettingsActivity.kt
index 3eef8b4..36af54a 100644
--- a/app/src/main/java/com/finnmglas/launcher/SettingsActivity.kt
+++ b/app/src/main/java/com/finnmglas/launcher/SettingsActivity.kt
@@ -1,19 +1,26 @@
package com.finnmglas.launcher
+import android.Manifest
import android.app.AlertDialog
import android.content.*
+import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
+import android.provider.MediaStore
import android.provider.Settings
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
import androidx.viewpager.widget.ViewPager
-import com.finnmglas.launcher.ui.main.SectionsPagerAdapter
+import com.finnmglas.launcher.extern.*
+import com.finnmglas.launcher.settings.SectionsPagerAdapter
import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.activity_settings.*
+import kotlinx.android.synthetic.main.fragment_settings_apps.*
+import kotlinx.android.synthetic.main.fragment_settings_theme.*
class SettingsActivity : AppCompatActivity() {
@@ -22,153 +29,49 @@ class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
+ setTheme(
+ when (getSavedTheme(this)) {
+ "dark" -> R.style.darkTheme
+ "finn" -> R.style.finnmglasTheme
+ else -> R.style.finnmglasTheme
+ }
+ )
+
setContentView(R.layout.activity_settings)
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
val sectionsPagerAdapter = SectionsPagerAdapter(this, supportFragmentManager)
- val viewPager: ViewPager = findViewById(R.id.view_pager)
+ val viewPager: ViewPager = findViewById(R.id.activity_settings_view_pager)
viewPager.adapter = sectionsPagerAdapter
- val tabs: TabLayout = findViewById(R.id.tabs)
+ val tabs: TabLayout = findViewById(R.id.activity_settings_tabs)
tabs.setupWithViewPager(viewPager)
- }
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- if(requestCode == 5000)
- {
- val value = data?.getStringExtra("value")
- val forApp = data?.getStringExtra("forApp") ?: return
-
- // Save the new App to Preferences
- val sharedPref = this.getSharedPreferences(
- getString(R.string.preference_file_key), Context.MODE_PRIVATE)
-
- val editor :SharedPreferences.Editor = sharedPref.edit()
- editor.putString("action_$forApp", value.toString())
- editor.apply()
-
- loadSettings(sharedPref)
- }
- else {
- super.onActivityResult(requestCode, resultCode, data)
+ // As older APIs somehow do not recognize the xml defined onClick
+ activity_settings_close.setOnClickListener() { finish() }
+ activity_settings_device_settings.setOnClickListener {
+ startActivityForResult(Intent(android.provider.Settings.ACTION_SETTINGS), 0)
}
}
- /** onClick functions for Settings */
- fun chooseDownApp(view: View) {chooseApp("downApp")}
- fun chooseUpApp(view: View) {chooseApp("upApp")}
- fun chooseLeftApp(view: View) {chooseApp("leftApp")}
- fun chooseRightApp(view: View) {chooseApp("rightApp")}
- fun chooseVolumeDownApp(view: View) {chooseApp("volumeDownApp")}
- fun chooseVolumeUpApp(view: View) {chooseApp("volumeUpApp")}
+ override fun onStart() {
+ super.onStart()
- fun chooseApp(forAction :String) {
- val intent = Intent(this, ChooseActivity::class.java)
- intent.putExtra("action", "pick")
- intent.putExtra("forApp", forAction) // for which action we choose the app
- startActivityForResult(intent, 5000)
- }
+ if (getSavedTheme(this) == "custom") {
+ activity_settings_container.setBackgroundColor(dominantColor)
+ activity_settings_app_bar.setBackgroundColor(dominantColor)
- fun chooseUninstallApp(view: View) {
- val intent = Intent(this, ChooseActivity::class.java)
- intent.putExtra("action", "uninstall")
- startActivity(intent)
- }
-
- fun chooseLaunchApp(view: View) {
- val intent = Intent(this, ChooseActivity::class.java)
- intent.putExtra("action", "launch")
- startActivity(intent)
- }
-
- fun chooseInstallApp(view : View) {
- try {
- val rateIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse("https://play.google.com/store/apps/"))
- startActivity(rateIntent)
- } catch (e: ActivityNotFoundException) {
- Toast.makeText(this,getString(R.string.settings_toast_store_not_found), Toast.LENGTH_SHORT)
- .show()
+ activity_settings_device_settings.setTextColor(vibrantColor)
+ activity_settings_close.setTextColor(vibrantColor)
+ activity_settings_tabs.setSelectedTabIndicatorColor(vibrantColor)
}
}
- fun openFinnWebsite(view: View) { openNewTabWindow(getString(R.string.settings_footer_web), this) }
- fun openGithubRepo(view: View) { openNewTabWindow(getString(R.string.settings_footer_repo), this) }
-
- // Rate App
- // Just copied code from https://stackoverflow.com/q/10816757/12787264
- // that is how we write good software ^
- fun rateApp(view: View) {
- try {
- val rateIntent = rateIntentForUrl("market://details")
- startActivity(rateIntent)
- } catch (e: ActivityNotFoundException) {
- val rateIntent = rateIntentForUrl("https://play.google.com/store/apps/details")
- startActivity(rateIntent)
- }
- }
-
- private fun rateIntentForUrl(url: String): Intent {
- val intent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse(String.format("%s?id=%s", url, packageName))
- )
- var flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
- flags = if (Build.VERSION.SDK_INT >= 21) {
- flags or Intent.FLAG_ACTIVITY_NEW_DOCUMENT
- } else {
- flags or Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
- }
- intent.addFlags(flags)
- return intent
- }
-
fun backHome(view: View) { finish() }
- fun setLauncher(view: View) {
- // on newer sdk: choose launcher
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- val callHomeSettingIntent = Intent(Settings.ACTION_HOME_SETTINGS)
- startActivity(callHomeSettingIntent)
- }
- // on older sdk: manage app details
- else {
- AlertDialog.Builder(this)
- .setTitle(getString(R.string.alert_cant_choose_launcher))
- .setMessage(getString(R.string.alert_cant_choose_launcher_message))
- .setPositiveButton(android.R.string.yes,
- DialogInterface.OnClickListener { dialog, which ->
- try {
- openAppSettings(packageName, this)
- } catch ( e : ActivityNotFoundException) {
- val intent = Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS)
- startActivity(intent)
- }
- })
- .setNegativeButton(android.R.string.no, null)
- .setIcon(android.R.drawable.ic_dialog_info)
- .show()
- }
- }
+ /** Theme - related */
- fun viewTutorial (view: View){
- startActivity(Intent(this, FirstStartupActivity::class.java))
- }
- // Show a dialog prompting for confirmation
- fun resetSettingsClick(view: View) {
- AlertDialog.Builder(this)
- .setTitle(getString(R.string.settings_reset))
- .setMessage(getString(R.string.settings_reset_message))
- .setPositiveButton(android.R.string.yes,
- DialogInterface.OnClickListener { dialog, which ->
- resetSettings(this.getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE), this)
- finish()
- })
- .setNegativeButton(android.R.string.no, null)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .show()
- }
}
diff --git a/app/src/main/java/com/finnmglas/launcher/SettingsFragmentApps.kt b/app/src/main/java/com/finnmglas/launcher/SettingsFragmentApps.kt
deleted file mode 100644
index ad193fd..0000000
--- a/app/src/main/java/com/finnmglas/launcher/SettingsFragmentApps.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.finnmglas.launcher
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-
-/** The 'Apps' Tab associated Fragment in Settings */
-
-class SettingsFragmentApps : Fragment() {
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
-
- return inflater.inflate(R.layout.fragment_settings_apps, container, false)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/finnmglas/launcher/SettingsFragmentLauncher.kt b/app/src/main/java/com/finnmglas/launcher/SettingsFragmentLauncher.kt
deleted file mode 100644
index 89cb44f..0000000
--- a/app/src/main/java/com/finnmglas/launcher/SettingsFragmentLauncher.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.finnmglas.launcher
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-
-/** The 'Launcher' Tab associated Fragment in Settings */
-
-class SettingsFragmentLauncher : Fragment() {
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
-
- return inflater.inflate(R.layout.fragment_settings_launcher, container, false)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/finnmglas/launcher/SettingsFragmentTheme.kt b/app/src/main/java/com/finnmglas/launcher/SettingsFragmentTheme.kt
deleted file mode 100644
index 71d8d2f..0000000
--- a/app/src/main/java/com/finnmglas/launcher/SettingsFragmentTheme.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.finnmglas.launcher
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-
-/** The 'Theme' Tab associated Fragment in Settings */
-
-class SettingsFragmentTheme : Fragment() {
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
-
- return inflater.inflate(R.layout.fragment_settings_theme, container, false)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/finnmglas/launcher/FontAwesome.kt b/app/src/main/java/com/finnmglas/launcher/extern/FontAwesome.kt
similarity index 89%
rename from app/src/main/java/com/finnmglas/launcher/FontAwesome.kt
rename to app/src/main/java/com/finnmglas/launcher/extern/FontAwesome.kt
index 7a4627a..4b8f2fb 100644
--- a/app/src/main/java/com/finnmglas/launcher/FontAwesome.kt
+++ b/app/src/main/java/com/finnmglas/launcher/extern/FontAwesome.kt
@@ -1,4 +1,4 @@
-package com.finnmglas.launcher // replace with your package
+package com.finnmglas.launcher.extern // replace with your package
// On GitHub: https://github.com/finnmglas/fontawesome-android
@@ -6,6 +6,7 @@ import android.content.Context
import android.graphics.Typeface
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
+import com.finnmglas.launcher.R
/** [FontAwesome] is just a type of TextView with special functions:
*
@@ -28,7 +29,9 @@ class FontAwesome : AppCompatTextView {
private fun init(attrs: AttributeSet?) {
if (attrs != null) {
- val a = context!!.obtainStyledAttributes(attrs, R.styleable.FontAwesome)
+ val a = context!!.obtainStyledAttributes(attrs,
+ R.styleable.FontAwesome
+ )
if (a.hasValue(R.styleable.FontAwesome_type))
type = a.getString(R.styleable.FontAwesome_type)!!
a.recycle()
diff --git a/app/src/main/java/com/finnmglas/launcher/Functions.kt b/app/src/main/java/com/finnmglas/launcher/extern/Functions.kt
similarity index 61%
rename from app/src/main/java/com/finnmglas/launcher/Functions.kt
rename to app/src/main/java/com/finnmglas/launcher/extern/Functions.kt
index 6bbc484..2049178 100644
--- a/app/src/main/java/com/finnmglas/launcher/Functions.kt
+++ b/app/src/main/java/com/finnmglas/launcher/extern/Functions.kt
@@ -1,4 +1,4 @@
-package com.finnmglas.launcher
+package com.finnmglas.launcher.extern
import android.app.Activity
import android.app.AlertDialog
@@ -8,14 +8,19 @@ import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
+import android.graphics.Bitmap
+import android.graphics.BlendMode
+import android.graphics.BlendModeColorFilter
+import android.graphics.PorterDuff
import android.net.Uri
+import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.View
-import android.view.animation.AlphaAnimation
-import android.view.animation.Animation
-import android.view.animation.DecelerateInterpolator
+import android.view.animation.*
+import android.widget.Button
import android.widget.Toast
+import com.finnmglas.launcher.R
/** Variables for all of the app */
var upApp = ""
@@ -30,6 +35,20 @@ var clockApp = ""
var appsList : MutableList = mutableListOf()
+var background : Bitmap? = null
+
+var dominantColor = 0
+var vibrantColor = 0
+
+/** REQUEST CODES */
+
+val REQUEST_PICK_IMAGE = 1
+val REQUEST_CHOOSE_APP = 2
+val REQUEST_UNINSTALL = 3
+val REQUEST_PERMISSION_STORAGE = 4
+
+/** Animate */
+
// Taken from https://stackoverflow.com/questions/47293269
fun View.blink(
times: Int = Animation.INFINITE,
@@ -47,20 +66,58 @@ fun View.blink(
})
}
-fun View.fadeIn(duration: Long = 1000L) {
+fun View.fadeIn(duration: Long = 300L) {
startAnimation(AlphaAnimation(0f, 1f).also {
it.interpolator = DecelerateInterpolator()
it.duration = duration
})
}
-fun View.fadeOut(duration: Long = 1000L) {
+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 */
fun isInstalled(uri: String, context: Context): Boolean {
@@ -86,10 +143,11 @@ private fun getIntent(packageName: String, context: Context): Intent? {
}
fun launchApp(packageName: String, context: Context) {
- val intent1 = getIntent(packageName, context)
+ val intent =
+ getIntent(packageName, context)
- if (intent1 != null) {
- context.startActivity(intent1)
+ if (intent != null) {
+ context.startActivity(intent)
if (context is Activity) {
context.overridePendingTransition(0, 0)
@@ -97,12 +155,17 @@ fun launchApp(packageName: String, context: Context) {
} else {
if (isInstalled(packageName, context)){
- AlertDialog.Builder(context)
+ AlertDialog.Builder(context,
+ R.style.AlertDialogCustom
+ )
.setTitle(context.getString(R.string.alert_cant_open_title))
.setMessage(context.getString(R.string.alert_cant_open_message))
.setPositiveButton(android.R.string.yes,
DialogInterface.OnClickListener { dialog, which ->
- openAppSettings(packageName, context)
+ openAppSettings(
+ packageName,
+ context
+ )
})
.setNegativeButton(android.R.string.no, null)
.setIcon(android.R.drawable.ic_dialog_info)
@@ -124,6 +187,24 @@ fun openNewTabWindow(urls: String, context : Context) {
/** Settings related functions */
+fun getSavedTheme(context : Context) : String {
+ val sharedPref = context.getSharedPreferences(
+ context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+
+ return sharedPref.getString("theme", "finn").toString()
+}
+
+fun saveTheme(context : Context, themeName : String) : String {
+ val sharedPref = context.getSharedPreferences(
+ context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+
+ val editor: SharedPreferences.Editor = sharedPref.edit()
+ editor.putString("theme", themeName)
+ editor.apply()
+
+ return themeName
+}
+
fun openAppSettings(pkg :String, context:Context){
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:$pkg")
@@ -140,39 +221,67 @@ fun loadSettings(sharedPref : SharedPreferences){
calendarApp = sharedPref.getString("action_calendarApp", "").toString()
clockApp = sharedPref.getString("action_clockApp", "").toString()
+
+ dominantColor = sharedPref.getInt("custom_dominant", 0)
+ vibrantColor = sharedPref.getInt("custom_vibrant", 0)
}
fun resetSettings(sharedPref : SharedPreferences, context: Context) : MutableList{
+
+ // set default theme
+ saveTheme(context, "finn")
+
val defaultList :MutableList = mutableListOf()
val editor: SharedPreferences.Editor = sharedPref.edit()
- val (chosenUpName, chosenUpPackage) = pickDefaultApp("action_upApp", context)
+ val (chosenUpName, chosenUpPackage) = pickDefaultApp(
+ "action_upApp",
+ context
+ )
editor.putString("action_upApp", chosenUpPackage)
defaultList.add(chosenUpName)
- val (chosenDownName, chosenDownPackage) = pickDefaultApp("action_downApp", context)
+ val (chosenDownName, chosenDownPackage) = pickDefaultApp(
+ "action_downApp",
+ context
+ )
editor.putString("action_downApp", chosenDownPackage)
defaultList.add(chosenDownName)
- val (chosenRightName, chosenRightPackage) = pickDefaultApp("action_rightApp", context)
+ val (chosenRightName, chosenRightPackage) = pickDefaultApp(
+ "action_rightApp",
+ context
+ )
editor.putString("action_rightApp", chosenRightPackage)
defaultList.add(chosenRightName)
- val (chosenLeftName, chosenLeftPackage) = pickDefaultApp("action_leftApp", context)
+ val (chosenLeftName, chosenLeftPackage) = pickDefaultApp(
+ "action_leftApp",
+ context
+ )
editor.putString("action_leftApp", chosenLeftPackage)
editor.putString("action_calendarApp", chosenLeftPackage)
defaultList.add(chosenLeftName)
- val (chosenVolumeUpName, chosenVolumeUpPackage) = pickDefaultApp("action_volumeUpApp", context)
+ val (chosenVolumeUpName, chosenVolumeUpPackage) = pickDefaultApp(
+ "action_volumeUpApp",
+ context
+ )
editor.putString("action_volumeUpApp", chosenVolumeUpPackage)
defaultList.add(chosenVolumeUpName)
- val (chosenVolumeDownName, chosenVolumeDownPackage) = pickDefaultApp("action_volumeDownApp", context)
+ val (chosenVolumeDownName, chosenVolumeDownPackage) = pickDefaultApp(
+ "action_volumeDownApp",
+ context
+ )
editor.putString("action_volumeDownApp", chosenVolumeDownPackage)
defaultList.add(chosenVolumeDownName)
- val (_, chosenClockPackage) = pickDefaultApp("action_clockApp", context)
+ val (_, chosenClockPackage) = pickDefaultApp(
+ "action_clockApp",
+ context
+ )
editor.putString("action_clockApp", chosenClockPackage)
editor.apply()
@@ -194,7 +303,7 @@ fun pickDefaultApp(action: String, context: Context) : Pair{
// Related question: https://stackoverflow.com/q/3013655/12787264 (Adjusted)
val list = context.resources.getStringArray(arrayResource)
- for (entry in list!!){
+ for (entry in list){
val splitResult = entry.split("|").toTypedArray()
val pkgname = splitResult[0]
val name = splitResult[1]
@@ -203,3 +312,19 @@ fun pickDefaultApp(action: String, context: Context) : Pair{
}
return Pair(context.getString(R.string.none_found), "")
}
+
+/** Bitmaps */
+
+fun getDominantColor(bitmap: Bitmap?): Int {
+ val newBitmap = Bitmap.createScaledBitmap(bitmap!!, 1, 1, true)
+ val color = newBitmap.getPixel(0, 0)
+ newBitmap.recycle()
+ return color
+}
+
+fun setButtonColor(btn: Button, color: Int) {
+ if (Build.VERSION.SDK_INT >= 29)
+ btn.background.colorFilter = BlendModeColorFilter(color, BlendMode.MULTIPLY)
+ else
+ btn.background.setColorFilter(color, PorterDuff.Mode.MULTIPLY)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/finnmglas/launcher/ui/main/PageViewModel.kt b/app/src/main/java/com/finnmglas/launcher/settings/PageViewModel.kt
similarity index 82%
rename from app/src/main/java/com/finnmglas/launcher/ui/main/PageViewModel.kt
rename to app/src/main/java/com/finnmglas/launcher/settings/PageViewModel.kt
index 584ab43..7157d60 100644
--- a/app/src/main/java/com/finnmglas/launcher/ui/main/PageViewModel.kt
+++ b/app/src/main/java/com/finnmglas/launcher/settings/PageViewModel.kt
@@ -1,10 +1,9 @@
-package com.finnmglas.launcher.ui.main
+package com.finnmglas.launcher.settings
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
class PageViewModel : ViewModel() {
diff --git a/app/src/main/java/com/finnmglas/launcher/ui/main/SectionsPagerAdapter.kt b/app/src/main/java/com/finnmglas/launcher/settings/SectionsPagerAdapter.kt
similarity index 80%
rename from app/src/main/java/com/finnmglas/launcher/ui/main/SectionsPagerAdapter.kt
rename to app/src/main/java/com/finnmglas/launcher/settings/SectionsPagerAdapter.kt
index f412ddd..2b304ef 100644
--- a/app/src/main/java/com/finnmglas/launcher/ui/main/SectionsPagerAdapter.kt
+++ b/app/src/main/java/com/finnmglas/launcher/settings/SectionsPagerAdapter.kt
@@ -1,4 +1,4 @@
-package com.finnmglas.launcher.ui.main
+package com.finnmglas.launcher.settings
import android.content.Context
import androidx.fragment.app.Fragment
@@ -14,13 +14,13 @@ private val TAB_TITLES = arrayOf(
/** Returns the fragment corresponding to the selected tab.*/
class SectionsPagerAdapter(private val context: Context, fm: FragmentManager)
- : FragmentPagerAdapter(fm) {
+ : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItem(position: Int): Fragment {
return when (position){
0 -> SettingsFragmentApps()
1 -> SettingsFragmentTheme()
- 2 -> SettingsFragmentLauncher()
+ 2 -> SettingsFragmentMeta()
else -> Fragment()
}
}
@@ -29,7 +29,5 @@ class SectionsPagerAdapter(private val context: Context, fm: FragmentManager)
return context.resources.getString(TAB_TITLES[position])
}
- override fun getCount(): Int {
- return 3
- }
+ override fun getCount(): Int { return 3 }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentApps.kt b/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentApps.kt
new file mode 100644
index 0000000..62189ad
--- /dev/null
+++ b/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentApps.kt
@@ -0,0 +1,113 @@
+package com.finnmglas.launcher.settings
+
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.net.Uri
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import com.finnmglas.launcher.ChooseActivity
+import com.finnmglas.launcher.R
+import com.finnmglas.launcher.extern.*
+import kotlinx.android.synthetic.main.fragment_settings_apps.*
+
+/** The 'Apps' Tab associated Fragment in Settings */
+
+class SettingsFragmentApps : Fragment() {
+
+ /** Lifecycle functions */
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+
+ return inflater.inflate(R.layout.fragment_settings_apps, container, false)
+ }
+
+ override fun onStart() {
+
+ if (getSavedTheme(context!!) == "custom") {
+ fragment_settings_apps_container.setBackgroundColor(dominantColor)
+
+ setButtonColor(fragment_settings_apps_choose_up_btn, vibrantColor)
+ setButtonColor(fragment_settings_apps_choose_down_btn, vibrantColor)
+ setButtonColor(fragment_settings_apps_choose_left_btn, vibrantColor)
+ setButtonColor(fragment_settings_apps_choose_right_btn, vibrantColor)
+ setButtonColor(fragment_settings_apps_choose_vol_up_btn, vibrantColor)
+ setButtonColor(fragment_settings_apps_choose_vol_down_btn, vibrantColor)
+
+ setButtonColor(fragment_settings_apps_launch_btn, vibrantColor)
+ setButtonColor(fragment_settings_apps_install_btn, vibrantColor)
+ setButtonColor(fragment_settings_apps_remove_btn, vibrantColor)
+ }
+
+ // Action - selecting buttons
+ fragment_settings_apps_choose_up_btn.setOnClickListener{ chooseApp("upApp") }
+ fragment_settings_apps_choose_down_btn.setOnClickListener{ chooseApp("downApp") }
+ fragment_settings_apps_choose_left_btn.setOnClickListener{ chooseApp("leftApp") }
+ fragment_settings_apps_choose_right_btn.setOnClickListener{ chooseApp("rightApp") }
+ fragment_settings_apps_choose_vol_up_btn.setOnClickListener{ chooseApp("volumeUpApp")}
+ fragment_settings_apps_choose_vol_down_btn.setOnClickListener{ chooseApp("volumeDownApp")}
+
+ // App management buttons
+ fragment_settings_apps_launch_btn.setOnClickListener{
+ val intent = Intent(this.context, ChooseActivity::class.java)
+ intent.putExtra("action", "launch")
+ startActivity(intent)
+ }
+ fragment_settings_apps_install_btn.setOnClickListener{
+ try {
+ val rateIntent = Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse("https://play.google.com/store/apps/"))
+ startActivity(rateIntent)
+ } catch (e: ActivityNotFoundException) {
+ Toast.makeText(this.context, getString(R.string.settings_toast_store_not_found), Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+ fragment_settings_apps_remove_btn.setOnClickListener{
+ val intent = Intent(this.context, ChooseActivity::class.java)
+ intent.putExtra("action", "uninstall")
+ startActivity(intent)
+ }
+
+ super.onStart()
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ when (requestCode) {
+ REQUEST_CHOOSE_APP -> {
+ val value = data?.getStringExtra("value")
+ val forApp = data?.getStringExtra("forApp") ?: return
+
+ // Save the new App to Preferences
+ val sharedPref = this.context!!.getSharedPreferences(
+ getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+
+ val editor : SharedPreferences.Editor = sharedPref.edit()
+ editor.putString("action_$forApp", value.toString())
+ editor.apply()
+
+ loadSettings(sharedPref)
+ }
+ else -> super.onActivityResult(requestCode, resultCode, data)
+ }
+ }
+
+ /** Extra functions */
+
+ private fun chooseApp(forAction: String) {
+ val intent = Intent(this.context, ChooseActivity::class.java)
+ intent.putExtra("action", "pick")
+ intent.putExtra("forApp", forAction) // for which action we choose the app
+ startActivityForResult(intent, REQUEST_CHOOSE_APP)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentMeta.kt b/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentMeta.kt
new file mode 100644
index 0000000..56b1a64
--- /dev/null
+++ b/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentMeta.kt
@@ -0,0 +1,141 @@
+package com.finnmglas.launcher.settings
+
+import android.app.AlertDialog
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.Bundle
+import android.provider.Settings
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.finnmglas.launcher.FirstStartupActivity
+import com.finnmglas.launcher.R
+import com.finnmglas.launcher.extern.*
+import kotlinx.android.synthetic.main.fragment_settings_meta.*
+
+/** The 'Meta' Tab associated Fragment in Settings */
+
+class SettingsFragmentMeta : Fragment() {
+
+ /** Lifecycle functions */
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_settings_meta, container, false)
+ }
+
+ override fun onStart() {
+
+ if (getSavedTheme(context!!) == "custom") {
+ fragment_settings_meta_container.setBackgroundColor(dominantColor)
+
+ setButtonColor(fragment_settings_meta_select_launcher_btn, vibrantColor)
+ setButtonColor(fragment_settings_meta_view_tutorial_btn, vibrantColor)
+ setButtonColor(fragment_settings_meta_reset_settings_btn, vibrantColor)
+
+ fragment_settings_meta_footer_play_icon.setTextColor(vibrantColor)
+ fragment_settings_meta_footer_github_icon.setTextColor(vibrantColor)
+ fragment_settings_meta_footer_globe_icon.setTextColor(vibrantColor)
+ }
+
+ // Button onClicks
+
+ fragment_settings_meta_select_launcher_btn.setOnClickListener {
+ // on newer sdk: choose launcher
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ val callHomeSettingIntent = Intent(Settings.ACTION_HOME_SETTINGS)
+ startActivity(callHomeSettingIntent)
+ }
+ // on older sdk: manage app details
+ else {
+ AlertDialog.Builder(this.context!!, R.style.AlertDialogCustom)
+ .setTitle(getString(R.string.alert_cant_choose_launcher))
+ .setMessage(getString(R.string.alert_cant_choose_launcher_message))
+ .setPositiveButton(android.R.string.yes,
+ DialogInterface.OnClickListener { _, _ ->
+ try {
+ openAppSettings(this.context!!.packageName, this.context!!)
+ } catch ( e : ActivityNotFoundException) {
+ val intent = Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS)
+ startActivity(intent)
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .show()
+ }
+ }
+
+ fragment_settings_meta_view_tutorial_btn.setOnClickListener {
+ startActivity(Intent(this.context, FirstStartupActivity::class.java))
+ }
+
+ // prompting for settings-reset confirmation
+ fragment_settings_meta_reset_settings_btn.setOnClickListener {
+ AlertDialog.Builder(this.context!!, R.style.AlertDialogCustom)
+ .setTitle(getString(R.string.settings_reset))
+ .setMessage(getString(R.string.settings_reset_message))
+ .setPositiveButton(android.R.string.yes,
+ DialogInterface.OnClickListener { _, _ ->
+ resetSettings(this.context!!.getSharedPreferences(getString(R.string.preference_file_key),
+ Context.MODE_PRIVATE), this.context!!)
+ activity!!.finish()
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .show()
+ }
+
+ // Footer onClicks
+ fragment_settings_meta_footer_github_icon.setOnClickListener {
+ openNewTabWindow(getString(R.string.settings_footer_repo), this.context!!)
+ }
+ // rate app
+ fragment_settings_meta_footer_play_icon.setOnClickListener {
+ try {
+ val rateIntent = rateIntentForUrl("market://details")
+ startActivity(rateIntent)
+ } catch (e: ActivityNotFoundException) {
+ val rateIntent = rateIntentForUrl("https://play.google.com/store/apps/details")
+ startActivity(rateIntent)
+ }
+ }
+
+ /*fragment_settings_meta_footer_website_icon.setOnClickListener {
+ openNewTabWindow(getString(R.string.settings_footer_web), this.context!!)
+ }*/
+ fragment_settings_meta_footer_globe_icon.setOnClickListener {
+ openNewTabWindow(getString(R.string.settings_footer_web), this.context!!)
+ }
+
+ super.onStart()
+ }
+
+ /** Extra functions */
+
+ // Rate App
+ // Just copied code from https://stackoverflow.com/q/10816757/12787264
+ // that is how we write good software ^^
+
+ private fun rateIntentForUrl(url: String): Intent {
+ val intent = Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse(String.format("%s?id=%s", url, this.context!!.packageName))
+ )
+ var flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+ flags = if (Build.VERSION.SDK_INT >= 21) {
+ flags or Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+ } else {
+ flags or Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
+ }
+ intent.addFlags(flags)
+ return intent
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentTheme.kt b/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentTheme.kt
new file mode 100644
index 0000000..43441f5
--- /dev/null
+++ b/app/src/main/java/com/finnmglas/launcher/settings/SettingsFragmentTheme.kt
@@ -0,0 +1,123 @@
+package com.finnmglas.launcher.settings
+
+import android.Manifest
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.provider.MediaStore
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.palette.graphics.Palette
+import com.finnmglas.launcher.R
+import com.finnmglas.launcher.extern.*
+import kotlinx.android.synthetic.main.fragment_settings_theme.*
+
+/** The 'Theme' Tab associated Fragment in Settings */
+
+class SettingsFragmentTheme : Fragment() {
+
+ /** Lifecycle functions */
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_settings_theme, container, false)
+ }
+
+ override fun onStart(){
+ // Hide 'select' button for the selected theme or allow customisation
+ when (getSavedTheme(context!!)) {
+ "dark" -> fragment_settings_theme_select_dark_btn.visibility = View.INVISIBLE
+ "finn" -> fragment_settings_theme_select_finn_btn.visibility = View.INVISIBLE
+ "custom" -> {
+ fragment_settings_theme_select_custom_btn.text = getString(R.string.settings_select_image)
+ fragment_settings_theme_container.setBackgroundColor(dominantColor)
+ setButtonColor(fragment_settings_theme_select_finn_btn, vibrantColor)
+ setButtonColor(fragment_settings_theme_select_dark_btn, vibrantColor)
+ setButtonColor(fragment_settings_theme_select_custom_btn, vibrantColor)
+ }
+ }
+
+ // Theme changing buttons
+ fragment_settings_theme_select_dark_btn.setOnClickListener {
+ saveTheme(context!!, "dark")
+ activity!!.recreate()
+ }
+ fragment_settings_theme_select_finn_btn.setOnClickListener {
+ saveTheme(context!!, "finn")
+ activity!!.recreate()
+ }
+ fragment_settings_theme_select_custom_btn.setOnClickListener {
+ // Request permission (on newer APIs)
+ if (Build.VERSION.SDK_INT >= 23) {
+ when {
+ ContextCompat.checkSelfPermission(context!!,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
+ -> letUserPickImage()
+ shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ -> {}
+ else
+ -> requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_PERMISSION_STORAGE)
+ }
+ }
+ else letUserPickImage()
+ }
+
+ super.onStart()
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+
+ when (requestCode) {
+ REQUEST_PERMISSION_STORAGE -> letUserPickImage()
+ REQUEST_PICK_IMAGE -> handlePickedImage(resultCode, data)
+ else -> super.onActivityResult(requestCode, resultCode, data)
+ }
+ }
+
+ /** Extra functions */
+
+ private fun letUserPickImage(crop: Boolean = false) {
+ val intent = Intent()
+ intent.type = "image/*"
+ intent.action = Intent.ACTION_PICK // other option: Intent.ACTION_GET_CONTENT
+ if (crop) intent.putExtra("crop", "true")
+ startActivityForResult(intent, REQUEST_PICK_IMAGE)
+ }
+
+ private fun handlePickedImage(resultCode: Int, data: Intent?) {
+
+ if (resultCode == AppCompatActivity.RESULT_OK) {
+ if (data == null) return
+
+ val imageUri = data.data
+ background = MediaStore.Images.Media.getBitmap(context!!.contentResolver, imageUri)
+
+ Palette.Builder(background!!).generate {
+ it?.let { palette ->
+ dominantColor = palette.getDominantColor(ContextCompat.getColor(context!!, R.color.darkTheme_accent_color))
+ vibrantColor = palette.getVibrantColor(ContextCompat.getColor(context!!, R.color.darkTheme_accent_color))
+
+ /* Save image Uri as string */
+ val editor: SharedPreferences.Editor = context!!.getSharedPreferences(
+ context!!.getString(R.string.preference_file_key), Context.MODE_PRIVATE).edit()
+ editor.putString("background_uri", imageUri.toString())
+ editor.putInt("custom_dominant", dominantColor)
+ editor.putInt("custom_vibrant", vibrantColor)
+ editor.apply()
+
+ saveTheme(context!!, "custom")
+ activity!!.recreate()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/anim/bottom_up.xml b/app/src/main/res/anim/bottom_up.xml
new file mode 100644
index 0000000..7832abf
--- /dev/null
+++ b/app/src/main/res/anim/bottom_up.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-de/custom_theme.jpg b/app/src/main/res/drawable-de/custom_theme.jpg
new file mode 100644
index 0000000..947a003
Binary files /dev/null and b/app/src/main/res/drawable-de/custom_theme.jpg differ
diff --git a/app/src/main/res/drawable-de/dark_theme.jpg b/app/src/main/res/drawable-de/dark_theme.jpg
new file mode 100644
index 0000000..60018be
Binary files /dev/null and b/app/src/main/res/drawable-de/dark_theme.jpg differ
diff --git a/app/src/main/res/drawable-de/finnmglas_theme.jpg b/app/src/main/res/drawable-de/finnmglas_theme.jpg
new file mode 100644
index 0000000..1b65f60
Binary files /dev/null and b/app/src/main/res/drawable-de/finnmglas_theme.jpg differ
diff --git a/app/src/main/res/drawable-fr/custom_theme.jpg b/app/src/main/res/drawable-fr/custom_theme.jpg
new file mode 100644
index 0000000..9fb4383
Binary files /dev/null and b/app/src/main/res/drawable-fr/custom_theme.jpg differ
diff --git a/app/src/main/res/drawable-fr/dark_theme.jpg b/app/src/main/res/drawable-fr/dark_theme.jpg
new file mode 100644
index 0000000..19e8861
Binary files /dev/null and b/app/src/main/res/drawable-fr/dark_theme.jpg differ
diff --git a/app/src/main/res/drawable-fr/finnmglas_theme.jpg b/app/src/main/res/drawable-fr/finnmglas_theme.jpg
new file mode 100644
index 0000000..2f0b6f7
Binary files /dev/null and b/app/src/main/res/drawable-fr/finnmglas_theme.jpg differ
diff --git a/app/src/main/res/drawable/custom_theme.jpg b/app/src/main/res/drawable/custom_theme.jpg
new file mode 100644
index 0000000..fd0e7ca
Binary files /dev/null and b/app/src/main/res/drawable/custom_theme.jpg differ
diff --git a/app/src/main/res/drawable/dark_theme.jpg b/app/src/main/res/drawable/dark_theme.jpg
new file mode 100644
index 0000000..df2414a
Binary files /dev/null and b/app/src/main/res/drawable/dark_theme.jpg differ
diff --git a/app/src/main/res/drawable/finnmglas_theme.jpg b/app/src/main/res/drawable/finnmglas_theme.jpg
new file mode 100644
index 0000000..97996e1
Binary files /dev/null and b/app/src/main/res/drawable/finnmglas_theme.jpg differ
diff --git a/app/src/main/res/layout/activity_choose.xml b/app/src/main/res/layout/activity_choose.xml
index b989abc..e15028a 100644
--- a/app/src/main/res/layout/activity_choose.xml
+++ b/app/src/main/res/layout/activity_choose.xml
@@ -1,20 +1,19 @@
-
@@ -24,7 +23,7 @@
android:layout_height="match_parent">
-
+ app:layout_constraintTop_toBottomOf="@id/activity_choose_app_bar">
diff --git a/app/src/main/res/layout/activity_firststartup.xml b/app/src/main/res/layout/activity_firststartup.xml
index 4581de9..74ae392 100644
--- a/app/src/main/res/layout/activity_firststartup.xml
+++ b/app/src/main/res/layout/activity_firststartup.xml
@@ -1,16 +1,66 @@
-
+
+
+
+
+
+
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@id/activity_firststartup_section_heading" />
+ app:layout_constraintTop_toBottomOf="@id/activity_firststartup_descriptive_text" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 7d4be6e..f1ba21e 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,21 +1,30 @@
-
+
+
-
-
+ android:layout_height="wrap_content">
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
-
+
+
+ app:tabTextColor="?attr/android:textColor" />
diff --git a/app/src/main/res/layout/fragment_settings_apps.xml b/app/src/main/res/layout/fragment_settings_apps.xml
index 0c7e1d4..cf0ca53 100644
--- a/app/src/main/res/layout/fragment_settings_apps.xml
+++ b/app/src/main/res/layout/fragment_settings_apps.xml
@@ -2,17 +2,18 @@
+ android:paddingLeft="32sp"
+ android:paddingTop="16sp"
+ android:paddingRight="32sp"
+ tools:context=".settings.SettingsFragmentApps">
@@ -51,20 +50,18 @@
android:gravity="center">
@@ -76,20 +73,18 @@
android:gravity="center">
@@ -100,20 +95,18 @@
android:gravity="center">
@@ -125,20 +118,18 @@
android:gravity="center">
@@ -149,20 +140,18 @@
android:gravity="center">
@@ -171,26 +160,23 @@
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings_launcher.xml b/app/src/main/res/layout/fragment_settings_launcher.xml
deleted file mode 100644
index 09e31c1..0000000
--- a/app/src/main/res/layout/fragment_settings_launcher.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings_meta.xml b/app/src/main/res/layout/fragment_settings_meta.xml
new file mode 100644
index 0000000..3bd2fcb
--- /dev/null
+++ b/app/src/main/res/layout/fragment_settings_meta.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings_theme.xml b/app/src/main/res/layout/fragment_settings_theme.xml
index af36cf4..6cbe7a7 100644
--- a/app/src/main/res/layout/fragment_settings_theme.xml
+++ b/app/src/main/res/layout/fragment_settings_theme.xml
@@ -1,23 +1,120 @@
-
+ android:paddingLeft="32sp"
+ android:paddingTop="16sp"
+ android:paddingRight="32sp"
+ tools:context=".settings.SettingsFragmentMeta">
-
+ android:layout_height="match_parent">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 26463e7..9205a82 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -13,7 +13,7 @@
Einstellungen
Zum Launcher Tutorial
- Feedback geben
+ Jetzt im Playstore bewerten
Hochwischen
Runterwischen
@@ -33,6 +33,9 @@
PlayStore nicht gefunden
+ Wählen
+ Bild ändern
+
Von
https://github.com/finnmglas/Launcher#de
https://www.finnmglas.com/de/
@@ -48,6 +51,7 @@
Die App konnte nicht entfernt werden
+ Tutorial
- |Nimm dir kurz Zeit und lerne, wie du diesen Launcher verwendest!\n\n|— Tippe um weiterzukommen —|36F|0
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 1caad74..b3617cd 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -12,7 +12,7 @@
Réglages
- Donner une rétroaction
+ Donner une rétroaction
Regardez le tutoriel
Balayez haut
@@ -33,6 +33,9 @@
Pas trouvé le PlayStore
+ Choisir
+ Changer Image
+
Par
https://www.finnmglas.com/fr/
https://github.com/finnmglas/Launcher
@@ -40,7 +43,7 @@
Choisir App
Lancer Apps
- Désinstaller Apps
+ Désinstaller
Retourner
@@ -48,6 +51,7 @@
Impossible de supprimer l\'application
+ Le Tutoriel
- |Prenez un moment et apprenez à utiliser ce lanceur!\n\n|— Appuyez pour continuer —|36F|0
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index c404569..c4a008d 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,6 +1,10 @@
- #2d2d2d
- #252827
- #5555ff
+ #252827
+ #5555ff
+ #fff
+
+ #000
+ #444
+ #fff
diff --git a/app/src/main/res/values/icons.xml b/app/src/main/res/values/icons.xml
index 44125b8..4e8d1a8 100644
--- a/app/src/main/res/values/icons.xml
+++ b/app/src/main/res/values/icons.xml
@@ -8,10 +8,14 @@
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 82f3cae..4760350 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -17,10 +17,10 @@
Settings
Apps
- Theme
- Launcher
+ Themes
+ Meta
- Give some feedback
+ Rate us on Google Play
View Launcher Tutorial
Swipe Up
@@ -41,6 +41,9 @@
PlayStore not found
+ Select
+ Change Image
+
By
https://github.com/finnmglas/Launcher#en
https://www.finnmglas.com
@@ -56,6 +59,7 @@
Unable to remove application
+ Tutorial
- |Take a few seconds to learn how to use this Launcher!\n\n|— Tap anywhere to continue —|36F|0
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index d79cf73..0d1f376 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,20 +1,43 @@
-
-
-
-
+
-
+
+