2019-09-01 11:54:12 +02:00
|
|
|
package com.denizd.substitutionplan.activities
|
2019-05-14 22:28:45 +02:00
|
|
|
|
2019-09-11 20:59:55 +02:00
|
|
|
import android.annotation.SuppressLint
|
2019-08-21 10:26:54 +02:00
|
|
|
import android.app.job.JobInfo
|
|
|
|
|
import android.app.job.JobScheduler
|
|
|
|
|
import android.content.ComponentName
|
2019-05-14 22:28:45 +02:00
|
|
|
import android.content.Context
|
|
|
|
|
import android.content.Intent
|
|
|
|
|
import android.content.SharedPreferences
|
|
|
|
|
import android.os.Build
|
|
|
|
|
import android.os.Bundle
|
2019-10-12 21:03:34 +02:00
|
|
|
import androidx.preference.PreferenceManager
|
2019-05-14 22:28:45 +02:00
|
|
|
import android.view.*
|
|
|
|
|
import android.widget.TextView
|
|
|
|
|
import androidx.appcompat.app.AlertDialog
|
|
|
|
|
import androidx.appcompat.app.AppCompatActivity
|
2019-05-21 18:55:29 +02:00
|
|
|
import androidx.appcompat.app.AppCompatDelegate
|
2019-05-14 22:28:45 +02:00
|
|
|
import androidx.core.content.ContextCompat
|
|
|
|
|
import androidx.core.widget.NestedScrollView
|
|
|
|
|
import androidx.fragment.app.Fragment
|
2019-07-30 16:58:51 +02:00
|
|
|
import androidx.fragment.app.FragmentTransaction
|
2019-05-14 22:28:45 +02:00
|
|
|
import androidx.recyclerview.widget.RecyclerView
|
2019-09-03 18:18:21 +02:00
|
|
|
import com.denizd.substitutionplan.data.HelperFunctions
|
2019-09-01 11:54:12 +02:00
|
|
|
import com.denizd.substitutionplan.R
|
|
|
|
|
import com.denizd.substitutionplan.fragments.FoodFragment
|
|
|
|
|
import com.denizd.substitutionplan.fragments.GeneralPlanFragment
|
|
|
|
|
import com.denizd.substitutionplan.fragments.PersonalPlanFragment
|
|
|
|
|
import com.denizd.substitutionplan.fragments.SettingsFragment
|
|
|
|
|
import com.denizd.substitutionplan.services.FBPingService
|
2019-05-14 22:28:45 +02:00
|
|
|
import com.google.android.material.appbar.AppBarLayout
|
|
|
|
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
|
|
|
|
import com.google.android.material.snackbar.Snackbar
|
2019-09-03 18:18:21 +02:00
|
|
|
import com.google.firebase.FirebaseApp
|
2019-05-14 22:28:45 +02:00
|
|
|
import java.lang.IllegalArgumentException
|
2019-10-12 21:03:34 +02:00
|
|
|
import java.lang.NullPointerException
|
2019-05-14 22:28:45 +02:00
|
|
|
import java.util.*
|
|
|
|
|
|
2019-09-22 19:46:20 +02:00
|
|
|
/**
|
|
|
|
|
* The main class of the app. This controls navigation and enables the user to navigate through the
|
|
|
|
|
* app's fragments and view the information provided on the substitution table. Theming as well as
|
|
|
|
|
* setting up Firebase Cloud Messaging and Crashlytics are handled here. Also checks whether
|
|
|
|
|
* the user has completed the setup (logging in, setting preferences)
|
|
|
|
|
*/
|
2019-09-01 11:54:12 +02:00
|
|
|
internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
2019-05-14 22:28:45 +02:00
|
|
|
|
2019-07-30 16:58:51 +02:00
|
|
|
private lateinit var context: Context
|
|
|
|
|
private lateinit var prefs: SharedPreferences
|
2019-05-14 22:28:45 +02:00
|
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
|
super.onCreate(savedInstanceState)
|
2019-07-30 16:58:51 +02:00
|
|
|
context = this
|
2019-09-20 15:49:09 +02:00
|
|
|
prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
2019-05-14 22:28:45 +02:00
|
|
|
val edit = prefs.edit()
|
2019-08-14 12:36:54 +02:00
|
|
|
|
2019-09-22 19:46:20 +02:00
|
|
|
/**
|
2019-10-12 21:03:34 +02:00
|
|
|
* This when-cascade allows the user to return to any point of the setup if they
|
2019-09-22 19:46:20 +02:00
|
|
|
* decide to postpone it, e.g. logging in but not setting up their preferences. Furthermore,
|
|
|
|
|
* it prevents existing users from upgrading from a previous version of the app and skip the
|
|
|
|
|
* mandatory login
|
|
|
|
|
*/
|
2019-10-12 21:03:34 +02:00
|
|
|
when {
|
|
|
|
|
!prefs.getBoolean("successful_login", false) -> { // launch the login screen
|
|
|
|
|
startActivity(Intent(context, Login::class.java))
|
|
|
|
|
finish()
|
2019-08-09 21:18:27 +02:00
|
|
|
}
|
2019-10-12 21:03:34 +02:00
|
|
|
prefs.getBoolean("firstTime", true) -> { // launch the first time setup screen
|
|
|
|
|
startActivity(Intent(context, FirstTime::class.java))
|
|
|
|
|
finish()
|
2019-09-05 18:20:30 +02:00
|
|
|
}
|
2019-10-12 21:03:34 +02:00
|
|
|
else -> { // launch the app
|
2019-09-05 18:20:30 +02:00
|
|
|
|
2019-10-12 21:03:34 +02:00
|
|
|
if (!prefs.getBoolean("colourTransferred", false)) {
|
|
|
|
|
HelperFunctions.transferOldColourIntsToString(prefs)
|
|
|
|
|
edit.putBoolean("colourTransferred", true).apply()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edit.putInt("launchDev", prefs.getInt("launchDev", 0) + 1)
|
|
|
|
|
edit.apply()
|
|
|
|
|
|
|
|
|
|
FirebaseApp.initializeApp(this)
|
|
|
|
|
pingFirebaseTopics()
|
|
|
|
|
|
|
|
|
|
val appBarLayout = findViewById<AppBarLayout>(R.id.appbarlayout)
|
|
|
|
|
val toolbarTxt = findViewById<TextView>(R.id.toolbarTxt)
|
|
|
|
|
val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav)
|
|
|
|
|
val contextView = findViewById<View>(R.id.coordination)
|
|
|
|
|
val window = this.window
|
|
|
|
|
|
|
|
|
|
/// Sets the theme explicitly to dismiss the splash screen
|
|
|
|
|
setTheme(R.style.AppTheme0)
|
|
|
|
|
|
|
|
|
|
/// Sets the system bar's colours according to the current Android version
|
|
|
|
|
val barColour = when {
|
|
|
|
|
Build.VERSION.SDK_INT < Build.VERSION_CODES.M -> ContextCompat.getColor(context, R.color.legacyBlack)
|
|
|
|
|
Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> ContextCompat.getColor(context, R.color.colorBackground)
|
|
|
|
|
else -> 0
|
|
|
|
|
}
|
|
|
|
|
if (barColour != 0) {
|
|
|
|
|
window.navigationBarColor = barColour
|
|
|
|
|
window.statusBarColor = barColour
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Applies theming with additional workarounds for API levels 23-28 (M-P)
|
|
|
|
|
when (prefs.getInt("themeInt", 0)) {
|
|
|
|
|
0 -> {
|
|
|
|
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
|
|
|
|
if (Build.VERSION.SDK_INT in 23..28) {
|
|
|
|
|
@SuppressLint("InlinedApi")
|
|
|
|
|
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
2 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
|
|
|
|
else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Displays the date and time of the last refresh of the substitution plan in a snack bar
|
|
|
|
|
if (!prefs.getBoolean("autoRefresh", false) && prefs.getInt("firstTimeOpening", 0) != 0) {
|
|
|
|
|
try {
|
|
|
|
|
Snackbar.make(contextView, "${getString(R.string.last_updated)} ${prefs.getString("timeNew", "")}", Snackbar.LENGTH_LONG).show()
|
|
|
|
|
} catch (e: IllegalArgumentException) {
|
2019-05-21 18:55:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-05-14 22:28:45 +02:00
|
|
|
|
2019-10-12 21:03:34 +02:00
|
|
|
/**
|
|
|
|
|
* Retrieves the greeting string if enabled by the user, sets it empty otherwise.
|
|
|
|
|
* Don't set the text view of the greeting string to View.GONE, as that will mess
|
|
|
|
|
* with the constraints
|
|
|
|
|
*/
|
|
|
|
|
val textViewGreeting = findViewById<TextView>(R.id.text_greeting)
|
|
|
|
|
textViewGreeting.text = if (
|
|
|
|
|
prefs.getBoolean("greeting", true)
|
|
|
|
|
&& (prefs.getString("username", "") ?: "").isNotEmpty()
|
|
|
|
|
) {
|
|
|
|
|
getGreetingString()
|
2019-05-21 18:55:29 +02:00
|
|
|
} else {
|
2019-10-12 21:03:34 +02:00
|
|
|
""
|
2019-05-21 18:55:29 +02:00
|
|
|
}
|
2019-05-14 22:28:45 +02:00
|
|
|
|
2019-10-12 21:03:34 +02:00
|
|
|
/// Legacy function
|
|
|
|
|
if (prefs.getInt("firstTimeOpening", 0) == 0) {
|
|
|
|
|
edit.putInt("firstTimeOpening", prefs.getInt("firstTimeOpening", 0) + 1).apply()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Launch the user-specified fragment (general or personal plan)
|
|
|
|
|
val defaultFragment = if (prefs.getBoolean("defaultPersonalised", false)) {
|
|
|
|
|
bottomNav.selectedItemId = R.id.personal
|
|
|
|
|
toolbarTxt.text = personalPlanTitle()
|
|
|
|
|
PersonalPlanFragment()
|
|
|
|
|
} else {
|
|
|
|
|
bottomNav.selectedItemId = R.id.plan
|
|
|
|
|
toolbarTxt.text = getString(R.string.app_name)
|
|
|
|
|
GeneralPlanFragment()
|
|
|
|
|
}
|
|
|
|
|
loadFragment(defaultFragment)
|
|
|
|
|
|
|
|
|
|
/// Opens the corresponding fragment or the info dialog
|
|
|
|
|
bottomNav.setOnNavigationItemSelectedListener { item: MenuItem ->
|
|
|
|
|
val fragment = when (item.itemId) {
|
|
|
|
|
R.id.plan -> {
|
|
|
|
|
toolbarTxt.text = getString(R.string.app_name)
|
|
|
|
|
GeneralPlanFragment()
|
|
|
|
|
}
|
|
|
|
|
R.id.personal -> {
|
|
|
|
|
toolbarTxt.text = personalPlanTitle()
|
|
|
|
|
PersonalPlanFragment()
|
|
|
|
|
}
|
|
|
|
|
R.id.menu -> {
|
|
|
|
|
toolbarTxt.text = getString(R.string.food_menu)
|
|
|
|
|
FoodFragment()
|
|
|
|
|
}
|
|
|
|
|
R.id.openinfopanel -> {
|
|
|
|
|
openInfoDialog()
|
|
|
|
|
null
|
|
|
|
|
}
|
|
|
|
|
else -> {
|
|
|
|
|
toolbarTxt.text = getString(R.string.settings)
|
|
|
|
|
SettingsFragment()
|
|
|
|
|
}
|
2019-05-14 22:28:45 +02:00
|
|
|
}
|
2019-10-12 21:03:34 +02:00
|
|
|
if (fragment == null) {
|
|
|
|
|
false
|
|
|
|
|
} else {
|
|
|
|
|
appBarLayout.setExpanded(true)
|
|
|
|
|
loadFragment(fragment)
|
2019-05-14 22:28:45 +02:00
|
|
|
}
|
2019-10-12 21:03:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Scrolls to the top of any currently displayed fragment
|
|
|
|
|
bottomNav.setOnNavigationItemReselectedListener { item: MenuItem ->
|
|
|
|
|
when (item.itemId) {
|
|
|
|
|
R.id.plan, R.id.personal, R.id.menu -> {
|
|
|
|
|
try {
|
|
|
|
|
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
|
|
|
|
|
recyclerView.post {
|
|
|
|
|
recyclerView.smoothScrollToPosition(0)
|
|
|
|
|
}
|
|
|
|
|
appBarLayout.setExpanded(true)
|
|
|
|
|
} catch (e: NullPointerException) {
|
2019-06-02 17:57:57 +02:00
|
|
|
}
|
2019-10-12 21:03:34 +02:00
|
|
|
}
|
|
|
|
|
R.id.settings -> {
|
|
|
|
|
try {
|
|
|
|
|
val nsv = findViewById<NestedScrollView>(R.id.settings_scroll_view)
|
|
|
|
|
nsv.post {
|
|
|
|
|
nsv.smoothScrollTo(0, 0)
|
|
|
|
|
}
|
|
|
|
|
appBarLayout.setExpanded(true)
|
|
|
|
|
} catch (e: NullPointerException) {
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-14 22:28:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-22 19:46:20 +02:00
|
|
|
/**
|
|
|
|
|
* Picks a greeting according to the time of day to present to the user if they choose to
|
|
|
|
|
* enable greetings
|
|
|
|
|
*
|
|
|
|
|
* @return the greeting
|
|
|
|
|
*/
|
2019-07-30 22:48:13 +02:00
|
|
|
private fun getGreetingString(): String {
|
|
|
|
|
val gen = Random()
|
2019-08-02 13:35:54 +02:00
|
|
|
return String.format(when (Calendar.getInstance().get(Calendar.HOUR_OF_DAY)) {
|
2019-09-22 13:39:20 +02:00
|
|
|
in 5..10 -> resources.getStringArray(R.array.greetings_morning)[gen.nextInt(resources.getStringArray(
|
|
|
|
|
R.array.greetings_morning
|
2019-09-01 11:54:12 +02:00
|
|
|
).size)]
|
2019-09-22 13:39:20 +02:00
|
|
|
in 11..17 -> resources.getStringArray(R.array.greetings_noon)[gen.nextInt(resources.getStringArray(
|
|
|
|
|
R.array.greetings_noon
|
2019-09-01 11:54:12 +02:00
|
|
|
).size)]
|
2019-09-22 13:39:20 +02:00
|
|
|
else -> resources.getStringArray(R.array.greetings_evening)[gen.nextInt(resources.getStringArray(
|
|
|
|
|
R.array.greetings_evening
|
2019-09-01 11:54:12 +02:00
|
|
|
).size)]
|
2019-08-02 13:35:54 +02:00
|
|
|
}, prefs.getString("username", ""))
|
2019-07-30 22:48:13 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-01 10:38:41 +02:00
|
|
|
/**
|
|
|
|
|
* Retrieves the strings provided in the substitution plan's info boxes as well as the
|
|
|
|
|
* refresh date and time from Shared Preferences and displays them in a dialog
|
|
|
|
|
*/
|
2019-07-30 16:58:51 +02:00
|
|
|
private fun openInfoDialog() {
|
|
|
|
|
val dialog = AlertDialog.Builder(context)
|
2019-09-19 07:33:16 +02:00
|
|
|
val dialogView = View.inflate(context, R.layout.simple_dialog, null)
|
2019-09-01 11:54:12 +02:00
|
|
|
dialogView.findViewById<TextView>(R.id.textviewtitle).text = getString(
|
|
|
|
|
R.string.information
|
|
|
|
|
)
|
2019-09-22 13:39:20 +02:00
|
|
|
val dialogText = "${getString(R.string.last_updated)} ${prefs.getString("timeNew", "")}.\n\n${prefs.getString("informational", "")}".trim()
|
2019-07-31 11:27:46 +02:00
|
|
|
dialogView.findViewById<TextView>(R.id.dialogtext).text = dialogText
|
2019-07-30 16:58:51 +02:00
|
|
|
dialog.setView(dialogView).show()
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 22:28:45 +02:00
|
|
|
private fun loadFragment(fragment: Fragment): Boolean {
|
2019-07-30 16:58:51 +02:00
|
|
|
supportFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit()
|
2019-05-14 22:28:45 +02:00
|
|
|
return true
|
|
|
|
|
}
|
2019-08-21 10:26:54 +02:00
|
|
|
|
2019-10-01 10:38:41 +02:00
|
|
|
/// Triggers FBPingService.kt to re-subscribe to the selected Firebase topics every 15 minutes
|
2019-08-21 10:26:54 +02:00
|
|
|
private fun pingFirebaseTopics() {
|
|
|
|
|
val componentName = ComponentName(this, FBPingService::class.java)
|
|
|
|
|
val info = JobInfo.Builder(42, componentName)
|
|
|
|
|
.setRequiresCharging(false)
|
|
|
|
|
.setPersisted(true)
|
|
|
|
|
.setPeriodic(900000)
|
|
|
|
|
.build()
|
|
|
|
|
val scheduler = getSystemService(JOB_SCHEDULER_SERVICE) as JobScheduler
|
|
|
|
|
scheduler.schedule(info)
|
|
|
|
|
}
|
2019-09-13 12:03:14 +02:00
|
|
|
|
2019-09-22 19:46:20 +02:00
|
|
|
/**
|
|
|
|
|
* Decides on the title for PersonalPlanFragment.kt. Picks a generic "Your plan" if greetings
|
|
|
|
|
* are enabled or "$user's Plan" if they are disabled
|
|
|
|
|
*
|
|
|
|
|
* @return the title
|
|
|
|
|
*/
|
2019-09-13 12:03:14 +02:00
|
|
|
private fun personalPlanTitle(): String {
|
2019-09-20 15:49:09 +02:00
|
|
|
val user = prefs.getString("username", "") ?: ""
|
|
|
|
|
return if (prefs.getBoolean("greeting", true) || user.isEmpty()) {
|
2019-09-13 12:03:14 +02:00
|
|
|
getString(R.string.yourPlan)
|
|
|
|
|
} else {
|
|
|
|
|
if (user.endsWith("s", true) || user.endsWith("x", true) || user.endsWith("z", true)) {
|
2019-09-22 13:39:20 +02:00
|
|
|
"$user${getString(R.string.no_s_plan)}"
|
2019-09-13 12:03:14 +02:00
|
|
|
} else {
|
2019-09-22 13:39:20 +02:00
|
|
|
"$user${getString(R.string.s_plan)}"
|
2019-09-13 12:03:14 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-14 22:28:45 +02:00
|
|
|
}
|