Skip to content

Commit

Permalink
Merge pull request #2 from maifeeulasad/feature/biometric
Browse files Browse the repository at this point in the history
Feature/biometric
  • Loading branch information
maifeeulasad authored Mar 19, 2021
2 parents be6bcd0 + 3d02dde commit cfca5d0
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 107 deletions.
15 changes: 3 additions & 12 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,7 @@ dependencies {
//implementation "com.google.dagger:hilt-android-testing:$hilt_ver"
implementation "androidx.hilt:hilt-common:1.0.0-alpha03"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"

//Bio-metric
implementation 'androidx.biometric:biometric:1.2.0-alpha03'
}
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
package="dev.spikeysanju.expensetracker">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.USE_BIOMETRIC"
android:requiredFeature="true"/>

<application
android:name=".app.ExpenseTracker"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package dev.spikeysanju.expensetracker.data.local.datastore

import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Singleton


class SettingsDataStore(context: Context) :
PrefsDataStore(
context,
PREF_FILE_SETTINGS
),
SettingsImpl {

// used to get the data from datastore
override val biometric: Flow<Boolean>
get() = dataStore.data.map { preferences ->
val biometric = preferences[BIOMETRIC_KEY] ?: false
biometric
}

// used to save the bio-metric preference to datastore
override suspend fun saveToDataStore(isBiometricEnabled: Boolean) {
dataStore.edit { preferences ->
preferences[BIOMETRIC_KEY] = isBiometricEnabled
}
}

companion object {
private const val PREF_FILE_SETTINGS = "settings_preference"
private val BIOMETRIC_KEY = booleanPreferencesKey("biometric_mode")
}
}

@Singleton
interface SettingsImpl {
val biometric: Flow<Boolean>
suspend fun saveToDataStore(isBiometricEnabled: Boolean)
}
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ class DashboardFragment :
findNavController().navigate(R.id.action_dashboardFragment_to_aboutFragment)
true
}
R.id.action_settings -> {
findNavController().navigate(R.id.action_dashboardFragment_to_settingsFragment)
true
}
else -> super.onOptionsItemSelected(item)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package dev.spikeysanju.expensetracker.view.main

import android.os.Bundle
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
Expand All @@ -14,17 +18,29 @@ import dev.spikeysanju.expensetracker.databinding.ActivityMainBinding
import dev.spikeysanju.expensetracker.repo.TransactionRepo
import dev.spikeysanju.expensetracker.utils.viewModelFactory
import dev.spikeysanju.expensetracker.view.main.viewmodel.TransactionViewModel
import dev.spikeysanju.expensetracker.view.settings.SettingsViewModel
import kotlinx.coroutines.flow.first
import java.util.concurrent.Executor
import kotlin.system.exitProcess

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var navHostFragment: NavHostFragment
private lateinit var appBarConfiguration: AppBarConfiguration

private lateinit var executor: Executor
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var promptInfo: BiometricPrompt.PromptInfo

private val repo by lazy { TransactionRepo(AppDatabase(this)) }
private val viewModel: TransactionViewModel by viewModels {
viewModelFactory { TransactionViewModel(this.application, repo) }
}

private val settingsViewModel: SettingsViewModel by viewModels{
viewModelFactory { SettingsViewModel(this.application) }
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
Expand All @@ -36,6 +52,11 @@ class MainActivity : AppCompatActivity() {
*/
viewModel

lifecycleScope.launchWhenStarted {
if(settingsViewModel.bioMetricPreference.first())
authenticate()
}

initViews(binding)
observeNavElements(binding, navHostFragment.navController)
}
Expand Down Expand Up @@ -79,4 +100,38 @@ class MainActivity : AppCompatActivity() {
navHostFragment.navController.navigateUp()
return super.onSupportNavigateUp()
}

private fun authenticate(){
executor = ContextCompat.getMainExecutor(this)
biometricPrompt = BiometricPrompt(this, executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
Toast.makeText(applicationContext,
"Welcome to Expenso", Toast.LENGTH_LONG)
.show()
}

override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
//todo: show message wait for a second; static err code
exitProcess(-1)
}

override fun onAuthenticationError(errorCode: Int,
errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
//todo: show message wait for a second; static err code
exitProcess(-2)
}
})

promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Please complete bio-metric login to continue")
.setNegativeButtonText("Exit")
.build()
biometricPrompt.authenticate(promptInfo)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.spikeysanju.expensetracker.view.settings


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import dev.spikeysanju.expensetracker.databinding.FragmentSettingsBinding
import dev.spikeysanju.expensetracker.view.base.BaseFragment
import kotlinx.coroutines.flow.first

@AndroidEntryPoint
class SettingsFragment : BaseFragment<FragmentSettingsBinding, SettingsViewModel>() {
override val viewModel: SettingsViewModel by viewModels()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

// Set the item state
lifecycleScope.launchWhenStarted {
binding.biometric.isChecked = viewModel.bioMetricPreference.first()
}

initViews()
}

private fun initViews() = with(binding) {
biometric.setOnCheckedChangeListener { _, biometricEnabled ->
viewModel.setBioMetricLock(biometricEnabled)
}
}

override fun getViewBinding(inflater: LayoutInflater, container: ViewGroup?) =
FragmentSettingsBinding.inflate(inflater, container, false)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dev.spikeysanju.expensetracker.view.settings


import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.spikeysanju.expensetracker.data.local.datastore.SettingsDataStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class SettingsViewModel @Inject constructor(
application: Application
) :
AndroidViewModel(application) {

// init datastore
private val settingsDataStore = SettingsDataStore(application)

// get bio-metric preference
val bioMetricPreference = settingsDataStore.biometric

fun setBioMetricLock(bioMetricLock: Boolean) {
viewModelScope.launch(Dispatchers.IO) {
settingsDataStore.saveToDataStore(bioMetricLock)
}
}

}
59 changes: 59 additions & 0 deletions app/src/main/res/layout/fragment_settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none">


<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".view.settings.SettingsFragment">

<ImageView
android:id="@+id/logo"
android:layout_width="140dp"
android:layout_height="140dp"
android:layout_marginTop="@dimen/dimen_64"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<LinearLayout
android:layout_marginStart="@dimen/dimen_16"
android:layout_marginTop="@dimen/dimen_48"
app:layout_constraintTop_toBottomOf="@id/logo"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/biometricTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_bold"
android:text="@string/text_settings_biometric"
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
app:layout_constraintStart_toStartOf="parent"/>


<androidx.appcompat.widget.SwitchCompat
android:layout_weight="1"
android:id="@+id/biometric"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/biometricTitle" />

</LinearLayout>



</androidx.constraintlayout.widget.ConstraintLayout>

</ScrollView>
5 changes: 5 additions & 0 deletions app/src/main/res/menu/menu_ui.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@
android:enabled="true"
android:title="@string/text_about"
app:showAsAction="never" />
<item
android:id="@+id/action_settings"
android:enabled="true"
android:title="@string/text_settings"
app:showAsAction="never" />

</menu>
Loading

0 comments on commit cfca5d0

Please sign in to comment.