Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'development' into 'master'
Development

See merge request Javinator9889/handwashing-reminder!8
  • Loading branch information
Javinator9889 committed May 3, 2020
2 parents a6aef51 + e5a814b commit 885f784
Show file tree
Hide file tree
Showing 21 changed files with 396 additions and 299 deletions.
5 changes: 4 additions & 1 deletion README.md
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions app/build.gradle
Expand Up @@ -42,7 +42,7 @@ android {
applicationId "com.javinator9889.handwashingreminder"
minSdkVersion 17
targetSdkVersion 29
versionCode 118
versionCode 121
versionName "1.1.2-${gitCommitHash}"
multiDexEnabled true
resConfigs "en", "es"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -171,7 +172,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'
Expand Down
Expand Up @@ -20,13 +20,15 @@ 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
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
Expand All @@ -41,7 +43,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
Expand All @@ -65,13 +66,16 @@ class LauncherActivity : AppCompatActivity() {
private var launchOnInstall = false
private var launchFromNotification = false
private var canFinishActivity = false
private lateinit var sharedPreferences: SharedPreferences
private lateinit var app: HandwashingApplication
private lateinit var initDeferred: Deferred<Unit>

init {
lifecycleScope.launch {
whenCreated {
app = HandwashingApplication.getInstance()
app = HandwashingApplication.instance
sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(this@LauncherActivity)
with(intent) {
notNull {
launchFromNotification =
Expand Down Expand Up @@ -141,7 +145,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()
Expand Down Expand Up @@ -183,9 +187,9 @@ class LauncherActivity : AppCompatActivity() {
private fun installRequiredModules() {
val modules = ArrayList<String>(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
}
Expand Down Expand Up @@ -247,7 +251,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) ==
Expand All @@ -258,8 +262,6 @@ class LauncherActivity : AppCompatActivity() {
} else {
app.activityHandler.disableActivityTracker()
}
Timber.d("Initializing Billing Service")
app.billingService = BillingService(this)
with(AlarmHandler(this)) {
scheduleAllAlarms()
}
Expand Down Expand Up @@ -306,13 +308,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
)
Expand Down
Expand Up @@ -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
Expand Down
Expand Up @@ -16,27 +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.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<Int>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Expand All @@ -45,26 +52,26 @@ 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?) {
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)
}
}
}
Expand Up @@ -16,50 +16,54 @@
*
* 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.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(
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<Int>()
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)
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
)
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 -> ""
}
}
}
}
Expand Up @@ -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
Expand Down Expand Up @@ -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<Disease>() {
Expand Down
Expand Up @@ -33,7 +33,7 @@ class Ads : AbstractItem<Ads.ViewHolder>() {
override fun getViewHolder(v: View): ViewHolder = ViewHolder(v)

class ViewHolder(v: View) : FastAdapter.ViewHolder<Ads>(v) {
private val ads = HandwashingApplication.getInstance().adLoader
private val ads = HandwashingApplication.instance.adLoader
private val container = v.findViewById<FrameLayout>(R.id.adsContainer)

override fun bindView(item: Ads, payloads: List<Any>) {
Expand Down
Expand Up @@ -89,7 +89,7 @@ class ActivityCheckbox : CheckBoxPreference {
firstCheck = false
return
}
with(HandwashingApplication.getInstance()) {
with(HandwashingApplication.instance) {
if (checked) {
activityHandler.startTrackingActivity()
} else {
Expand Down
Expand Up @@ -82,7 +82,7 @@ class ActivityMultiSelectList : MultiSelectListPreference {
}

private fun reloadActivityHandler() {
with(HandwashingApplication.getInstance()) {
with(HandwashingApplication.instance) {
activityHandler.reload()
}
}
Expand Down

0 comments on commit 885f784

Please sign in to comment.