Connected TOTP and the scanner

This commit is contained in:
Yogesh Choudhary Paliyal
2021-09-22 21:13:02 +05:30
parent 909d799e65
commit e4ba06e6f7
11 changed files with 127 additions and 20 deletions

7
.idea/misc.xml generated
View File

@@ -5,13 +5,10 @@
<map>
<entry key="../../../../layout/custom_preview.xml" value="0.20833333333333334" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/drawable/ic_twotone_content_copy_24.xml" value="0.10989583333333333" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/activity_add_totpactivity.xml" value="0.25" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/activity_add_totpactivity.xml" value="0.16485507246376813" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/activity_dashboard.xml" value="0.2" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/activity_scanner.xml" value="0.2" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/backup_activity.xml" value="0.12635869565217392" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/fragment_detail.xml" value="0.1403985507246377" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/item_accounts.xml" value="0.15" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/item_totp.xml" value="0.33" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/layout/item_accounts.xml" value="0.1" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/main/res/xml/backup_preferences.xml" value="0.4287690179806362" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/production/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.21614583333333334" />
<entry key="..\:/Users/paliy/StudioProjects/KeyPass/app/src/staging/res/drawable/ic_twotone_content_copy_24.xml" value="0.21614583333333334" />

View File

@@ -0,0 +1,5 @@
package com.yogeshpaliyal.keypass.constants
object IntentKeys {
const val SCANNED_TEXT = "scanned_text"
}

View File

@@ -0,0 +1,5 @@
package com.yogeshpaliyal.keypass.constants
object RequestCodes {
const val SCANNER = 342
}

View File

@@ -16,29 +16,29 @@ import kotlinx.coroutines.flow.Flow
abstract class DbDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertOrUpdateAccount(accountModel: AccountModel)
abstract suspend fun insertOrUpdateAccount(vararg accountModel: AccountModel)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertOrUpdateAccount(accountModel: List<AccountModel>)
abstract suspend fun insertOrUpdateAccount(accountModel: List<AccountModel>)
@Query("SELECT * FROM account ORDER BY title ASC")
abstract fun getAllAccounts(): LiveData<List<AccountModel>>
@Query("SELECT * FROM account ORDER BY title ASC")
abstract fun getAllAccountsList(): List<AccountModel>
abstract suspend fun getAllAccountsList(): List<AccountModel>
@Query("SELECT * FROM account WHERE CASE WHEN :tag IS NOT NULL THEN tags = :tag ELSE 1 END AND ((username LIKE '%'||:query||'%' ) OR (title LIKE '%'||:query||'%' ) OR (notes LIKE '%'||:query||'%' )) ORDER BY title ASC")
abstract fun getAllAccounts(query: String?, tag: String?): LiveData<List<AccountModel>>
@Query("SELECT * FROM account WHERE id = :id")
abstract fun getAccount(id: Long?): AccountModel?
abstract suspend fun getAccount(id: Long?): AccountModel?
@Query("SELECT DISTINCT tags FROM account")
abstract fun getTags(): Flow<List<String>>
@Query("DELETE from account WHERE id = :id")
abstract fun deleteAccount(id: Long?)
abstract suspend fun deleteAccount(id: Long?)
@Delete
abstract fun deleteAccount(accountModel: AccountModel)
abstract suspend fun deleteAccount(accountModel: AccountModel)
}

View File

@@ -5,7 +5,11 @@ import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.viewModels
import androidx.lifecycle.Observer
import com.google.android.material.snackbar.Snackbar
import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.constants.IntentKeys
import com.yogeshpaliyal.keypass.constants.RequestCodes
import com.yogeshpaliyal.keypass.databinding.ActivityAddTotpactivityBinding
import dagger.hilt.android.AndroidEntryPoint
@@ -41,5 +45,18 @@ class AddTOTPActivity : AppCompatActivity() {
ScannerActivity.start(this)
}
mViewModel.error.observe(this, Observer {
it?.getContentIfNotHandled()?.let {
Snackbar.make(binding.root, it, Snackbar.LENGTH_SHORT).show()
}
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RequestCodes.SCANNER && resultCode == RESULT_OK){
mViewModel.setSecretKey(data?.extras?.getString(IntentKeys.SCANNED_TEXT) ?: "")
}
}
}

View File

