Skip to content

Commit

Permalink
- upgraded to Room version 2.2.5
Browse files Browse the repository at this point in the history
- added feature to export/import app data (db dump)
 -- should be used in a situation where an app reinstall is necessary as in the case with the recent Google Maps SDK crash (see: https://issuetracker.google.com/issues/154855417).
- CurrentStatusForegroundService now extends LifecycleService
 -- this fixed a bug where the gatecodes notification would come back even after "destroying" app
- stop recyclerview from updating if user has scrolled away from the top
 -- this improves experience scrolling list when "order by nearby" is enabled
- removed redundant "always order by nearest" option from Settings
- added icons to Settings options
  • Loading branch information
lmj0011 committed Apr 27, 2020
1 parent a62b80a commit e5d3b0b
Show file tree
Hide file tree
Showing 31 changed files with 543 additions and 191 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ Features include:
* Store and keep track of Trips, Apartment Codes, and Customers
* Export Trips to a spreadsheet
* See total earnings across multiple gigs (calculated from Trips)
* Create personal maps of places that are difficult to navigate. (ie. apartment complexes)

## Download
Get the app from the [Google Play Store](https://play.google.com/store/apps/details?id=name.lmj0011.courierlocker.prod) or [releases page](https://github.com/lmj0011/courier-locker/releases).

If you want to try new features before they get to the stable release, you can download the dev version [here](https://courierlocker.org/dist/dev).
Get the app from the [Google Play Store](https://play.google.com/store/apps/details?id=name.lmj0011.courierlocker.prod).

## Issues, Feature Requests and Contributing

Expand All @@ -40,7 +39,7 @@ Please make sure to read the full guidelines. Your issue may be closed without w

## License

Copyright 2019 Landan Jackson
Copyright 2019-2020 Landan Jackson

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
8 changes: 4 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ android {
applicationId "name.lmj0011.courierlocker"
minSdkVersion 19
targetSdkVersion 29
versionCode 38
versionCode 45
versionName "1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
Expand Down Expand Up @@ -50,7 +50,7 @@ android {
productFlavors {
dev { // active development/testing
applicationIdSuffix ".dev"
versionNameSuffix ".0.0-dev"
versionNameSuffix ".1.0-dev"
resValue("string", "app_name", "Courier Locker (dev)")
manifestPlaceholders = [
appIcon: "@mipmap/ic_launcher_dev",
Expand All @@ -59,7 +59,7 @@ android {
}
beta { // public testing
applicationIdSuffix ".beta"
versionNameSuffix ".0.0-beta"
versionNameSuffix ".1.0-beta"
resValue("string", "app_name", "Courier Locker (beta)")
manifestPlaceholders = [
appIcon: "@mipmap/ic_launcher_beta",
Expand All @@ -68,7 +68,7 @@ android {
}
prod { // official release
applicationIdSuffix ".prod"
versionNameSuffix ".0.0"
versionNameSuffix ".1.0"
resValue("string", "app_name", "Courier Locker")
manifestPlaceholders = [
appIcon: "@mipmap/ic_launcher",
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SettingsActivity" />
<activity android:name=".SettingsActivity"/>

<service
android:name=".services.CurrentStatusForegroundService"
Expand Down
71 changes: 37 additions & 34 deletions app/src/main/java/name/lmj0011/courierlocker/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,18 @@ import android.view.Menu
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.core.os.bundleOf
import androidx.databinding.DataBindingUtil
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.*
import androidx.preference.PreferenceManager
import com.crashlytics.android.Crashlytics
import com.google.android.material.bottomnavigation.BottomNavigationView
import io.fabric.sdk.android.Fabric
import kotlinx.android.synthetic.main.app_bar_main.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import name.lmj0011.courierlocker.databinding.ActivityMainBinding
import name.lmj0011.courierlocker.fragments.TripsFragmentDirections
import name.lmj0011.courierlocker.fragments.dialogs.ImportedAppDataDialogFragment
import name.lmj0011.courierlocker.helpers.LocationHelper
import name.lmj0011.courierlocker.helpers.PermissionHelper
import name.lmj0011.courierlocker.helpers.PlexmapsXmlParser
Expand All @@ -43,6 +37,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
private lateinit var binding: ActivityMainBinding
private lateinit var navController: NavController
private lateinit var appBarConfiguration : AppBarConfiguration
private lateinit var topLevelDestinations: Set<Int>

companion object {
const val TRIPS_WRITE_REQUEST_CODE = 104
Expand All @@ -65,15 +60,14 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
setContentView(binding.root)

// AppBar Navigation configuration
val topLevelDestinations = setOf(R.id.tripsFragment, R.id.gateCodesFragment, R.id.customersFragment, R.id.mapsFragment)
topLevelDestinations = setOf(R.id.tripsFragment, R.id.gateCodesFragment, R.id.customersFragment, R.id.mapsFragment)
appBarConfiguration = AppBarConfiguration.Builder(topLevelDestinations)
.setDrawerLayout(binding.drawerLayout)
.build()

setSupportActionBar(binding.drawerLayout.toolbar)
setupActionBarWithNavController(navController, appBarConfiguration)
binding.navView.setNavigationItemSelectedListener(this::onNavigationItemSelected)
/////

LocationHelper.setFusedLocationClient(this)

Expand All @@ -96,16 +90,29 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
super.onResume()
Timber.i("onResume Called")

val menuItemId = intent.extras?.getInt("menuItemId")
menuItemId?.let { this.navigateTo(it) }
// any message that the previous Activity wants to send
intent.extras?.getString("messageFromCaller")?.let {
this.showToastMessage(it, Toast.LENGTH_LONG)
}

intent.extras?.getInt("menuItemId")?.let {
this.navigateTo(it)
}

val editTripId = intent.extras?.getInt("editTripId")
editTripId?.let {
intent.extras?.getInt("editTripId")?.let {
when {
it > 0 -> navController.navigate(TripsFragmentDirections.actionTripsFragmentToEditTripFragment(editTripId))
it > 0 -> navController.navigate(TripsFragmentDirections.actionTripsFragmentToEditTripFragment(it))
}
}

intent.extras?.getBoolean("importedAppData")?.let {
if(!it) return

val dialog = ImportedAppDataDialogFragment()
dialog.show(supportFragmentManager, "ImportedAppDataDialogFragment")
}


CurrentStatusForegroundService.stopService(this)

if(PermissionHelper.permissionAccessFineLocationApproved) {
Expand Down Expand Up @@ -142,31 +149,27 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}

override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.navHostFragment).navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
this.onBackPressed()
return true
}

override fun onBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
Timber.i("label: ${navController.currentDestination?.label}")

when(navController.currentDestination?.label) {
"Trips" -> {
navController.popBackStack(R.id.gateCodesFragment, false)
// an open drawer means user is at a top level destination, close app
finish()
}else if(topLevelDestinations.contains(navController.currentDestination?.id)) {
binding.drawerLayout.openDrawer(GravityCompat.START)
}else {
when(navController.currentDestination?.id) {
// seems to be the only way to get the Maps recyclerview to show updated items when navigated
// from EditAptBuildingsMapsFragment
R.id.editAptBuildingsMapsFragment -> {
navController.navigate(R.id.mapsFragment)
}
"Gate Codes" -> {
navController.popBackStack(R.id.gateCodesFragment, false)
finish()
else -> {
super.onBackPressed()
}
"Customers" -> {
navController.popBackStack(R.id.gateCodesFragment, false)
finish()
}

}

super.onBackPressed()
}
}

Expand Down Expand Up @@ -213,8 +216,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
}

fun showToastMessage(message: String) {
val toast = Toast.makeText(this, message, Toast.LENGTH_SHORT)
fun showToastMessage(message: String, duration: Int = Toast.LENGTH_SHORT) {
val toast = Toast.makeText(this, message, duration)
toast.setGravity(Gravity.TOP, 0, 150)
toast.show()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import timber.log.Timber
* ref: https://stackoverflow.com/a/44949401/2445763
*/
class SettingsActivity : AppCompatActivity() {
companion object {
const val DB_EXPORT_REQUEST_CODE = 105
const val DB_IMPORT_REQUEST_CODE = 106
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.i("onCreate Called")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import name.lmj0011.courierlocker.databinding.ListItemMapBinding
import name.lmj0011.courierlocker.fragments.MapsFragmentDirections
import name.lmj0011.courierlocker.fragments.dialogs.DeleteApartmentDialogFragment
import name.lmj0011.courierlocker.fragments.dialogs.NavigateToAptBuildingDialogFragment
import name.lmj0011.courierlocker.helpers.ListLock
import name.lmj0011.courierlocker.helpers.LocationHelper


Expand Down Expand Up @@ -51,7 +52,7 @@ class MapListAdapter(private val clickListener: MapListener, private val parentF
val lengthThenNatural = compareBy<String> { it.length }
.then(naturalOrder())

apt.buildings.map { it.number }.sortedWith(lengthThenNatural).forEach {
apt.buildings.filter { it.number != null }.map { it.number }.sortedWith(lengthThenNatural).forEach {
popup.menu.add(it)
}

Expand All @@ -72,6 +73,7 @@ class MapListAdapter(private val clickListener: MapListener, private val parentF
}

binding.buildingImageBtn.setOnClickListener {
ListLock.lock()
popup.show()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ data class Apartment(
var sourceUrl: String = "",

@ColumnInfo(name = "buildings")
var buildings: List<Building> = mutableListOf()
var buildings: MutableList<Building> = mutableListOf()
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import androidx.lifecycle.LiveData
import androidx.room.*

@Dao
interface ApartmentDao {
interface ApartmentDao: BaseDao {

@Insert
fun insert(apartment: Apartment)
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/name/lmj0011/courierlocker/database/BaseDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package name.lmj0011.courierlocker.database

import androidx.room.Dao
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery

// ref: https://stackoverflow.com/a/51560124/2445763
@Dao
interface BaseDao {
@RawQuery
fun checkpoint(supportSQLiteQuery: SupportSQLiteQuery?): Int
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import timber.log.Timber

@Database(entities = [GateCode::class, Trip::class, Customer::class, Apartment::class], version = 5, exportSchema = true)
@TypeConverters(DataConverters::class)
abstract class CourierLockerDatabase : RoomDatabase() {

abstract val baseDao: BaseDao
abstract val gateCodeDao: GateCodeDao
abstract val tripDao: TripDao
abstract val customerDao: CustomerDao
Expand Down Expand Up @@ -85,6 +87,42 @@ abstract class CourierLockerDatabase : RoomDatabase() {
return instance
}
}

fun getDbData(context: Context): ByteArray? {
var data: ByteArray? = null

try {
val currentdb = context.getDatabasePath("courier_locker_database")

data = currentdb.readBytes()
} catch (e: Exception) {
Timber.i("backup db failed!")
}

return data
}

fun setDbData(context: Context, data: ByteArray) {
try {
val currentdb = context.getDatabasePath("courier_locker_database")
val currentdbSHM = context.getDatabasePath("courier_locker_database-shm")
val currentdbWAL = context.getDatabasePath("courier_locker_database-wal")
val output = currentdb.outputStream()

output.write(data)
output.flush()
output.close()

if(currentdbSHM.delete() && currentdbWAL.delete()) {
Timber.i("journal files (-shm -wal) deleted successfully!")
}

Timber.i("imported db successfully!")
} catch (e: Exception) {
Timber.i("importing db failed!")
}

}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import androidx.room.Query
import androidx.room.Update

@Dao
interface CustomerDao {
interface CustomerDao: BaseDao {

@Insert
fun insert(customer: Customer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import androidx.room.Query
import androidx.room.Update

@Dao
interface GateCodeDao {
interface GateCodeDao: BaseDao {

@Insert
fun insert(gateCode: GateCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import androidx.room.Query
import androidx.room.Update

@Dao
interface TripDao {
interface TripDao: BaseDao {

@Insert
fun insert(trip: Trip)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import name.lmj0011.courierlocker.database.ApartmentDao
import name.lmj0011.courierlocker.database.GateCodeDao
import name.lmj0011.courierlocker.viewmodels.ApartmentViewModel
import name.lmj0011.courierlocker.viewmodels.GateCodeViewModel

/**
* This is pretty much boiler plate code for a ViewModel Factory.
*
* Provides the GateCodeDao and context to the ViewModel.
* Provides the Dao and context to the ViewModel.
*/
class ApartmentViewModelFactory(
private val dataSource: ApartmentDao,
Expand Down
Loading

0 comments on commit e5d3b0b

Please sign in to comment.