From d2f14bd03e381a00949069308d112ac0e6ab7c92 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Thu, 30 Apr 2020 08:47:07 +0200 Subject: [PATCH 1/8] Updated README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 712aa89..9a68990 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,10 @@ Currently, the application supports: + Send notifications at specific time. This feature was developed using the Android's - [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager). + [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) + but because the notifications were not working as expected (they were almost + always delayed) the app now uses AlarmManager for waking the device at + specific time, even if it is in Doze mode. + Detect user activity and send a notification when ends an specific one. For example, if he gets out of a vehicle, or has just finished running, etc. This was developed using Google's [Activity Recognition From 7a1b6a56e4f9ec59bac2f01743893e3b4583edd9 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Thu, 30 Apr 2020 17:40:17 +0200 Subject: [PATCH 2/8] Updated Fragments with zero argument constructor Having no default constructor causes orientation changes (for example) not to be able to recreate the fragment. This is because the constructor is called using reflection and uses the zero argument constructor by default. With this approach screen rotation should be fine --- app/build.gradle | 2 +- .../diseases}/DiseaseDescriptionFragment.kt | 23 ++++++++++---- .../DiseaseExtraInformationFragment.kt | 30 ++++++++++++------- .../collections/DiseaseTextAdapter.kt | 18 ++++++++--- .../PrivacyTermsCollectionAdapter.kt | 2 +- 5 files changed, 53 insertions(+), 22 deletions(-) rename app/src/main/java/com/javinator9889/handwashingreminder/{collections => activities/views/fragments/diseases}/DiseaseDescriptionFragment.kt (77%) rename app/src/main/java/com/javinator9889/handwashingreminder/{collections => activities/views/fragments/diseases}/DiseaseExtraInformationFragment.kt (67%) diff --git a/app/build.gradle b/app/build.gradle index 6ced094..4103595 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,7 +42,7 @@ android { applicationId "com.javinator9889.handwashingreminder" minSdkVersion 17 targetSdkVersion 29 - versionCode 118 + versionCode 119 versionName "1.1.2-${gitCommitHash}" multiDexEnabled true resConfigs "en", "es" diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseDescriptionFragment.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt similarity index 77% rename from app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseDescriptionFragment.kt rename to app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt index 6492267..55b26fd 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseDescriptionFragment.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt @@ -16,7 +16,7 @@ * * Created by Javinator9889 on 19/04/20 - Handwashing reminder. */ -package com.javinator9889.handwashingreminder.collections +package com.javinator9889.handwashingreminder.activities.views.fragments.diseases import android.os.Bundle import androidx.annotation.LayoutRes @@ -24,19 +24,30 @@ import com.javinator9889.handwashingreminder.R import com.javinator9889.handwashingreminder.activities.base.BaseFragmentView import com.javinator9889.handwashingreminder.activities.views.viewmodels.ParsedHTMLText import kotlinx.android.synthetic.main.disease_description.* +import kotlin.properties.Delegates internal const val ARG_TITLE = "bundle:title" internal const val ARG_SDESC = "bundle:description:short" internal const val ARG_LDESC = "bundle:description:long" internal const val ARG_PROVIDER = "bundle:provider" internal const val ARG_WEBSITE = "bundle:website" +internal const val ARG_ANIMATION_ID = "bundle:animation:id" +internal const val ARG_HTML_TEXT = "bundle:text:html" -class DiseaseDescriptionFragment( - private val parsedHTMLText: ParsedHTMLText, - private val animId: Int -) : BaseFragmentView() { +class DiseaseDescriptionFragment : BaseFragmentView() { @get:LayoutRes override val layoutId: Int = R.layout.disease_description + private lateinit var parsedHTMLText: ParsedHTMLText + private var animId by Delegates.notNull() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (savedInstanceState != null || arguments != null) { + val data = savedInstanceState ?: arguments + parsedHTMLText = data!!.getParcelable(ARG_HTML_TEXT)!! + animId = data.getInt(ARG_ANIMATION_ID) + } + } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) @@ -45,6 +56,8 @@ class DiseaseDescriptionFragment( outState.putCharSequence(ARG_LDESC, longDescription.text) outState.putCharSequence(ARG_PROVIDER, provider.text) outState.putCharSequence(ARG_WEBSITE, website.text) + outState.putParcelable(ARG_HTML_TEXT, parsedHTMLText) + outState.putInt(ARG_ANIMATION_ID, animId) } override fun onActivityCreated(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseExtraInformationFragment.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt similarity index 67% rename from app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseExtraInformationFragment.kt rename to app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt index 0f8024b..df3b758 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseExtraInformationFragment.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt @@ -16,24 +16,34 @@ * * Created by Javinator9889 on 19/04/20 - Handwashing reminder. */ -package com.javinator9889.handwashingreminder.collections +package com.javinator9889.handwashingreminder.activities.views.fragments.diseases import android.os.Bundle import androidx.annotation.LayoutRes import com.javinator9889.handwashingreminder.R import com.javinator9889.handwashingreminder.activities.base.BaseFragmentView +import com.javinator9889.handwashingreminder.activities.views.fragments.washinghands.ARG_POSITION import com.javinator9889.handwashingreminder.activities.views.viewmodels.ParsedHTMLText import kotlinx.android.synthetic.main.simple_text_view.* +import kotlin.properties.Delegates internal const val ARG_SYMPTOMS = "bundle:symptoms" internal const val ARG_PREVENTION = "bundle:prevention" -class DiseaseExtraInformationFragment( - private val position: Int, - private val parsedHTMLText: ParsedHTMLText -) : BaseFragmentView() { +class DiseaseExtraInformationFragment : BaseFragmentView() { @get:LayoutRes override val layoutId: Int = R.layout.simple_text_view + private var position by Delegates.notNull() + private lateinit var parsedHTMLText: ParsedHTMLText + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (savedInstanceState != null || arguments != null) { + val data = savedInstanceState ?: arguments + position = data!!.getInt(ARG_POSITION) + parsedHTMLText = data.getParcelable(ARG_HTML_TEXT)!! + } + } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) @@ -41,18 +51,16 @@ class DiseaseExtraInformationFragment( outState.putCharSequence(ARG_SYMPTOMS, text.text) else if (position == 2) outState.putCharSequence(ARG_PREVENTION, text.text) + outState.putInt(ARG_POSITION, position) + outState.putParcelable(ARG_HTML_TEXT, parsedHTMLText) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) text.text = when (position) { - 1 -> savedInstanceState.getCharSequence( - ARG_SYMPTOMS - ) - 2 -> savedInstanceState.getCharSequence( - ARG_PREVENTION - ) + 1 -> savedInstanceState.getCharSequence(ARG_SYMPTOMS) + 2 -> savedInstanceState.getCharSequence(ARG_PREVENTION) else -> "" } else diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt b/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt index 475579b..97e7e35 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt @@ -18,22 +18,32 @@ */ package com.javinator9889.handwashingreminder.collections +import android.os.Bundle import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter +import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.ARG_ANIMATION_ID +import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.ARG_HTML_TEXT +import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.DiseaseDescriptionFragment +import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.DiseaseExtraInformationFragment import com.javinator9889.handwashingreminder.activities.views.viewmodels.ParsedHTMLText class DiseaseTextAdapter( fm: FragmentActivity, private val animId: Int, private val parsedHTMLText: ParsedHTMLText -) : - FragmentStateAdapter(fm) { +) : FragmentStateAdapter(fm) { override fun getItemCount(): Int = 3 override fun createFragment(position: Int): Fragment = when (position) { - 0 -> DiseaseDescriptionFragment(parsedHTMLText, animId) - 1, 2 -> DiseaseExtraInformationFragment(position, parsedHTMLText) + 0 -> DiseaseDescriptionFragment() + 1, 2 -> DiseaseExtraInformationFragment() else -> Fragment() + }.apply { + val bundle = Bundle(3) + bundle.putInt(ARG_POSITION, position) + bundle.putInt(ARG_ANIMATION_ID, animId) + bundle.putParcelable(ARG_HTML_TEXT, parsedHTMLText) + arguments = bundle } } \ No newline at end of file diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/collections/PrivacyTermsCollectionAdapter.kt b/app/src/main/java/com/javinator9889/handwashingreminder/collections/PrivacyTermsCollectionAdapter.kt index d11d94c..d10d587 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/collections/PrivacyTermsCollectionAdapter.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/collections/PrivacyTermsCollectionAdapter.kt @@ -46,7 +46,7 @@ class PrivacyTermsCollectionAdapter(fm: FragmentActivity) : } -private const val ARG_POSITION = "item:position" +internal const val ARG_POSITION = "item:position" class PolicyTextViewFragment : BaseFragment() { override fun onCreateView( From 156f50ff4f1211f9b9f88865ae535cea738a1488 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Thu, 30 Apr 2020 17:59:08 +0200 Subject: [PATCH 3/8] Updated application for reducing items to initialize inside the "onCreate" method --- app/build.gradle | 2 +- .../activities/LauncherActivity.kt | 19 +++++++++---------- .../views/fragments/diseases/adapter/Ads.kt | 2 +- .../fragments/settings/ActivityCheckbox.kt | 2 +- .../settings/ActivityMultiSelectList.kt | 2 +- .../views/fragments/settings/SettingsView.kt | 10 ++++++---- .../activities/views/viewmodels/VideoModel.kt | 3 +-- .../views/viewmodels/WashingHandsModel.kt | 2 +- .../application/HandwashingApplication.kt | 10 +--------- .../jobs/BootCompletedJob.kt | 5 +++-- .../workers/ScheduledNotificationWorker.kt | 2 +- .../handwashingreminder/utils/Android.kt | 6 +++--- .../handwashingreminder/utils/Graphics.kt | 4 ++-- .../appintro/IntroActivity.kt | 5 +++-- 14 files changed, 34 insertions(+), 40 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4103595..9a9ed13 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -171,7 +171,7 @@ dependencies { // https://developer.android.com/jetpack/androidx/releases/lifecycle#declaring_dependencies implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0' // https://developer.android.com/reference/kotlin/androidx/preference/package-summary - implementation 'androidx.preference:preference:1.1.1' + api 'androidx.preference:preference-ktx:1.1.1' // https://github.com/bumptech/glide api 'com.github.bumptech.glide:glide:4.11.0' kapt 'com.github.bumptech.glide:compiler:4.11.0' diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt index 4c57aa7..911284c 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt @@ -27,6 +27,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import androidx.lifecycle.whenCreated import androidx.lifecycle.whenStarted +import androidx.preference.PreferenceManager import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GoogleApiAvailability import com.google.android.play.core.splitcompat.SplitCompat @@ -41,7 +42,6 @@ import com.javinator9889.handwashingreminder.application.HandwashingApplication import com.javinator9889.handwashingreminder.emoji.EmojiLoader import com.javinator9889.handwashingreminder.gms.ads.AdLoader import com.javinator9889.handwashingreminder.gms.ads.AdsEnabler -import com.javinator9889.handwashingreminder.gms.vendor.BillingService import com.javinator9889.handwashingreminder.jobs.alarms.AlarmHandler import com.javinator9889.handwashingreminder.utils.* import com.javinator9889.handwashingreminder.utils.Preferences.Companion.ADS_ENABLED @@ -65,13 +65,14 @@ class LauncherActivity : AppCompatActivity() { private var launchOnInstall = false private var launchFromNotification = false private var canFinishActivity = false + private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) private lateinit var app: HandwashingApplication private lateinit var initDeferred: Deferred init { lifecycleScope.launch { whenCreated { - app = HandwashingApplication.getInstance() + app = HandwashingApplication.instance with(intent) { notNull { launchFromNotification = @@ -141,7 +142,7 @@ class LauncherActivity : AppCompatActivity() { super.onActivityResult(requestCode, resultCode, data) if (requestCode == DYNAMIC_FEATURE_INSTALL_RESULT_CODE) { EmojiLoader.get(this) - if (app.sharedPreferences.getBoolean(ADS_ENABLED, true)) { + if (sharedPreferences.getBoolean(ADS_ENABLED, true)) { when (resultCode) { Activity.RESULT_OK -> { initAds() @@ -183,9 +184,9 @@ class LauncherActivity : AppCompatActivity() { private fun installRequiredModules() { val modules = ArrayList(MODULE_COUNT) val googleApi = GoogleApiAvailability.getInstance() - if (app.sharedPreferences.getBoolean(ADS_ENABLED, true)) + if (sharedPreferences.getBoolean(ADS_ENABLED, true)) modules += Ads.MODULE_NAME - if (!app.sharedPreferences.getBoolean(APP_INIT_KEY, false)) { + if (!sharedPreferences.getBoolean(APP_INIT_KEY, false)) { modules += AppIntro.MODULE_NAME launchOnInstall = true } @@ -247,7 +248,7 @@ class LauncherActivity : AppCompatActivity() { Timber.d("Setting-up security providers") Security.insertProviderAt(Conscrypt.newProvider(), 1) Timber.d("Setting-up activity recognition") - if (app.sharedPreferences.getBoolean( + if (sharedPreferences.getBoolean( Preferences.ACTIVITY_TRACKING_ENABLED, false ) && with(GoogleApiAvailability.getInstance()) { isGooglePlayServicesAvailable(this@LauncherActivity) == @@ -258,8 +259,6 @@ class LauncherActivity : AppCompatActivity() { } else { app.activityHandler.disableActivityTracker() } - Timber.d("Initializing Billing Service") - app.billingService = BillingService(this) with(AlarmHandler(this)) { scheduleAllAlarms() } @@ -306,13 +305,13 @@ class LauncherActivity : AppCompatActivity() { } } firebaseAnalytics.setAnalyticsCollectionEnabled( - app.sharedPreferences.getBoolean( + sharedPreferences.getBoolean( Preferences.ANALYTICS_ENABLED, true ) ) firebasePerformance.isPerformanceCollectionEnabled = - app.sharedPreferences.getBoolean( + sharedPreferences.getBoolean( Preferences.PERFORMANCE_ENABLED, true ) diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/adapter/Ads.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/adapter/Ads.kt index f00e806..5849a81 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/adapter/Ads.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/adapter/Ads.kt @@ -33,7 +33,7 @@ class Ads : AbstractItem() { override fun getViewHolder(v: View): ViewHolder = ViewHolder(v) class ViewHolder(v: View) : FastAdapter.ViewHolder(v) { - private val ads = HandwashingApplication.getInstance().adLoader + private val ads = HandwashingApplication.instance.adLoader private val container = v.findViewById(R.id.adsContainer) override fun bindView(item: Ads, payloads: List) { diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityCheckbox.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityCheckbox.kt index aa3923e..b2c87ee 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityCheckbox.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityCheckbox.kt @@ -89,7 +89,7 @@ class ActivityCheckbox : CheckBoxPreference { firstCheck = false return } - with(HandwashingApplication.getInstance()) { + with(HandwashingApplication.instance) { if (checked) { activityHandler.startTrackingActivity() } else { diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityMultiSelectList.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityMultiSelectList.kt index 374d356..8d0db50 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityMultiSelectList.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/ActivityMultiSelectList.kt @@ -82,7 +82,7 @@ class ActivityMultiSelectList : MultiSelectListPreference { } private fun reloadActivityHandler() { - with(HandwashingApplication.getInstance()) { + with(HandwashingApplication.instance) { activityHandler.reload() } } diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt index ad9823c..b7e44fa 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt @@ -41,6 +41,7 @@ import com.javinator9889.handwashingreminder.application.HandwashingApplication import com.javinator9889.handwashingreminder.emoji.EmojiLoader import com.javinator9889.handwashingreminder.gms.ads.AdsEnabler import com.javinator9889.handwashingreminder.gms.splitservice.SplitInstallService +import com.javinator9889.handwashingreminder.gms.vendor.BillingService import com.javinator9889.handwashingreminder.jobs.alarms.Alarms import com.javinator9889.handwashingreminder.listeners.OnPurchaseFinishedListener import com.javinator9889.handwashingreminder.utils.* @@ -62,11 +63,13 @@ class SettingsView : PreferenceFragmentCompat(), private lateinit var adsPreference: WeakReference private lateinit var donationsPreference: WeakReference private lateinit var emojiCompat: EmojiCompat - private val app = HandwashingApplication.getInstance() + private lateinit var billingService: BillingService + private val app = HandwashingApplication.instance override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requireActivity().setTheme(R.style.AppTheme_MaterialDialogs) + billingService = BillingService(requireContext()) } override fun onCreatePreferences( @@ -206,8 +209,7 @@ class SettingsView : PreferenceFragmentCompat(), else resources.getTextArray(R.array.in_app_donations) it.icon = icon(Ionicons.Icon.ion_card) - app.billingService - .addOnPurchaseFinishedListener(this@SettingsView) + billingService.addOnPurchaseFinishedListener(this@SettingsView) donationsPreference = WeakReference(it) } translations?.let { @@ -402,7 +404,7 @@ class SettingsView : PreferenceFragmentCompat(), Timber.d("Purchase clicked - $newValue") val purchaseId = newValue as String if (isConnected()) - app.billingService.doPurchase(purchaseId, requireActivity()) + billingService.doPurchase(purchaseId, requireActivity()) else { if (context == null) return false diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/VideoModel.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/VideoModel.kt index d025e8f..09c6ed2 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/VideoModel.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/VideoModel.kt @@ -48,8 +48,7 @@ private const val LIVEDATA_KEY = "videomodel:livedata" class VideoModel( private val state: SavedStateHandle, private val position: Int ) : ViewModel() { - private val cachePath: File = - HandwashingApplication.getInstance().applicationContext.cacheDir + private val cachePath: File = HandwashingApplication.instance.applicationContext.cacheDir val videos: LiveData = liveData { emitSource(state.getLiveData(LIVEDATA_KEY, loadVideo())) } diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/WashingHandsModel.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/WashingHandsModel.kt index afa4234..79d2c19 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/WashingHandsModel.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/viewmodels/WashingHandsModel.kt @@ -76,7 +76,7 @@ class WashingHandsModel( } private suspend fun processStringArray(@ArrayRes array: Int): CharSequence = - with(HandwashingApplication.getInstance()) { + with(HandwashingApplication.instance) { with(EmojiLoader.get(this)) { try { this.await() diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/application/HandwashingApplication.kt b/app/src/main/java/com/javinator9889/handwashingreminder/application/HandwashingApplication.kt index 8b2136f..0b192d7 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/application/HandwashingApplication.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/application/HandwashingApplication.kt @@ -27,7 +27,6 @@ import com.google.firebase.FirebaseApp import com.google.firebase.crashlytics.FirebaseCrashlytics import com.javinator9889.handwashingreminder.gms.activity.ActivityHandler import com.javinator9889.handwashingreminder.gms.ads.AdLoader -import com.javinator9889.handwashingreminder.gms.vendor.BillingService import com.javinator9889.handwashingreminder.utils.LogReportTree import com.javinator9889.handwashingreminder.utils.isDebuggable import javinator9889.localemanager.application.BaseApplication @@ -38,17 +37,11 @@ import timber.log.Timber class HandwashingApplication : BaseApplication() { var adLoader: AdLoader? = null - lateinit var billingService: BillingService lateinit var activityHandler: ActivityHandler - lateinit var sharedPreferences: SharedPreferences lateinit var firebaseInitDeferred: Deferred companion object { - private lateinit var instance: HandwashingApplication - - fun getInstance(): HandwashingApplication { - return this.instance - } + lateinit var instance: HandwashingApplication } override fun attachBaseContext(base: Context?) { @@ -63,7 +56,6 @@ class HandwashingApplication : BaseApplication() { override fun onCreate() { super.onCreate() instance = this - sharedPreferences = getCustomSharedPreferences(this) activityHandler = ActivityHandler(this) firebaseInitDeferred = initFirebaseAppAsync() } diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/jobs/BootCompletedJob.kt b/app/src/main/java/com/javinator9889/handwashingreminder/jobs/BootCompletedJob.kt index 86c662e..1a614c9 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/jobs/BootCompletedJob.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/jobs/BootCompletedJob.kt @@ -21,6 +21,7 @@ package com.javinator9889.handwashingreminder.jobs import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import androidx.preference.PreferenceManager import com.javinator9889.handwashingreminder.application.HandwashingApplication import com.javinator9889.handwashingreminder.jobs.alarms.AlarmHandler import com.javinator9889.handwashingreminder.utils.Preferences @@ -29,8 +30,8 @@ import timber.log.Timber class BootCompletedJob : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == Intent.ACTION_BOOT_COMPLETED) { - val app = HandwashingApplication.getInstance() - val preferences = app.sharedPreferences + val app = HandwashingApplication.instance + val preferences = PreferenceManager.getDefaultSharedPreferences(context) if (preferences.getBoolean( Preferences.ACTIVITY_TRACKING_ENABLED, false diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/jobs/workers/ScheduledNotificationWorker.kt b/app/src/main/java/com/javinator9889/handwashingreminder/jobs/workers/ScheduledNotificationWorker.kt index 6335e8f..10d633c 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/jobs/workers/ScheduledNotificationWorker.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/jobs/workers/ScheduledNotificationWorker.kt @@ -72,7 +72,7 @@ abstract class ScheduledNotificationWorker(context: Context) { .currentTimeMillis() - startTime}ms" ) } catch (e: Exception) { - with(HandwashingApplication.getInstance()) { + with(HandwashingApplication.instance) { // Don't use so much resources, wait at most half a second until // Firebase initializes or continue with execution. // Firebase is only needed for Timber (Crashlytics) so until diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/utils/Android.kt b/app/src/main/java/com/javinator9889/handwashingreminder/utils/Android.kt index 7e0a8d7..eadf927 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/utils/Android.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/utils/Android.kt @@ -45,7 +45,7 @@ fun isAtLeast(version: AndroidVersion): Boolean = Build.VERSION.SDK_INT >= version.code fun isHighPerformingDevice(): Boolean { - with(HandwashingApplication.getInstance()) { + with(HandwashingApplication.instance) { val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val isLowRamDevice = @@ -59,7 +59,7 @@ fun isHighPerformingDevice(): Boolean { } fun isConnected(): Boolean { - val connectivityManager = HandwashingApplication.getInstance() + val connectivityManager = HandwashingApplication.instance .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager if (isAtLeast(AndroidVersion.M)) { val network = connectivityManager.activeNetwork ?: return false @@ -79,7 +79,7 @@ fun isConnected(): Boolean { } fun isDebuggable(): Boolean = - (0 != HandwashingApplication.getInstance().applicationInfo.flags and + (0 != HandwashingApplication.instance.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) fun getDeviceInfo(): String = with(StringBuilder()) { diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/utils/Graphics.kt b/app/src/main/java/com/javinator9889/handwashingreminder/utils/Graphics.kt index 49a992d..80cdf8b 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/utils/Graphics.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/utils/Graphics.kt @@ -27,7 +27,7 @@ import com.javinator9889.handwashingreminder.application.HandwashingApplication * @return A float value to represent px equivalent to dp depending on device density */ fun dpToPx(dp: Float): Float { - val context = HandwashingApplication.getInstance().applicationContext + val context = HandwashingApplication.instance.applicationContext return dp * context.resources.displayMetrics.density } @@ -38,6 +38,6 @@ fun dpToPx(dp: Float): Float { * @return A float value to represent dp equivalent to px value */ fun pxToDp(px: Float): Float { - val context = HandwashingApplication.getInstance().applicationContext + val context = HandwashingApplication.instance.applicationContext return px / context.resources.displayMetrics.density } \ No newline at end of file diff --git a/appintro/src/main/java/com/javinator9889/handwashingreminder/appintro/IntroActivity.kt b/appintro/src/main/java/com/javinator9889/handwashingreminder/appintro/IntroActivity.kt index 39b6830..002178f 100644 --- a/appintro/src/main/java/com/javinator9889/handwashingreminder/appintro/IntroActivity.kt +++ b/appintro/src/main/java/com/javinator9889/handwashingreminder/appintro/IntroActivity.kt @@ -30,6 +30,7 @@ import androidx.annotation.Keep import androidx.core.content.edit import androidx.core.util.set import androidx.fragment.app.Fragment +import androidx.preference.PreferenceManager import com.github.paolorotolo.appintro.AppIntro2 import com.github.paolorotolo.appintro.AppIntroViewPager import com.google.android.gms.common.ConnectionResult.SUCCESS @@ -165,8 +166,8 @@ class IntroActivity : AppIntro2(), override fun onDonePressed(currentFragment: Fragment?) { super.onDonePressed(currentFragment) - val app = HandwashingApplication.getInstance() - val sharedPreferences = app.sharedPreferences + val app = HandwashingApplication.instance + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) sharedPreferences.edit(commit = true) { timeConfigSlide.itemAdapter.adapterItems.forEach { item -> val time = "${item.hours}:${item.minutes}" From 86727a13bbed1ea41f3447e31cf62449609994fd Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Thu, 30 Apr 2020 18:59:24 +0200 Subject: [PATCH 4/8] Fixed initialization error for SharedPreferences in LauncherActivity The context is not yet initialized so wait until it is created --- app/build.gradle | 2 +- .../handwashingreminder/activities/LauncherActivity.kt | 5 ++++- .../activities/views/fragments/settings/SettingsView.kt | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9a9ed13..2b5a434 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,7 +42,7 @@ android { applicationId "com.javinator9889.handwashingreminder" minSdkVersion 17 targetSdkVersion 29 - versionCode 119 + versionCode 120 versionName "1.1.2-${gitCommitHash}" multiDexEnabled true resConfigs "en", "es" diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt index 911284c..67e11f0 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/LauncherActivity.kt @@ -20,6 +20,7 @@ package com.javinator9889.handwashingreminder.activities import android.app.Activity import android.content.Intent +import android.content.SharedPreferences import android.os.Bundle import android.view.animation.Animation import android.view.animation.AnimationUtils @@ -65,7 +66,7 @@ class LauncherActivity : AppCompatActivity() { private var launchOnInstall = false private var launchFromNotification = false private var canFinishActivity = false - private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) + private lateinit var sharedPreferences: SharedPreferences private lateinit var app: HandwashingApplication private lateinit var initDeferred: Deferred @@ -73,6 +74,8 @@ class LauncherActivity : AppCompatActivity() { lifecycleScope.launch { whenCreated { app = HandwashingApplication.instance + sharedPreferences = + PreferenceManager.getDefaultSharedPreferences(this@LauncherActivity) with(intent) { notNull { launchFromNotification = diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt index b7e44fa..adec01f 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt @@ -69,7 +69,6 @@ class SettingsView : PreferenceFragmentCompat(), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requireActivity().setTheme(R.style.AppTheme_MaterialDialogs) - billingService = BillingService(requireContext()) } override fun onCreatePreferences( @@ -81,6 +80,7 @@ class SettingsView : PreferenceFragmentCompat(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + billingService = BillingService(view.context) viewLifecycleOwner.lifecycleScope.launch { val emojiLoader = EmojiLoader.get(view.context) val share = findPreference("share") From 34821f42cbef751e6a2aadcd7c8c61167957ca65 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Fri, 1 May 2020 10:25:17 +0200 Subject: [PATCH 5/8] Solved an issue while displaying diseases information --- app/build.gradle | 3 +- .../activities/base/BaseFragmentView.kt | 5 +++ .../diseases/DiseaseDescriptionFragment.kt | 39 +++++++------------ .../DiseaseExtraInformationFragment.kt | 29 +++++--------- .../collections/DiseaseTextAdapter.kt | 1 + 5 files changed, 32 insertions(+), 45 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2b5a434..b0c70fc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,7 +42,7 @@ android { applicationId "com.javinator9889.handwashingreminder" minSdkVersion 17 targetSdkVersion 29 - versionCode 120 + versionCode 121 versionName "1.1.2-${gitCommitHash}" multiDexEnabled true resConfigs "en", "es" @@ -78,6 +78,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' multiDexEnabled = true signingConfig signingConfigs.release + versionNameSuffix "-stable" debuggable false jniDebuggable false diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt index 5a72d86..9ca79bd 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt @@ -29,6 +29,11 @@ abstract class BaseFragmentView : BaseFragment() { @get:LayoutRes protected abstract val layoutId: Int + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + retainInstance = true + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt index 55b26fd..9fc791b 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt @@ -40,15 +40,6 @@ class DiseaseDescriptionFragment : BaseFragmentView() { private lateinit var parsedHTMLText: ParsedHTMLText private var animId by Delegates.notNull() - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (savedInstanceState != null || arguments != null) { - val data = savedInstanceState ?: arguments - parsedHTMLText = data!!.getParcelable(ARG_HTML_TEXT)!! - animId = data.getInt(ARG_ANIMATION_ID) - } - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence(ARG_TITLE, title.text) @@ -62,22 +53,20 @@ class DiseaseDescriptionFragment : BaseFragmentView() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - animatedView.setAnimation(animId) - if (savedInstanceState != null) { - title.text = savedInstanceState.getCharSequence(ARG_TITLE) - shortDescription.text = - savedInstanceState.getCharSequence(ARG_SDESC) - longDescription.text = savedInstanceState.getCharSequence(ARG_LDESC) - provider.text = savedInstanceState.getCharSequence(ARG_PROVIDER) - website.text = savedInstanceState.getCharSequence(ARG_WEBSITE) - } else { - title.text = parsedHTMLText.name - shortDescription.text = parsedHTMLText.shortDescription - longDescription.text = parsedHTMLText.longDescription - provider.text = - getString(R.string.written_by, parsedHTMLText.provider) - website.text = - getString(R.string.available_at, parsedHTMLText.website) + if (savedInstanceState != null || arguments != null) { + val data = (savedInstanceState ?: arguments)!! + parsedHTMLText = data.getParcelable(ARG_HTML_TEXT)!! + animId = data.getInt(ARG_ANIMATION_ID) + animatedView.setAnimation(animId) + title.text = data.getCharSequence(ARG_TITLE) ?: parsedHTMLText.name + shortDescription.text = data.getCharSequence(ARG_SDESC) + ?: parsedHTMLText.shortDescription + longDescription.text = data.getCharSequence(ARG_LDESC) + ?: parsedHTMLText.longDescription + provider.text = data.getCharSequence(ARG_PROVIDER) + ?: getString(R.string.written_by, parsedHTMLText.provider) + website.text = data.getCharSequence(ARG_WEBSITE) + ?: getString(R.string.available_at, parsedHTMLText.website) } } } \ No newline at end of file diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt index df3b758..fa751d7 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt @@ -22,13 +22,13 @@ import android.os.Bundle import androidx.annotation.LayoutRes import com.javinator9889.handwashingreminder.R import com.javinator9889.handwashingreminder.activities.base.BaseFragmentView -import com.javinator9889.handwashingreminder.activities.views.fragments.washinghands.ARG_POSITION import com.javinator9889.handwashingreminder.activities.views.viewmodels.ParsedHTMLText import kotlinx.android.synthetic.main.simple_text_view.* import kotlin.properties.Delegates internal const val ARG_SYMPTOMS = "bundle:symptoms" internal const val ARG_PREVENTION = "bundle:prevention" +internal const val ARG_POSITION = "bundle:item:position" class DiseaseExtraInformationFragment : BaseFragmentView() { @get:LayoutRes @@ -36,15 +36,6 @@ class DiseaseExtraInformationFragment : BaseFragmentView() { private var position by Delegates.notNull() private lateinit var parsedHTMLText: ParsedHTMLText - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (savedInstanceState != null || arguments != null) { - val data = savedInstanceState ?: arguments - position = data!!.getInt(ARG_POSITION) - parsedHTMLText = data.getParcelable(ARG_HTML_TEXT)!! - } - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) if (position == 1) @@ -57,17 +48,17 @@ class DiseaseExtraInformationFragment : BaseFragmentView() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - if (savedInstanceState != null) - text.text = when (position) { - 1 -> savedInstanceState.getCharSequence(ARG_SYMPTOMS) - 2 -> savedInstanceState.getCharSequence(ARG_PREVENTION) - else -> "" - } - else + if (savedInstanceState != null || arguments != null) { + val data = (savedInstanceState ?: arguments)!! + position = data.getInt(ARG_POSITION) + parsedHTMLText = data.getParcelable(ARG_HTML_TEXT)!! text.text = when (position) { - 1 -> parsedHTMLText.symptoms - 2 -> parsedHTMLText.prevention + 1 -> data.getCharSequence(ARG_SYMPTOMS) + ?: parsedHTMLText.symptoms + 2 -> data.getCharSequence(ARG_PREVENTION) + ?: parsedHTMLText.prevention else -> "" } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt b/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt index 97e7e35..44b1ddc 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/collections/DiseaseTextAdapter.kt @@ -24,6 +24,7 @@ import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.ARG_ANIMATION_ID import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.ARG_HTML_TEXT +import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.ARG_POSITION import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.DiseaseDescriptionFragment import com.javinator9889.handwashingreminder.activities.views.fragments.diseases.DiseaseExtraInformationFragment import com.javinator9889.handwashingreminder.activities.views.viewmodels.ParsedHTMLText From 22cc2916cd2592189c7664ea2e00b874adfc7f80 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Fri, 1 May 2020 10:35:25 +0200 Subject: [PATCH 6/8] Improved performance of settings screen --- .../views/fragments/settings/SettingsView.kt | 475 ++++++++++-------- 1 file changed, 263 insertions(+), 212 deletions(-) diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt index adec01f..a7412f5 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/settings/SettingsView.kt @@ -50,7 +50,7 @@ import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.library.ionicons.Ionicons import com.mikepenz.iconics.utils.sizeDp -import kotlinx.coroutines.launch +import kotlinx.coroutines.* import timber.log.Timber import java.lang.ref.WeakReference @@ -111,226 +111,277 @@ class SettingsView : PreferenceFragmentCompat(), val suggestions = findPreference("send_suggestions") val libraries = findPreference("opensource_libs") val privacyAndTerms = findPreference("tos_privacy") - share?.let { - it.icon = icon(Ionicons.Icon.ion_android_share) - it.setOnPreferenceClickListener { - with(FirebaseAnalytics.getInstance(requireContext())) { - logEvent(FirebaseAnalytics.Event.SHARE, null) - } - with(Intent.createChooser(Intent().apply { - action = Intent.ACTION_SEND - putExtra( - Intent.EXTRA_TEXT, - getText(R.string.share_text) - ) - putExtra( - Intent.EXTRA_TITLE, - getText(R.string.share_title) - ) - ClipData.Item( - getUriFromRes( - requireContext(), - R.drawable.handwashing_app_logo - ) - ) - clipData = ClipData( - ClipDescription( - getString(R.string.share_label), - arrayOf("image/*") - ), - ClipData.Item( - getUriFromRes( - requireContext(), - R.drawable.handwashing_app_logo + val deferreds = mutableListOf>() + deferreds.add( + async(Dispatchers.Main) { + share?.let { + it.icon = icon(Ionicons.Icon.ion_android_share) + it.setOnPreferenceClickListener { + with(FirebaseAnalytics.getInstance(requireContext())) { + logEvent(FirebaseAnalytics.Event.SHARE, null) + } + with(Intent.createChooser(Intent().apply { + action = Intent.ACTION_SEND + putExtra( + Intent.EXTRA_TEXT, + getText(R.string.share_text) ) - ) - ) - flags = Intent.FLAG_GRANT_READ_URI_PERMISSION - type = "text/plain" - }, null)) { - startActivity(this) - } - true - } - } - playStore?.let { - it.icon = icon(Ionicons.Icon.ion_android_playstore) - it.setOnPreferenceClickListener { - openWebsite(PLAYSTORE_URL, R.string.playstore_err) - true - } - } - telegram?.let { - it.setOnPreferenceClickListener { - openWebsite(TELEGRAM_URL, R.string.telegram_err) - true - } - } - github?.let { - it.icon = icon(Ionicons.Icon.ion_social_github) - it.setOnPreferenceClickListener { - openWebsite(GITHUB_URL, R.string.browser_err) - true - } - } - twitter?.let { - it.icon = icon(Ionicons.Icon.ion_social_twitter) - it.setOnPreferenceClickListener { - openWebsite(TWITTER_URL, R.string.twitter_err) - true - } - } - linkedIn?.let { - it.icon = icon(Ionicons.Icon.ion_social_linkedin) - it.setOnPreferenceClickListener { - openWebsite(LINKEDIN_URL, R.string.browser_err) - true - } - } - firebaseAnalytics?.let { - it.onPreferenceChangeListener = this@SettingsView - it.icon = icon(Ionicons.Icon.ion_arrow_graph_up_right) - firebaseAnalyticsPreference = WeakReference(it) - } - firebasePerformance?.let { - it.onPreferenceChangeListener = this@SettingsView - it.icon = icon(Ionicons.Icon.ion_speedometer) - firebasePerformancePreference = WeakReference(it) - } - ads?.let { - it.onPreferenceChangeListener = this@SettingsView - it.icon = icon(Ionicons.Icon.ion_ios_barcode_outline) - adsPreference = WeakReference(it) - } - donations?.let { - it.onPreferenceChangeListener = this@SettingsView - it.entryValues = if (isDebuggable()) - resources.getTextArray(R.array.in_app_donations_debug) - else - resources.getTextArray(R.array.in_app_donations) - it.icon = icon(Ionicons.Icon.ion_card) - billingService.addOnPurchaseFinishedListener(this@SettingsView) - donationsPreference = WeakReference(it) - } - translations?.let { - it.icon = icon(Ionicons.Icon.ion_chatbox_working) - it.setOnPreferenceClickListener { - openWebsite(TRANSLATE_URL, R.string.browser_err) - true - } - } - suggestions?.let { - it.setOnPreferenceClickListener { - with(Intent(Intent.ACTION_SENDTO)) { - type = "*/*" - data = Uri.parse("mailto:") - putExtra(Intent.EXTRA_EMAIL, arrayOf(Email.TO)) - putExtra(Intent.EXTRA_SUBJECT, Email.SUBJECT) - putExtra(Intent.EXTRA_TEXT, getDeviceInfo()) - if (resolveActivity(requireContext().packageManager) - != null - ) { - startActivity(this) - } else { - MaterialDialog(requireContext()).show { - title(R.string.no_app) - message( - text = getString( - R.string.no_app_long, - getString(R.string.sending_email) + putExtra( + Intent.EXTRA_TITLE, + getText(R.string.share_title) + ) + ClipData.Item( + getUriFromRes( + requireContext(), + R.drawable.handwashing_app_logo + ) + ) + clipData = ClipData( + ClipDescription( + getString(R.string.share_label), + arrayOf("image/*") + ), + ClipData.Item( + getUriFromRes( + requireContext(), + R.drawable.handwashing_app_logo + ) ) ) - positiveButton(android.R.string.ok) - cancelable(true) - cancelOnTouchOutside(true) + flags = Intent.FLAG_GRANT_READ_URI_PERMISSION + type = "text/plain" + }, null)) { + startActivity(this) } + true } } - true - } - it.icon = icon(Ionicons.Icon.ion_chatbubbles) - } - libraries?.let { - it.setOnPreferenceClickListener { - val bundle = Bundle(1).apply { - putString("view", "libs") + }) + deferreds.add( + async(Dispatchers.Main) { + playStore?.let { + it.icon = icon(Ionicons.Icon.ion_android_playstore) + it.setOnPreferenceClickListener { + openWebsite(PLAYSTORE_URL, R.string.playstore_err) + true + } } - with(FirebaseAnalytics.getInstance(requireContext())) { - logEvent(FirebaseAnalytics.Event.VIEW_ITEM, bundle) + }) + deferreds.add( + async(Dispatchers.Main) { + telegram?.let { + it.setOnPreferenceClickListener { + openWebsite(TELEGRAM_URL, R.string.telegram_err) + true + } } - LibsBuilder() - .withAutoDetect(true) - .withFields(R.string::class.java.fields) - .withCheckCachedDetection(true) - .withSortEnabled(true) - .withAboutVersionShown(true) - .withAboutVersionShownCode(true) - .withAboutVersionShownName(true) - .withShowLoadingProgress(true) - .withActivityTitle(getString(R.string.app_name)) - .start(requireContext()) - true - } - it.icon = icon(Ionicons.Icon.ion_code) - } - privacyAndTerms?.let { - it.setOnPreferenceClickListener { - Intent( - requireContext(), - PrivacyTermsActivity::class.java - ).run { - startActivity(this) + }) + deferreds.add( + async(Dispatchers.Main) { + github?.let { + it.icon = icon(Ionicons.Icon.ion_social_github) + it.setOnPreferenceClickListener { + openWebsite(GITHUB_URL, R.string.browser_err) + true + } } - true - } - it.icon = icon(Ionicons.Icon.ion_android_cloud_done) - } - emojiCompat = emojiLoader.await() - breakfast?.let { - it.icon = icon(Ionicons.Icon.ion_coffee) - it.alarm = Alarms.BREAKFAST_ALARM - try { - it.title = - emojiCompat.process(getText(R.string.breakfast_pref_title)) - it.summaryText = - emojiCompat.process(getText(R.string.breakfast_pref_summ)) - } catch (_: IllegalStateException) { - it.title = getText(R.string.breakfast_pref_title) - it.summaryText = getText(R.string.breakfast_pref_summ) - } finally { - it.updateSummary() - } - } - lunch?.let { - it.icon = icon(Ionicons.Icon.ion_android_restaurant) - it.alarm = Alarms.LUNCH_ALARM - try { - it.title = - emojiCompat.process(getText(R.string.lunch_pref_title)) - it.summaryText = - emojiCompat.process(getText(R.string.lunch_pref_summ)) - } catch (_: IllegalStateException) { - it.title = getText(R.string.lunch_pref_title) - it.summaryText = getText(R.string.lunch_pref_summ) - } finally { - it.updateSummary() - } - } - dinner?.let { - it.icon = icon(Ionicons.Icon.ion_ios_moon_outline) - it.alarm = Alarms.DINNER_ALARM - try { - it.title = - emojiCompat.process(getText(R.string.dinner_pref_title)) - it.summaryText = - emojiCompat.process(getText(R.string.dinner_pref_summ)) - } catch (_: IllegalStateException) { - it.title = getText(R.string.dinner_pref_title) - it.summaryText = getText(R.string.dinner_pref_summ) - } finally { - it.updateSummary() - } - } + }) + deferreds.add( + async(Dispatchers.Main) { + twitter?.let { + it.icon = icon(Ionicons.Icon.ion_social_twitter) + it.setOnPreferenceClickListener { + openWebsite(TWITTER_URL, R.string.twitter_err) + true + } + } + }) + deferreds.add( + async(Dispatchers.Main) { + linkedIn?.let { + it.icon = icon(Ionicons.Icon.ion_social_linkedin) + it.setOnPreferenceClickListener { + openWebsite(LINKEDIN_URL, R.string.browser_err) + true + } + } + }) + deferreds.add( + async(Dispatchers.Main) { + firebaseAnalytics?.let { + it.onPreferenceChangeListener = this@SettingsView + it.icon = icon(Ionicons.Icon.ion_arrow_graph_up_right) + firebaseAnalyticsPreference = WeakReference(it) + } + }) + deferreds.add( + async(Dispatchers.Main) { + firebasePerformance?.let { + it.onPreferenceChangeListener = this@SettingsView + it.icon = icon(Ionicons.Icon.ion_speedometer) + firebasePerformancePreference = WeakReference(it) + } + }) + deferreds.add( + async(Dispatchers.Main) { + ads?.let { + it.onPreferenceChangeListener = this@SettingsView + it.icon = icon(Ionicons.Icon.ion_ios_barcode_outline) + adsPreference = WeakReference(it) + } + }) + deferreds.add( + async(Dispatchers.Main) { + donations?.let { + it.onPreferenceChangeListener = this@SettingsView + it.entryValues = if (isDebuggable()) + resources.getTextArray(R.array.in_app_donations_debug) + else + resources.getTextArray(R.array.in_app_donations) + it.icon = icon(Ionicons.Icon.ion_card) + billingService.addOnPurchaseFinishedListener(this@SettingsView) + donationsPreference = WeakReference(it) + } + }) + deferreds.add( + async(Dispatchers.Main) { + translations?.let { + it.icon = icon(Ionicons.Icon.ion_chatbox_working) + it.setOnPreferenceClickListener { + openWebsite(TRANSLATE_URL, R.string.browser_err) + true + } + } + }) + deferreds.add( + async(Dispatchers.Main) { + suggestions?.let { + it.setOnPreferenceClickListener { + with(Intent(Intent.ACTION_SENDTO)) { + type = "*/*" + data = Uri.parse("mailto:") + putExtra(Intent.EXTRA_EMAIL, arrayOf(Email.TO)) + putExtra(Intent.EXTRA_SUBJECT, Email.SUBJECT) + putExtra(Intent.EXTRA_TEXT, getDeviceInfo()) + if (resolveActivity(requireContext().packageManager) + != null + ) { + startActivity(this) + } else { + MaterialDialog(requireContext()).show { + title(R.string.no_app) + message( + text = getString( + R.string.no_app_long, + getString(R.string.sending_email) + ) + ) + positiveButton(android.R.string.ok) + cancelable(true) + cancelOnTouchOutside(true) + } + } + } + true + } + it.icon = icon(Ionicons.Icon.ion_chatbubbles) + } + }) + deferreds.add( + async(Dispatchers.Main) { + libraries?.let { + it.setOnPreferenceClickListener { + val bundle = Bundle(1).apply { + putString("view", "libs") + } + with(FirebaseAnalytics.getInstance(requireContext())) { + logEvent( + FirebaseAnalytics.Event.VIEW_ITEM, + bundle + ) + } + LibsBuilder() + .withAutoDetect(true) + .withFields(R.string::class.java.fields) + .withCheckCachedDetection(true) + .withSortEnabled(true) + .withAboutVersionShown(true) + .withAboutVersionShownCode(true) + .withAboutVersionShownName(true) + .withShowLoadingProgress(true) + .withActivityTitle(getString(R.string.app_name)) + .start(requireContext()) + true + } + it.icon = icon(Ionicons.Icon.ion_code) + } + }) + deferreds.add( + async(Dispatchers.Main) { + privacyAndTerms?.let { + it.setOnPreferenceClickListener { + Intent( + requireContext(), + PrivacyTermsActivity::class.java + ).run { + startActivity(this) + } + true + } + it.icon = icon(Ionicons.Icon.ion_android_cloud_done) + } + }) + deferreds.add( + async(Dispatchers.Main) { + emojiCompat = emojiLoader.await() + breakfast?.let { + it.icon = icon(Ionicons.Icon.ion_coffee) + it.alarm = Alarms.BREAKFAST_ALARM + try { + it.title = + emojiCompat.process(getText(R.string.breakfast_pref_title)) + it.summaryText = + emojiCompat.process(getText(R.string.breakfast_pref_summ)) + } catch (_: IllegalStateException) { + it.title = getText(R.string.breakfast_pref_title) + it.summaryText = + getText(R.string.breakfast_pref_summ) + } finally { + it.updateSummary() + } + } + lunch?.let { + it.icon = icon(Ionicons.Icon.ion_android_restaurant) + it.alarm = Alarms.LUNCH_ALARM + try { + it.title = + emojiCompat.process(getText(R.string.lunch_pref_title)) + it.summaryText = + emojiCompat.process(getText(R.string.lunch_pref_summ)) + } catch (_: IllegalStateException) { + it.title = getText(R.string.lunch_pref_title) + it.summaryText = getText(R.string.lunch_pref_summ) + } finally { + it.updateSummary() + } + } + dinner?.let { + it.icon = icon(Ionicons.Icon.ion_ios_moon_outline) + it.alarm = Alarms.DINNER_ALARM + try { + it.title = + emojiCompat.process(getText(R.string.dinner_pref_title)) + it.summaryText = + emojiCompat.process(getText(R.string.dinner_pref_summ)) + } catch (_: IllegalStateException) { + it.title = getText(R.string.dinner_pref_title) + it.summaryText = getText(R.string.dinner_pref_summ) + } finally { + it.updateSummary() + } + } + }) + deferreds.awaitAll() } } From 080dae35555e1cfef3f77882526f92d61daded48 Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Fri, 1 May 2020 10:42:14 +0200 Subject: [PATCH 7/8] Do not retain instance by default --- .../handwashingreminder/activities/base/BaseFragmentView.kt | 5 ----- .../views/fragments/diseases/DiseaseDescriptionFragment.kt | 5 +++++ .../fragments/diseases/DiseaseExtraInformationFragment.kt | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt index 9ca79bd..5a72d86 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/base/BaseFragmentView.kt @@ -29,11 +29,6 @@ abstract class BaseFragmentView : BaseFragment() { @get:LayoutRes protected abstract val layoutId: Int - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - retainInstance = true - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt index 9fc791b..d2130dc 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseDescriptionFragment.kt @@ -40,6 +40,11 @@ class DiseaseDescriptionFragment : BaseFragmentView() { private lateinit var parsedHTMLText: ParsedHTMLText private var animId by Delegates.notNull() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + retainInstance = true + } + override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putCharSequence(ARG_TITLE, title.text) diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt index fa751d7..634879e 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseaseExtraInformationFragment.kt @@ -36,6 +36,11 @@ class DiseaseExtraInformationFragment : BaseFragmentView() { private var position by Delegates.notNull() private lateinit var parsedHTMLText: ParsedHTMLText + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + retainInstance = true + } + override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) if (position == 1) From e5a814b3893d2876d52b20738cc0a0ce4672880d Mon Sep 17 00:00:00 2001 From: Javinator9889 Date: Fri, 1 May 2020 10:58:19 +0200 Subject: [PATCH 8/8] Avoid possible memory leaks by calling "onDestroy" manually when back button is pressed --- .../activities/MainActivity.kt | 9 +++++++-- .../fragments/diseases/DiseasesFragment.kt | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/MainActivity.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/MainActivity.kt index b2a1b8a..1219b03 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/MainActivity.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/MainActivity.kt @@ -125,9 +125,14 @@ class MainActivity : ActionBarBase(), menu.selectedItemId = R.id.diseases onNavigationItemSelected(menu.menu.findItem(R.id.diseases)) } else { - if (activeFragment == R.id.diseases) + if (activeFragment == R.id.diseases) { + with(fragments[activeFragment].get()!! as DiseasesFragment) { + onBackPressed() + } + fragments.clear() super.onBackPressed() - else { + finish() + } else { val washingHandsFragment = fragments[activeFragment].get() ?: createFragmentForId(R.id.handwashing) as WashingHandsFragment diff --git a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseasesFragment.kt b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseasesFragment.kt index a396383..4284573 100644 --- a/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseasesFragment.kt +++ b/app/src/main/java/com/javinator9889/handwashingreminder/activities/views/fragments/diseases/DiseasesFragment.kt @@ -43,6 +43,7 @@ import com.mikepenz.fastadapter.listeners.ClickEventHook import kotlinx.android.synthetic.main.diseases_list.* import kotlinx.android.synthetic.main.diseases_list.view.* import kotlinx.coroutines.launch +import timber.log.Timber class DiseasesFragment : BaseFragmentView() { override val layoutId: Int = R.layout.diseases_list @@ -93,6 +94,23 @@ class DiseasesFragment : BaseFragmentView() { adapter = fastAdapter } fastAdapter.addEventHook(DiseaseClickEventHook()) + fastAdapter.withSavedInstanceState(savedInstanceState) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + fastAdapter.saveInstanceState(outState) + } + + fun onBackPressed() { + try { + diseasesContainer.adapter = null + diseasesAdapter.clear() + } catch (e: Exception) { + Timber.w(e, "Exception when calling 'onBackPressed'") + } finally { + onDestroy() + } } private inner class DiseaseClickEventHook : ClickEventHook() {