@@ -1,10 +1,53 @@
package com.yogeshpaliyal.keypass.ui.addTOTP
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.yogeshpaliyal.keypass.AppDatabase
import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.data.AccountModel
import com.yogeshpaliyal.keypass.utils.Event
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class AddTOTPViewModel @Inject constructor(): ViewModel() {
class AddTOTPViewModel @Inject constructor(private val appDatabase: AppDatabase): ViewModel() {
private val _goBack = MutableLiveData<Event<Unit>>()
val goBack : LiveData<Event<Unit>> = _goBack
private val _error = MutableLiveData<Event<Int>>()
val error : LiveData<Event<Int>> = _error
val secretKey = MutableLiveData<String>("")
val accountName = MutableLiveData<String>("")
fun saveAccount(){
viewModelScope.launch {
val secretKey = secretKey.value
val accountName = accountName.value
if (accountName.isNullOrEmpty()){
_error.postValue(Event(R.string.alert_black_secret_key))
return@launch
}
if (accountName.isNullOrEmpty()){
_error.postValue(Event(R.string.alert_black_secret_key))
return@launch
}
val accountModel = AccountModel(password = secretKey, title = accountName)
appDatabase.getDao().insertOrUpdateAccount(accountModel)
}
}
fun setSecretKey(secretKey: String){
this.secretKey.value = secretKey
}
}

View File

@@ -1,6 +1,7 @@
package com.yogeshpaliyal.keypass.ui.addTOTP
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -11,6 +12,8 @@ import androidx.appcompat.app.AppCompatActivity
import com.budiyev.android.codescanner.CodeScanner
import com.budiyev.android.codescanner.DecodeCallback
import com.budiyev.android.codescanner.ErrorCallback
import com.yogeshpaliyal.keypass.constants.IntentKeys
import com.yogeshpaliyal.keypass.constants.RequestCodes
import com.yogeshpaliyal.keypass.databinding.ActivityScannerBinding
import dagger.hilt.android.AndroidEntryPoint
@@ -25,9 +28,9 @@ class ScannerActivity : AppCompatActivity() {
companion object{
@JvmStatic
fun start(context: Context) {
val starter = Intent(context, ScannerActivity::class.java)
context.startActivity(starter)
fun start(activity: Activity) {
val starter = Intent(activity, ScannerActivity::class.java)
activity.startActivityForResult(starter,RequestCodes.SCANNER)
}
}
@@ -50,17 +53,21 @@ class ScannerActivity : AppCompatActivity() {
} else {
codeScanner?.startPreview()
// Callbacks
codeScanner?.decodeCallback = DecodeCallback {
codeScanner?.decodeCallback = DecodeCallback { result ->
runOnUiThread {
Toast.makeText(this, "Scan result: ${it.text}", Toast.LENGTH_LONG).show()
setResult(RESULT_OK, Intent().also {
it.putExtra(IntentKeys.SCANNED_TEXT, result.text)
})
finish()
//Toast.makeText(this, "Scan result: ${it.text}", Toast.LENGTH_LONG).show()
}
}
codeScanner?.errorCallback = ErrorCallback { // or ErrorCallback.SUPPRESS
runOnUiThread {
Toast.makeText(
/* Toast.makeText(
this, "Camera initialization error: ${it.message}",
Toast.LENGTH_LONG
).show()
).show()*/
}
}
}

View File

@@ -40,7 +40,7 @@ class DashboardActivity :
private val mViewModel by viewModels<DashboardViewModel>()
val currentNavigationFragment: Fragment?
private val currentNavigationFragment: Fragment?
get() = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
?.childFragmentManager
?.fragments

View File

@@ -0,0 +1,27 @@
package com.yogeshpaliyal.keypass.utils
/*Used as a wrapper for data that is exposed via a LiveData that represents an
event.*/
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}

View File

@@ -41,6 +41,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Secret Key"
android:text="@{mViewModel.secretKey}"
android:id="@+id/etSecretKey"/>
</com.google.android.material.textfield.TextInputLayout>
@@ -58,6 +59,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/account_name"
android:text="@{mViewModel.accountName}"
android:id="@+id/etAccount"/>
</com.google.android.material.textfield.TextInputLayout>
@@ -69,6 +71,8 @@
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="@dimen/grid_2"
android:text="Save"
android:id="@+id/btnSave"
android:onClick="@{()->mViewModel.saveAccount()}"
app:icon="@drawable/ic_round_done_24"
android:textColor="?attr/colorOnSecondary"/>

View File

@@ -64,4 +64,6 @@
<string name="enabled">Enabled</string>
<string name="override_auto_backup_file">Override Auto Backup File</string>
<string name="scanner">Scanner</string>
<string name="alert_black_secret_key">Please enter secret key</string>
<string name="alert_black_account_name">Please enter account name</string>
</resources>