mirror of
https://github.com/yogeshpaliyal/KeyPass.git
synced 2026-02-06 03:19:02 -06:00
Merge pull request #23 from yogeshpaliyal/feature/auto_backup
Upgrade to AGP 7, Dependencies updated
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||

|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
4
app/.gitignore
vendored
4
app/.gitignore
vendored
@@ -1 +1,3 @@
|
||||
/build
|
||||
/build
|
||||
**.aab
|
||||
**.apk
|
||||
@@ -1,7 +0,0 @@
|
||||
[packages]
|
||||
com.yogeshpaliyal.keypass = raa
|
||||
|
||||
[localazy]
|
||||
allStringsUploaded = true
|
||||
showWelcomeMessage = false
|
||||
|
||||
@@ -62,7 +62,7 @@ android {
|
||||
}
|
||||
|
||||
lintOptions{
|
||||
abortOnError false
|
||||
abortOnError true
|
||||
}
|
||||
|
||||
testOptions.unitTests.includeAndroidResources = true
|
||||
@@ -79,6 +79,7 @@ dependencies {
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
|
||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
||||
BIN
app/production/release/app-production-release.apk
Normal file
BIN
app/production/release/app-production-release.apk
Normal file
Binary file not shown.
18
app/production/release/output-metadata.json
Normal file
18
app/production/release/output-metadata.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 2,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.yogeshpaliyal.keypass",
|
||||
"variantName": "processProductionReleaseResources",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"versionCode": 3,
|
||||
"versionName": "1.3",
|
||||
"outputFile": "app-production-release.apk"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.yogeshpaliyal.keypass
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
@@ -21,4 +19,4 @@ class ExampleInstrumentedTest {
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.yogeshpaliyal.keypass", appContext.packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
package com.yogeshpaliyal.keypass
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.yogeshpaliyal.keypass.data.AccountModel
|
||||
import com.yogeshpaliyal.keypass.db.DbDao
|
||||
import com.yogeshpaliyal.keypass.utils.getRandomString
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
@@ -25,4 +20,4 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
// define DAO start
|
||||
abstract fun getDao(): DbDao
|
||||
// define DAO end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package com.yogeshpaliyal.keypass
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
* https://techpaliyal.com
|
||||
* created on 23-01-2021 10:33
|
||||
*/
|
||||
data class InfoModel(var user_id: String,
|
||||
var username : String,
|
||||
var password : String,
|
||||
var notes: String,
|
||||
var insertedDate : Long,
|
||||
var lastUpdatedDate : Long)
|
||||
data class InfoModel(
|
||||
var user_id: String,
|
||||
var username: String,
|
||||
var password: String,
|
||||
var notes: String,
|
||||
var insertedDate: Long,
|
||||
var lastUpdatedDate: Long
|
||||
)
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.yogeshpaliyal.keypass
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* yogeshpaliyal.foss@gmail.com
|
||||
@@ -13,14 +12,12 @@ import dagger.hilt.android.HiltAndroidApp
|
||||
@HiltAndroidApp
|
||||
class MyApplication : Application() {
|
||||
|
||||
companion object{
|
||||
companion object {
|
||||
lateinit var instance: MyApplication
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
instance = this
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,4 +44,4 @@ class MaskedCardView @JvmOverloads constructor(
|
||||
pathProvider.calculatePath(shapeAppearance, 1f, rectF, path)
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import androidx.room.PrimaryKey
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.yogeshpaliyal.universal_adapter.model.BaseDiffUtil
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -49,8 +48,10 @@ data class AccountModel(
|
||||
var tags: String? = null
|
||||
) : BaseDiffUtil {
|
||||
|
||||
fun getInitials() = (title?.firstOrNull() ?: username?.firstOrNull() ?: site?.firstOrNull()
|
||||
?: notes?.firstOrNull() ?: 'K').toString()
|
||||
fun getInitials() = (
|
||||
title?.firstOrNull() ?: username?.firstOrNull() ?: site?.firstOrNull()
|
||||
?: notes?.firstOrNull() ?: 'K'
|
||||
).toString()
|
||||
|
||||
override fun getDiffId(): Any? {
|
||||
return id
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.yogeshpaliyal.keypass.data
|
||||
import com.google.gson.annotations.Expose
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -13,8 +12,8 @@ import com.google.gson.annotations.SerializedName
|
||||
data class BackupData(
|
||||
@SerializedName("version")
|
||||
@Expose
|
||||
val version : Int,
|
||||
val version: Int,
|
||||
@SerializedName("data")
|
||||
@Expose
|
||||
val data : List<AccountModel> ) {
|
||||
}
|
||||
val data: List<AccountModel>
|
||||
)
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.room.Query
|
||||
import com.yogeshpaliyal.keypass.data.AccountModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -25,7 +24,6 @@ abstract class DbDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract fun insertOrUpdateAccount(accountModel: List<AccountModel>)
|
||||
|
||||
|
||||
@Query("SELECT * FROM account ORDER BY title ASC")
|
||||
abstract fun getAllAccounts(): LiveData<List<AccountModel>>
|
||||
|
||||
@@ -43,6 +41,4 @@ abstract class DbDao {
|
||||
|
||||
@Query("DELETE from account WHERE id = :id")
|
||||
abstract fun deleteAccount(id: Long?)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.yogeshpaliyal.keypass.db_helper
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
|
||||
@@ -11,7 +11,6 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -32,7 +31,6 @@ suspend fun AppDatabase.createBackup(key: String, contentResolver: ContentResolv
|
||||
return@withContext true
|
||||
}
|
||||
|
||||
|
||||
suspend fun AppDatabase.restoreBackup(
|
||||
key: String,
|
||||
contentResolver: ContentResolver,
|
||||
@@ -47,7 +45,7 @@ suspend fun AppDatabase.restoreBackup(
|
||||
return@withContext false
|
||||
}
|
||||
|
||||
return@withContext Gson().fromJson(restoredFile, BackupData::class.java)?.let{ data ->
|
||||
return@withContext Gson().fromJson(restoredFile, BackupData::class.java)?.let { data ->
|
||||
if (data.version == 3) {
|
||||
for (datum in data.data) {
|
||||
datum.uniqueId = getRandomString()
|
||||
@@ -59,8 +57,6 @@ suspend fun AppDatabase.restoreBackup(
|
||||
withTransaction {
|
||||
getDao().insertOrUpdateAccount(data.data)
|
||||
}
|
||||
true
|
||||
true
|
||||
} ?: false
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.yogeshpaliyal.keypass.db_helper
|
||||
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
@@ -15,7 +14,6 @@ import javax.crypto.*
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -25,21 +23,20 @@ import javax.crypto.spec.SecretKeySpec
|
||||
*/
|
||||
object EncryptionHelper {
|
||||
private const val ALGORITHM = "AES"
|
||||
private const val TRANSFORMATION = "AES/CBC/PKCS5Padding"
|
||||
//private const val TRANSFORMATION = "AES"
|
||||
private const val TRANSFORMATION = "AES/CBC/PKCS5Padding"
|
||||
// private const val TRANSFORMATION = "AES"
|
||||
// private const val TRANSFORMATION = "DES/CBC/PKCS5Padding"
|
||||
|
||||
private val iV = byteArrayOf(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
|
||||
private val iV = byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
|
||||
@Throws(CryptoException::class)
|
||||
fun doCryptoEncrypt(
|
||||
key: String, data: String,
|
||||
key: String,
|
||||
data: String,
|
||||
outputFile: OutputStream?
|
||||
) {
|
||||
try {
|
||||
|
||||
|
||||
val secretKey: Key =
|
||||
SecretKeySpec(key.toByteArray(), ALGORITHM)
|
||||
val cipher = Cipher.getInstance(TRANSFORMATION)
|
||||
@@ -47,7 +44,7 @@ object EncryptionHelper {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(iV))
|
||||
|
||||
data.byteInputStream().use {
|
||||
val inputStream = it
|
||||
val inputStream = it
|
||||
outputFile?.use {
|
||||
val outputStream = it
|
||||
CipherOutputStream(outputStream, cipher).use {
|
||||
@@ -62,7 +59,7 @@ object EncryptionHelper {
|
||||
// Log.d("TestingEnc","NoSuchAlgorithmException")
|
||||
throw CryptoException("Error encrypting/decrypting file", ex)
|
||||
} catch (ex: InvalidKeyException) {
|
||||
//Log.d("TestingEnc","InvalidKeyException")
|
||||
// Log.d("TestingEnc","InvalidKeyException")
|
||||
throw CryptoException("Error encrypting/decrypting file", ex)
|
||||
} catch (ex: BadPaddingException) {
|
||||
// Log.d("TestingEnc","BadPaddingException")
|
||||
@@ -76,11 +73,11 @@ object EncryptionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Throws(CryptoException::class)
|
||||
fun doCryptoDecrypt(
|
||||
key: String, inputFile: InputStream?
|
||||
) : String {
|
||||
key: String,
|
||||
inputFile: InputStream?
|
||||
): String {
|
||||
var data = ""
|
||||
try {
|
||||
val secretKey: Key =
|
||||
@@ -91,25 +88,24 @@ object EncryptionHelper {
|
||||
|
||||
inputFile.use {
|
||||
val inputStream = it
|
||||
CipherInputStream(inputStream, cipher).use {
|
||||
data = String(it.readBytes())
|
||||
}
|
||||
CipherInputStream(inputStream, cipher).use {
|
||||
data = String(it.readBytes())
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ex: NoSuchPaddingException) {
|
||||
//Log.d("TestingEnc","NoSuchPaddingException")
|
||||
// Log.d("TestingEnc","NoSuchPaddingException")
|
||||
throw CryptoException("Error encrypting/decrypting file", ex)
|
||||
} catch (ex: NoSuchAlgorithmException) {
|
||||
//Log.d("TestingEnc","NoSuchAlgorithmException")
|
||||
// Log.d("TestingEnc","NoSuchAlgorithmException")
|
||||
throw CryptoException("Error encrypting/decrypting file", ex)
|
||||
} catch (ex: InvalidKeyException) {
|
||||
//Log.d("TestingEnc","InvalidKeyException")
|
||||
// Log.d("TestingEnc","InvalidKeyException")
|
||||
throw CryptoException("Error encrypting/decrypting file", ex)
|
||||
} catch (ex: BadPaddingException) {
|
||||
//Log.d("TestingEnc","BadPaddingException")
|
||||
// Log.d("TestingEnc","BadPaddingException")
|
||||
throw CryptoException("Error encrypting/decrypting file", ex)
|
||||
} catch (ex: IllegalBlockSizeException) {
|
||||
//Log.d("TestingEnc","IllegalBlockSizeException")
|
||||
// Log.d("TestingEnc","IllegalBlockSizeException")
|
||||
throw CryptoException("Error encrypting/decrypting file", ex)
|
||||
} catch (ex: IOException) {
|
||||
// Log.d("TestingEnc","IOException")
|
||||
@@ -119,9 +115,7 @@ object EncryptionHelper {
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun encryptPassword(message: String, password: String): String{
|
||||
fun encryptPassword(message: String, password: String): String {
|
||||
/* Encrypt the message. */
|
||||
var cipher: Cipher? = null
|
||||
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
|
||||
@@ -147,11 +141,8 @@ object EncryptionHelper {
|
||||
return String(cipher.doFinal(encryptedMessage.toByteArray()))
|
||||
}
|
||||
|
||||
|
||||
@Throws(NoSuchAlgorithmException::class, InvalidKeySpecException::class)
|
||||
fun generateKey(passLockKey: String): SecretKey {
|
||||
return SecretKeySpec(passLockKey.encodeToByteArray(), "AES")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,13 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object AppModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun getDb(@ApplicationContext context: Context): AppDatabase{
|
||||
fun getDb(@ApplicationContext context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(
|
||||
context,
|
||||
AppDatabase::class.java,
|
||||
@@ -44,12 +43,9 @@ object AppModule {
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun getSharedPre(@ApplicationContext context: Context): SharedPreferences{
|
||||
fun getSharedPre(@ApplicationContext context: Context): SharedPreferences {
|
||||
return MySharedPreferences(context).sharedPref
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.yogeshpaliyal.keypass.listener
|
||||
|
||||
import android.view.View
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -12,4 +11,4 @@ import android.view.View
|
||||
interface AccountsClickListener<T> {
|
||||
fun onItemClick(view: View, model: T)
|
||||
fun onCopyClicked(model: T)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.yogeshpaliyal.keypass.listener
|
||||
|
||||
import android.view.View
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -11,4 +10,4 @@ import android.view.View
|
||||
*/
|
||||
interface UniversalClickListener<T> {
|
||||
fun onItemClick(view: View, model: T)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ class BasicService : AutofillService() {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Create the base response
|
||||
val response = FillResponse.Builder()
|
||||
|
||||
@@ -129,8 +128,9 @@ class BasicService : AutofillService() {
|
||||
fields[hint] = id
|
||||
} else {
|
||||
Log.v(
|
||||
TAG, "Ignoring hint '" + hint + "' on " + id
|
||||
+ " because it was already set"
|
||||
TAG,
|
||||
"Ignoring hint '" + hint + "' on " + id +
|
||||
" because it was already set"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -173,9 +173,9 @@ class BasicService : AutofillService() {
|
||||
text: CharSequence
|
||||
): RemoteViews {
|
||||
val presentation = RemoteViews(packageName, R.layout.multidataset_service_list_item)
|
||||
presentation.setTextViewText(R.id.text, "paliyal"+text)
|
||||
presentation.setTextViewText(R.id.text, "paliyal" + text)
|
||||
presentation.setImageViewResource(R.id.icon, R.mipmap.ic_launcher)
|
||||
return presentation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
package com.yogeshpaliyal.keypass.service
|
||||
|
||||
import android.app.assist.AssistStructure
|
||||
import android.app.assist.AssistStructure.ViewNode
|
||||
import android.os.Build
|
||||
import android.os.CancellationSignal
|
||||
import android.service.autofill.*
|
||||
import android.view.autofill.AutofillId
|
||||
import android.view.autofill.AutofillValue
|
||||
import android.widget.RemoteViews
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -24,21 +17,13 @@ class MyAutoFillService : AutofillService() {
|
||||
private val TAG = "MyAutoFillService"
|
||||
private val NUMBER_DATASETS = 4
|
||||
|
||||
|
||||
override fun onFillRequest(
|
||||
request: FillRequest,
|
||||
cancellationSignal: CancellationSignal,
|
||||
callback: FillCallback
|
||||
) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,25 +12,23 @@ import com.yogeshpaliyal.keypass.ui.nav.DashboardActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AuthenticationActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding : ActivityAuthenticationBinding
|
||||
private lateinit var binding: ActivityAuthenticationBinding
|
||||
|
||||
private lateinit var executor: Executor
|
||||
private lateinit var biometricPrompt: BiometricPrompt
|
||||
private lateinit var promptInfo: BiometricPrompt.PromptInfo
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityAuthenticationBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
executor = ContextCompat.getMainExecutor(this)
|
||||
biometricPrompt = BiometricPrompt(this, executor,
|
||||
biometricPrompt = BiometricPrompt(
|
||||
this, executor,
|
||||
object : BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(
|
||||
errorCode: Int,
|
||||
@@ -42,7 +40,7 @@ class AuthenticationActivity : AppCompatActivity() {
|
||||
"Authentication error: $errString", Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
// finish()
|
||||
// finish()
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(
|
||||
@@ -61,8 +59,8 @@ class AuthenticationActivity : AppCompatActivity() {
|
||||
)
|
||||
.show()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.app_name))
|
||||
@@ -78,16 +76,13 @@ class AuthenticationActivity : AppCompatActivity() {
|
||||
|
||||
binding.btnRetry.setOnClickListener {
|
||||
biometricPrompt.authenticate(promptInfo)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun onAuthenticated(){
|
||||
// binding.passCodeView.isVisible = false
|
||||
private fun onAuthenticated() {
|
||||
// binding.passCodeView.isVisible = false
|
||||
val dashboardIntent = Intent(this, DashboardActivity::class.java)
|
||||
startActivity(dashboardIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,10 @@ class BackupActivity : AppCompatActivity() {
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
|
||||
@Inject
|
||||
lateinit var sp : SharedPreferences
|
||||
lateinit var sp: SharedPreferences
|
||||
|
||||
@Inject
|
||||
lateinit var appDb : AppDatabase
|
||||
lateinit var appDb: AppDatabase
|
||||
|
||||
private val CHOOSE_BACKUPS_LOCATION_REQUEST_CODE = 26212
|
||||
|
||||
@@ -102,22 +102,22 @@ class BackupActivity : AppCompatActivity() {
|
||||
findPreference<Preference>("start_backup")?.isVisible = isBackupEnabled.not()
|
||||
|
||||
findPreference<Preference>("create_backup")?.isVisible = isBackupEnabled
|
||||
findPreference<Preference>("create_backup")?.summary = getString(R.string.last_backup_date,getBackupTime(sp).formatCalendar("dd MMM yyyy hh:mm aa"))
|
||||
findPreference<Preference>("create_backup")?.summary = getString(R.string.last_backup_date, getBackupTime(sp).formatCalendar("dd MMM yyyy hh:mm aa"))
|
||||
findPreference<Preference>("backup_folder")?.isVisible = isBackupEnabled
|
||||
val directory = URLDecoder.decode(getBackupDirectory(sp),"utf-8").split("/")
|
||||
val directory = URLDecoder.decode(getBackupDirectory(sp), "utf-8").split("/")
|
||||
val folderName = directory.get(directory.lastIndex)
|
||||
findPreference<Preference>("backup_folder")?.summary = folderName
|
||||
findPreference<Preference>("settings_verify_key_phrase")?.isVisible = false
|
||||
findPreference<Preference>("stop_backup")?.isVisible = isBackupEnabled
|
||||
}
|
||||
|
||||
private fun startBackup(){
|
||||
private fun startBackup() {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
|
||||
intent.addFlags(
|
||||
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
)
|
||||
|
||||
try {
|
||||
@@ -129,7 +129,7 @@ class BackupActivity : AppCompatActivity() {
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == CHOOSE_BACKUPS_LOCATION_REQUEST_CODE && resultCode == Activity.RESULT_OK){
|
||||
if (requestCode == CHOOSE_BACKUPS_LOCATION_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
|
||||
val contentResolver = context?.contentResolver
|
||||
val selectedDirectory = data?.data
|
||||
if (contentResolver != null && selectedDirectory != null) {
|
||||
@@ -138,13 +138,13 @@ class BackupActivity : AppCompatActivity() {
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
|
||||
setBackupDirectory(sp,selectedDirectory.toString())
|
||||
setBackupDirectory(sp, selectedDirectory.toString())
|
||||
backup(selectedDirectory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun backup(selectedDirectory: Uri){
|
||||
private fun backup(selectedDirectory: Uri) {
|
||||
|
||||
val keyPair = getOrCreateBackupKey(sp)
|
||||
|
||||
@@ -155,11 +155,12 @@ class BackupActivity : AppCompatActivity() {
|
||||
|
||||
lifecycleScope.launch {
|
||||
context?.contentResolver?.let {
|
||||
appDb.createBackup(keyPair.second,
|
||||
appDb.createBackup(
|
||||
keyPair.second,
|
||||
it,
|
||||
tempFile?.uri
|
||||
)
|
||||
setBackupTime(sp,System.currentTimeMillis())
|
||||
setBackupTime(sp, System.currentTimeMillis())
|
||||
if (keyPair.first) {
|
||||
val binding = LayoutBackupKeypharseBinding.inflate(layoutInflater)
|
||||
binding.txtCode.text = getOrCreateBackupKey(sp).second
|
||||
@@ -176,9 +177,10 @@ class BackupActivity : AppCompatActivity() {
|
||||
MaterialAlertDialogBuilder(requireContext()).setView(binding.root)
|
||||
.setPositiveButton(
|
||||
getString(R.string.yes)
|
||||
) { dialog, which -> dialog?.dismiss()
|
||||
) { dialog, which ->
|
||||
dialog?.dismiss()
|
||||
}.show()
|
||||
}else{
|
||||
} else {
|
||||
Toast.makeText(context, getString(R.string.backup_completed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
@@ -187,20 +189,19 @@ class BackupActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun changeBackupFolder(){
|
||||
private fun changeBackupFolder() {
|
||||
startBackup()
|
||||
}
|
||||
|
||||
private fun verifyKeyPhrase(){
|
||||
private fun verifyKeyPhrase() {
|
||||
Toast.makeText(context, getString(R.string.coming_soon), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun stopBackup(){
|
||||
private fun stopBackup() {
|
||||
clearBackupKey(sp)
|
||||
setBackupDirectory(sp,"")
|
||||
setBackupTime(sp,-1)
|
||||
setBackupDirectory(sp, "")
|
||||
setBackupTime(sp, -1)
|
||||
updateItems()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Observer
|
||||
@@ -20,7 +19,6 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* yogeshpaliyal.foss@gmail.com
|
||||
@@ -32,7 +30,6 @@ class DetailActivity : AppCompatActivity() {
|
||||
|
||||
lateinit var binding: FragmentDetailBinding
|
||||
|
||||
|
||||
@Inject
|
||||
lateinit var appDb: AppDatabase
|
||||
|
||||
@@ -50,7 +47,6 @@ class DetailActivity : AppCompatActivity() {
|
||||
|
||||
private val mViewModel by viewModels<DetailViewModel>()
|
||||
|
||||
|
||||
private val accountId by lazy {
|
||||
intent?.extras?.getLong(ARG_ACCOUNT_ID) ?: -1
|
||||
}
|
||||
@@ -62,9 +58,12 @@ class DetailActivity : AppCompatActivity() {
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
mViewModel.loadAccount(accountId)
|
||||
mViewModel.accountModel.observe(this, Observer {
|
||||
binding.accountData = it
|
||||
})
|
||||
mViewModel.accountModel.observe(
|
||||
this,
|
||||
Observer {
|
||||
binding.accountData = it
|
||||
}
|
||||
)
|
||||
|
||||
if (accountId > 0) {
|
||||
binding.bottomAppBar.replaceMenu(R.menu.bottom_app_bar_detail)
|
||||
@@ -78,8 +77,6 @@ class DetailActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
binding.bottomAppBar.setNavigationOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
@@ -92,7 +89,6 @@ class DetailActivity : AppCompatActivity() {
|
||||
return@setOnMenuItemClickListener false
|
||||
}
|
||||
|
||||
|
||||
binding.btnSave.setOnClickListener {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val model = mViewModel.accountModel.value
|
||||
@@ -126,12 +122,10 @@ class DetailActivity : AppCompatActivity() {
|
||||
.setNegativeButton(getString(R.string.cancel)) { dialog, which ->
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.bottom_app_bar_detail, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -30,8 +29,5 @@ class DetailViewModel @Inject constructor(application: Application, val appDb: A
|
||||
appDb.getDao().getAccount(accountId) ?: AccountModel()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.yogeshpaliyal.keypass.ui.generate
|
||||
|
||||
import android.R.attr.label
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.os.Bundle
|
||||
@@ -12,10 +11,9 @@ import com.yogeshpaliyal.keypass.databinding.ActivityGeneratePasswordBinding
|
||||
import com.yogeshpaliyal.keypass.utils.PasswordGenerator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class GeneratePasswordActivity : AppCompatActivity() {
|
||||
private lateinit var binding : ActivityGeneratePasswordBinding
|
||||
private lateinit var binding: ActivityGeneratePasswordBinding
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityGeneratePasswordBinding.inflate(layoutInflater)
|
||||
@@ -28,15 +26,14 @@ class GeneratePasswordActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
binding.tilPassword.setEndIconOnClickListener {
|
||||
val clipboard= getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("random_password", binding.etPassword.text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(this, getString(R.string.copied_to_clipboard), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun generatePassword(){
|
||||
private fun generatePassword() {
|
||||
val password = PasswordGenerator(
|
||||
binding.sliderPasswordLength.value.toInt(), binding.cbCapAlphabets.isChecked,
|
||||
binding.cbLowerAlphabets.isChecked,
|
||||
@@ -46,4 +43,4 @@ class GeneratePasswordActivity : AppCompatActivity() {
|
||||
|
||||
binding.etPassword.setText(password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.yogeshpaliyal.keypass.data.AccountModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -28,7 +27,6 @@ class DashboardViewModel @Inject constructor(application: Application, val appDb
|
||||
MutableLiveData<String>()
|
||||
}
|
||||
|
||||
|
||||
val mediator = MediatorLiveData<LiveData<List<AccountModel>>>()
|
||||
|
||||
init {
|
||||
@@ -40,7 +38,5 @@ class DashboardViewModel @Inject constructor(application: Application, val appDb
|
||||
mediator.postValue(appDb.getDao().getAllAccounts(keyword.value, tag.value))
|
||||
}
|
||||
mediator.postValue(appDb.getDao().getAllAccounts(keyword.value, tag.value))
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,12 @@ import com.yogeshpaliyal.keypass.R
|
||||
import com.yogeshpaliyal.keypass.data.AccountModel
|
||||
import com.yogeshpaliyal.keypass.databinding.FragmentHomeBinding
|
||||
import com.yogeshpaliyal.keypass.listener.AccountsClickListener
|
||||
import com.yogeshpaliyal.keypass.listener.UniversalClickListener
|
||||
import com.yogeshpaliyal.keypass.ui.detail.DetailActivity
|
||||
import com.yogeshpaliyal.universal_adapter.adapter.UniversalAdapterViewType
|
||||
import com.yogeshpaliyal.universal_adapter.adapter.UniversalRecyclerAdapter
|
||||
import com.yogeshpaliyal.universal_adapter.utils.Resource
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -76,7 +74,6 @@ class HomeFragment : Fragment() {
|
||||
|
||||
val observer = Observer<List<AccountModel>> {
|
||||
mAdapter.updateData(Resource.success(it))
|
||||
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -84,10 +81,13 @@ class HomeFragment : Fragment() {
|
||||
|
||||
binding.recyclerView.adapter = mAdapter.getAdapter()
|
||||
|
||||
mViewModel.mediator.observe(viewLifecycleOwner, Observer {
|
||||
it.removeObserver(observer)
|
||||
it.observe(viewLifecycleOwner, observer)
|
||||
})
|
||||
mViewModel.mediator.observe(
|
||||
viewLifecycleOwner,
|
||||
Observer {
|
||||
it.removeObserver(observer)
|
||||
it.observe(viewLifecycleOwner, observer)
|
||||
}
|
||||
)
|
||||
|
||||
/* lifecycleScope.launch() {
|
||||
mViewModel.result
|
||||
@@ -97,8 +97,5 @@ class HomeFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,8 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior.from
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import com.yogeshpaliyal.keypass.R
|
||||
import com.yogeshpaliyal.keypass.databinding.FragmentBottomNavDrawerBinding
|
||||
import com.yogeshpaliyal.keypass.ui.detail.DetailViewModel
|
||||
import com.yogeshpaliyal.keypass.utils.initViewModel
|
||||
import com.yogeshpaliyal.keypass.utils.themeColor
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
import kotlin.LazyThreadSafetyMode.NONE
|
||||
|
||||
/**
|
||||
@@ -36,8 +33,6 @@ class BottomNavDrawerFragment :
|
||||
Fragment(),
|
||||
NavigationAdapter.NavigationAdapterListener {
|
||||
|
||||
|
||||
|
||||
private lateinit var binding: FragmentBottomNavDrawerBinding
|
||||
|
||||
private val behavior: BottomSheetBehavior<FrameLayout> by lazy(NONE) {
|
||||
@@ -46,14 +41,10 @@ class BottomNavDrawerFragment :
|
||||
|
||||
private val mViewModel by viewModels<BottomNavViewModel>()
|
||||
|
||||
|
||||
private val bottomSheetCallback = BottomNavigationDrawerCallback()
|
||||
|
||||
|
||||
private val navigationListeners: MutableList<NavigationAdapter.NavigationAdapterListener> =
|
||||
mutableListOf()
|
||||
|
||||
|
||||
mutableListOf()
|
||||
|
||||
private val foregroundShapeDrawable: MaterialShapeDrawable by lazy(NONE) {
|
||||
val foregroundContext = binding.foregroundContainer.context
|
||||
@@ -82,7 +73,6 @@ class BottomNavDrawerFragment :
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val closeDrawerOnBackPressed = object : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() {
|
||||
close()
|
||||
@@ -115,7 +105,7 @@ class BottomNavDrawerFragment :
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.run {
|
||||
//backgroundContainer.background = backgroundShapeDrawable
|
||||
// backgroundContainer.background = backgroundShapeDrawable
|
||||
foregroundContainer.background = foregroundShapeDrawable
|
||||
|
||||
scrimView.setOnClickListener { close() }
|
||||
@@ -134,7 +124,6 @@ class BottomNavDrawerFragment :
|
||||
// Close the sandwiching account picker if open
|
||||
addOnStateChangedAction(object : OnStateChangedAction {
|
||||
override fun onStateChanged(sheet: View, newState: Int) {
|
||||
|
||||
}
|
||||
})
|
||||
// If the drawer is open, pressing the system back button should close the drawer.
|
||||
@@ -145,8 +134,6 @@ class BottomNavDrawerFragment :
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
behavior.addBottomSheetCallback(bottomSheetCallback)
|
||||
behavior.state = STATE_HIDDEN
|
||||
|
||||
@@ -157,11 +144,9 @@ class BottomNavDrawerFragment :
|
||||
adapter.submitList(it)
|
||||
}
|
||||
mViewModel.setNavigationMenuItemChecked(0)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun open() {
|
||||
behavior.state = STATE_HALF_EXPANDED
|
||||
}
|
||||
@@ -182,8 +167,6 @@ class BottomNavDrawerFragment :
|
||||
navigationListeners.add(listener)
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onNavMenuItemClicked(item: NavigationModelItem.NavMenuItem) {
|
||||
mViewModel.setNavigationMenuItemChecked(item.id)
|
||||
close()
|
||||
@@ -194,15 +177,13 @@ class BottomNavDrawerFragment :
|
||||
navigationListeners.forEach { it.onNavEmailFolderClicked(folder) }
|
||||
}
|
||||
|
||||
|
||||
fun toggle() {
|
||||
when {
|
||||
behavior.state == STATE_HIDDEN -> open()
|
||||
behavior.state == STATE_HIDDEN
|
||||
|| behavior.state == STATE_HALF_EXPANDED
|
||||
|| behavior.state == STATE_EXPANDED
|
||||
|| behavior.state == STATE_COLLAPSED -> close()
|
||||
behavior.state == STATE_HIDDEN ||
|
||||
behavior.state == STATE_HALF_EXPANDED ||
|
||||
behavior.state == STATE_EXPANDED
|
||||
|| behavior.state == STATE_COLLAPSED -> close()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -19,17 +18,17 @@ import javax.inject.Inject
|
||||
* created on 31-01-2021 14:11
|
||||
*/
|
||||
@HiltViewModel
|
||||
class BottomNavViewModel @Inject constructor (application: Application,val appDb: AppDatabase) : AndroidViewModel(application) {
|
||||
class BottomNavViewModel @Inject constructor (application: Application, val appDb: AppDatabase) : AndroidViewModel(application) {
|
||||
private val _navigationList: MutableLiveData<List<NavigationModelItem>> = MutableLiveData()
|
||||
private val tagsDb = appDb.getDao().getTags()
|
||||
|
||||
private var tagsList : List<String> ?= null
|
||||
private var tagsList: List<String> ? = null
|
||||
|
||||
val navigationList: LiveData<List<NavigationModelItem>>
|
||||
get() = _navigationList
|
||||
|
||||
init {
|
||||
postListUpdate()
|
||||
postListUpdate()
|
||||
|
||||
viewModelScope.launch {
|
||||
tagsDb.collect {
|
||||
@@ -39,8 +38,6 @@ class BottomNavViewModel @Inject constructor (application: Application,val appDb
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the currently selected menu item.
|
||||
*
|
||||
@@ -59,18 +56,13 @@ class BottomNavViewModel @Inject constructor (application: Application,val appDb
|
||||
return updated
|
||||
}
|
||||
|
||||
|
||||
private fun postListUpdate() {
|
||||
val newList = if(tagsList.isNullOrEmpty().not()){
|
||||
val newList = if (tagsList.isNullOrEmpty().not()) {
|
||||
NavigationModel.navigationMenuItems + NavigationModelItem.NavDivider("Tags") + (tagsList?.filter { it != null }?.map { NavigationModelItem.NavEmailFolder(it) } ?: listOf())
|
||||
}else{
|
||||
} else {
|
||||
NavigationModel.navigationMenuItems
|
||||
}
|
||||
|
||||
|
||||
_navigationList.value = newList
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +97,4 @@ class BottomNavigationDrawerCallback : BottomSheetBehavior.BottomSheetCallback()
|
||||
fun removeOnStateChangedAction(action: OnStateChangedAction): Boolean {
|
||||
return onStateChangedActions.remove(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ import com.yogeshpaliyal.keypass.ui.settings.MySettingsFragmentDirections
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class DashboardActivity : AppCompatActivity(),
|
||||
class DashboardActivity :
|
||||
AppCompatActivity(),
|
||||
Toolbar.OnMenuItemClickListener,
|
||||
NavController.OnDestinationChangedListener,
|
||||
NavigationAdapter.NavigationAdapterListener {
|
||||
lateinit var binding: ActivityDashboardBinding
|
||||
|
||||
|
||||
private val bottomNavDrawer: BottomNavDrawerFragment by lazy(LazyThreadSafetyMode.NONE) {
|
||||
supportFragmentManager.findFragmentById(R.id.bottom_nav_drawer) as BottomNavDrawerFragment
|
||||
}
|
||||
@@ -51,11 +51,11 @@ class DashboardActivity : AppCompatActivity(),
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_SECURE,
|
||||
WindowManager.LayoutParams.FLAG_SECURE
|
||||
);
|
||||
)
|
||||
binding = ActivityDashboardBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
//setSupportActionBar(binding.bottomAppBar)
|
||||
// setSupportActionBar(binding.bottomAppBar)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = mViewModel
|
||||
@@ -64,11 +64,9 @@ class DashboardActivity : AppCompatActivity(),
|
||||
this@DashboardActivity
|
||||
)
|
||||
|
||||
|
||||
/* val intent = Intent(this, AuthenticationActivity::class.java)
|
||||
startActivity(intent)*/
|
||||
|
||||
|
||||
/* val autoFillService = getAutoFillService()
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
if (autoFillService?.isAutofillSupported == true && autoFillService.hasEnabledAutofillServices().not()) {
|
||||
@@ -78,7 +76,6 @@ class DashboardActivity : AppCompatActivity(),
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
binding.btnAdd.setOnClickListener {
|
||||
currentNavigationFragment?.apply {
|
||||
exitTransition = MaterialElevationScale(false).apply {
|
||||
@@ -89,25 +86,26 @@ class DashboardActivity : AppCompatActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
DetailActivity.start(this)
|
||||
DetailActivity.start(this)
|
||||
}
|
||||
|
||||
|
||||
bottomNavDrawer.apply {
|
||||
//addOnSlideAction(HalfClockwiseRotateSlideAction(binding.bottomAppBar))
|
||||
// addOnSlideAction(HalfClockwiseRotateSlideAction(binding.bottomAppBar))
|
||||
// addOnSlideAction(AlphaSlideAction(binding.bottomAppBarTitle, true))
|
||||
addOnStateChangedAction(ShowHideFabStateAction(binding.btnAdd))
|
||||
addOnStateChangedAction(ChangeSettingsMenuStateAction { showSettings ->
|
||||
// Toggle between the current destination's BAB menu and the menu which should
|
||||
// be displayed when the BottomNavigationDrawer is open.
|
||||
binding.bottomAppBar.replaceMenu(
|
||||
if (showSettings) {
|
||||
R.menu.bottom_app_bar_settings_menu
|
||||
} else {
|
||||
getBottomAppBarMenuForDestination()
|
||||
}
|
||||
)
|
||||
})
|
||||
addOnStateChangedAction(
|
||||
ChangeSettingsMenuStateAction { showSettings ->
|
||||
// Toggle between the current destination's BAB menu and the menu which should
|
||||
// be displayed when the BottomNavigationDrawer is open.
|
||||
binding.bottomAppBar.replaceMenu(
|
||||
if (showSettings) {
|
||||
R.menu.bottom_app_bar_settings_menu
|
||||
} else {
|
||||
getBottomAppBarMenuForDestination()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
// addOnSandwichSlideAction(HalfCounterClockwiseRotateSlideAction(binding.bottomAppBarChevron))
|
||||
addNavigationListener(this@DashboardActivity)
|
||||
@@ -120,8 +118,6 @@ class DashboardActivity : AppCompatActivity(),
|
||||
}
|
||||
setOnMenuItemClickListener(this@DashboardActivity)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
@@ -135,8 +131,6 @@ class DashboardActivity : AppCompatActivity(),
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onDestinationChanged(
|
||||
controller: NavController,
|
||||
destination: NavDestination,
|
||||
@@ -154,8 +148,8 @@ class DashboardActivity : AppCompatActivity(),
|
||||
|
||||
override fun onNavMenuItemClicked(item: NavigationModelItem.NavMenuItem) {
|
||||
// Swap the list of emails for the given mailbox
|
||||
//navigateToHome(item.titleRes, item.mailbox)
|
||||
when(item.id){
|
||||
// navigateToHome(item.titleRes, item.mailbox)
|
||||
when (item.id) {
|
||||
NavigationModel.GENERATE_PASSWORD -> {
|
||||
val intent = Intent(this, GeneratePasswordActivity::class.java)
|
||||
startActivity(intent)
|
||||
@@ -174,7 +168,6 @@ class DashboardActivity : AppCompatActivity(),
|
||||
bottomNavDrawer.close()
|
||||
}
|
||||
|
||||
|
||||
private fun hideBottomAppBar() {
|
||||
binding.run {
|
||||
bottomAppBar.performHide()
|
||||
@@ -211,21 +204,20 @@ class DashboardActivity : AppCompatActivity(),
|
||||
val dest = destination ?: findNavController(R.id.nav_host_fragment).currentDestination
|
||||
return when (dest?.id) {
|
||||
R.id.homeFragment -> R.menu.bottom_app_bar_settings_menu
|
||||
//R.id.emailFragment -> R.menu.bottom_app_bar_email_menu
|
||||
// R.id.emailFragment -> R.menu.bottom_app_bar_email_menu
|
||||
else -> R.menu.bottom_app_bar_settings_menu
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setBottomAppBarForHome(@MenuRes menuRes: Int) {
|
||||
binding.run {
|
||||
btnAdd.setImageState(intArrayOf(-android.R.attr.state_activated), true)
|
||||
bottomAppBar.visibility = View.VISIBLE
|
||||
bottomAppBar.replaceMenu(menuRes)
|
||||
//btnAdd.contentDescription = getString(R.string.fab_compose_email_content_description)
|
||||
//bottomAppBarTitle.visibility = View.VISIBLE
|
||||
// btnAdd.contentDescription = getString(R.string.fab_compose_email_content_description)
|
||||
// bottomAppBarTitle.visibility = View.VISIBLE
|
||||
bottomAppBar.performShow()
|
||||
btnAdd.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +86,4 @@ class NavigationAdapter(
|
||||
) {
|
||||
holder.bind(getItem(position))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.yogeshpaliyal.keypass.ui.nav
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.yogeshpaliyal.keypass.R
|
||||
|
||||
/**
|
||||
@@ -12,7 +10,6 @@ object NavigationModel {
|
||||
const val HOME = 0
|
||||
const val GENERATE_PASSWORD = 1
|
||||
|
||||
|
||||
var navigationMenuItems = mutableListOf(
|
||||
NavigationModelItem.NavMenuItem(
|
||||
id = HOME,
|
||||
@@ -27,11 +24,4 @@ object NavigationModel {
|
||||
checked = false,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -50,14 +50,14 @@ sealed class NavigationModelItem {
|
||||
newItem: NavigationModelItem
|
||||
): Boolean {
|
||||
return when {
|
||||
oldItem is NavMenuItem && newItem is NavMenuItem ->
|
||||
oldItem.icon == newItem.icon &&
|
||||
oldItem.titleRes == newItem.titleRes &&
|
||||
oldItem.checked == newItem.checked
|
||||
oldItem is NavMenuItem && newItem is NavMenuItem ->
|
||||
oldItem.icon == newItem.icon &&
|
||||
oldItem.titleRes == newItem.titleRes &&
|
||||
oldItem.checked == newItem.checked
|
||||
oldItem is NavEmailFolder && newItem is NavEmailFolder ->
|
||||
StringDiffUtil.areContentsTheSame(oldItem.category, newItem.category)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.yogeshpaliyal.keypass.ui.nav
|
||||
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.yogeshpaliyal.keypass.databinding.NavDividerItemLayoutBinding
|
||||
@@ -11,7 +10,7 @@ sealed class NavigationViewHolder<T : NavigationModelItem>(
|
||||
view: View
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
abstract fun bind(navItem : T)
|
||||
abstract fun bind(navItem: T)
|
||||
|
||||
class NavMenuItemViewHolder(
|
||||
private val binding: NavMenuItemLayoutBinding,
|
||||
@@ -49,4 +48,4 @@ sealed class NavigationViewHolder<T : NavigationModelItem>(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.yogeshpaliyal.keypass.ui.settings
|
||||
|
||||
import android.R.attr.label
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
@@ -25,24 +24,23 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
private val CHOOSE_BACKUPS_LOCATION_REQUEST_CODE = 26212
|
||||
private val CHOOSE_RESTORE_FILE_REQUEST_CODE = 26213
|
||||
|
||||
@Inject
|
||||
lateinit var appDb : AppDatabase
|
||||
lateinit var appDb: AppDatabase
|
||||
|
||||
@Inject
|
||||
lateinit var sp : SharedPreferences
|
||||
lateinit var sp: SharedPreferences
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||
}
|
||||
|
||||
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
||||
when(preference?.key){
|
||||
when (preference?.key) {
|
||||
"feedback" -> {
|
||||
context?.email(getString(R.string.feedback_to_keypass), "yogeshpaliyal.foss@gmail.com")
|
||||
return true
|
||||
@@ -73,20 +71,20 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
return super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
|
||||
private fun selectBackupDirectory(){
|
||||
private fun selectBackupDirectory() {
|
||||
val selectedDirectory = Uri.parse(getBackupDirectory(sp))
|
||||
|
||||
context?.let {
|
||||
if(it.canUserAccessBackupDirectory(sp)){
|
||||
if (it.canUserAccessBackupDirectory(sp)) {
|
||||
backup(selectedDirectory)
|
||||
}else{
|
||||
} else {
|
||||
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
|
||||
intent.addFlags(
|
||||
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
)
|
||||
|
||||
try {
|
||||
@@ -96,30 +94,28 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun selectRestoreFile(){
|
||||
private fun selectRestoreFile() {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
intent.type = "*/*"
|
||||
|
||||
intent.addFlags(
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
)
|
||||
|
||||
try {
|
||||
startActivityForResult(intent, CHOOSE_RESTORE_FILE_REQUEST_CODE)
|
||||
}catch (e: Exception){
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == CHOOSE_BACKUPS_LOCATION_REQUEST_CODE && resultCode == Activity.RESULT_OK){
|
||||
if (requestCode == CHOOSE_BACKUPS_LOCATION_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
|
||||
val contentResolver = context?.contentResolver
|
||||
val selectedDirectory = data?.data
|
||||
if (contentResolver != null && selectedDirectory != null) {
|
||||
@@ -128,10 +124,10 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
|
||||
setBackupDirectory(sp,selectedDirectory.toString())
|
||||
setBackupDirectory(sp, selectedDirectory.toString())
|
||||
backup(selectedDirectory)
|
||||
}
|
||||
} else if (requestCode == CHOOSE_RESTORE_FILE_REQUEST_CODE && resultCode == Activity.RESULT_OK){
|
||||
} else if (requestCode == CHOOSE_RESTORE_FILE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
|
||||
val contentResolver = context?.contentResolver
|
||||
val selectedFile = data?.data
|
||||
if (contentResolver != null && selectedFile != null) {
|
||||
@@ -148,7 +144,7 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
"Restore"
|
||||
) { dialog, which ->
|
||||
lifecycleScope.launch {
|
||||
val result = appDb.restoreBackup(binding.etKeyPhrase.text.toString(),contentResolver, selectedFile)
|
||||
val result = appDb.restoreBackup(binding.etKeyPhrase.text.toString(), contentResolver, selectedFile)
|
||||
if (result) {
|
||||
dialog?.dismiss()
|
||||
Toast.makeText(
|
||||
@@ -156,7 +152,7 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
getString(R.string.backup_restored),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}else{
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
getString(R.string.invalid_keyphrase),
|
||||
@@ -165,13 +161,11 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun backup(selectedDirectory: Uri){
|
||||
fun backup(selectedDirectory: Uri) {
|
||||
|
||||
val keyPair = getOrCreateBackupKey(sp)
|
||||
|
||||
@@ -182,10 +176,11 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
|
||||
lifecycleScope.launch {
|
||||
context?.contentResolver?.let {
|
||||
appDb.createBackup(keyPair.second,
|
||||
it,
|
||||
tempFile?.uri
|
||||
)
|
||||
appDb.createBackup(
|
||||
keyPair.second,
|
||||
it,
|
||||
tempFile?.uri
|
||||
)
|
||||
if (keyPair.first) {
|
||||
val binding = LayoutBackupKeypharseBinding.inflate(layoutInflater)
|
||||
binding.txtCode.text = getOrCreateBackupKey(sp).second
|
||||
@@ -199,14 +194,13 @@ class MySettingsFragment : PreferenceFragmentCompat() {
|
||||
MaterialAlertDialogBuilder(requireContext()).setView(binding.root)
|
||||
.setPositiveButton(
|
||||
"Yes"
|
||||
) { dialog, which -> dialog?.dismiss()
|
||||
) { dialog, which ->
|
||||
dialog?.dismiss()
|
||||
}.show()
|
||||
}else{
|
||||
} else {
|
||||
Toast.makeText(context, getString(R.string.backup_completed), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,4 +132,4 @@ fun Float.normalize(
|
||||
|
||||
return outputMin * (1 - (this - inputMin) / (inputMax - inputMin)) +
|
||||
outputMax * ((this - inputMin) / (inputMax - inputMin))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Context
|
||||
import android.view.autofill.AutofillManager
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -12,9 +11,8 @@ import androidx.core.content.ContextCompat.getSystemService
|
||||
* created on 31-01-2021 15:27
|
||||
*/
|
||||
|
||||
|
||||
fun Context?.getAutoFillService() = if (this != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
getSystemService(this, AutofillManager::class.java)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun Context?.getAutoFillService() = if (this != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
getSystemService(this, AutofillManager::class.java)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import android.text.TextUtils
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import java.security.SecureRandom
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -21,21 +20,21 @@ fun getRandomString(sizeOfRandomString: Int): String {
|
||||
val random = SecureRandom()
|
||||
val sb = StringBuilder(sizeOfRandomString)
|
||||
for (i in 0 until sizeOfRandomString) sb.append(
|
||||
ALLOWED_CHARACTERS[random.nextInt(
|
||||
ALLOWED_CHARACTERS.length
|
||||
)]
|
||||
ALLOWED_CHARACTERS[
|
||||
random.nextInt(
|
||||
ALLOWED_CHARACTERS.length
|
||||
)
|
||||
]
|
||||
)
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
|
||||
fun Context.canUserAccessBackupDirectory(sp : SharedPreferences): Boolean {
|
||||
fun Context.canUserAccessBackupDirectory(sp: SharedPreferences): Boolean {
|
||||
val backupDirectoryUri = getUri(getBackupDirectory(sp)) ?: return false
|
||||
val backupDirectory = DocumentFile.fromTreeUri(this, backupDirectoryUri)
|
||||
return backupDirectory != null && backupDirectory.exists() && backupDirectory.canRead() && backupDirectory.canWrite()
|
||||
}
|
||||
|
||||
|
||||
private fun getUri(string: String?): Uri? {
|
||||
val uri = string
|
||||
return if (TextUtils.isEmpty(uri)) {
|
||||
|
||||
@@ -15,31 +15,29 @@
|
||||
|
||||
package com.yogeshpaliyal.keypass.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowInsets
|
||||
import android.widget.ImageView
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.databinding.BindingAdapter
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||
|
||||
@BindingAdapter(
|
||||
"popupElevationOverlay"
|
||||
)
|
||||
fun Spinner.bindPopupElevationOverlay(popupElevationOverlay: Float) {
|
||||
setPopupBackgroundDrawable(ColorDrawable(
|
||||
ElevationOverlayProvider(context)
|
||||
.compositeOverlayWithThemeSurfaceColorIfNeeded(popupElevationOverlay)
|
||||
))
|
||||
setPopupBackgroundDrawable(
|
||||
ColorDrawable(
|
||||
ElevationOverlayProvider(context)
|
||||
.compositeOverlayWithThemeSurfaceColorIfNeeded(popupElevationOverlay)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@BindingAdapter(
|
||||
@@ -67,8 +65,6 @@ fun TextView.bindDrawables(
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@BindingAdapter("goneIf")
|
||||
fun View.bindGoneIf(gone: Boolean) {
|
||||
visibility = if (gone) {
|
||||
@@ -219,4 +215,4 @@ fun View.requestApplyInsetsWhenAttached() {
|
||||
override fun onViewDetachedFromWindow(v: View) = Unit
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.yogeshpaliyal.keypass.utils
|
||||
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@@ -46,4 +45,4 @@ class ContentViewBindingDelegate<in R : AppCompatActivity, out T : ViewDataBindi
|
||||
|
||||
fun <R : AppCompatActivity, T : ViewDataBinding> contentView(
|
||||
@LayoutRes layoutRes: Int
|
||||
): ContentViewBindingDelegate<R, T> = ContentViewBindingDelegate(layoutRes)
|
||||
): ContentViewBindingDelegate<R, T> = ContentViewBindingDelegate(layoutRes)
|
||||
|
||||
@@ -67,4 +67,4 @@ fun Context.themeInterpolator(@AttrRes attr: Int): Interpolator {
|
||||
|
||||
fun Context.getDrawableOrNull(@DrawableRes id: Int?): Drawable? {
|
||||
return if (id == null || id == 0) null else AppCompatResources.getDrawable(this, id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.yogeshpaliyal.keypass.utils
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -11,11 +10,9 @@ import java.util.*
|
||||
* created on 23-03-2021 22:30
|
||||
*/
|
||||
|
||||
|
||||
|
||||
fun Long.formatCalendar(dateTimeFormat: String?): String? {
|
||||
val calendar: Calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = this
|
||||
val simpleDateFormat = SimpleDateFormat(dateTimeFormat, Locale.US)
|
||||
return simpleDateFormat.format(calendar.getTime())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -14,7 +13,6 @@ import android.net.Uri
|
||||
|
||||
@JvmName("IntentHelper")
|
||||
|
||||
|
||||
fun Context.email(
|
||||
chooserTitle: String,
|
||||
email: String = "",
|
||||
@@ -33,8 +31,7 @@ fun Context.email(
|
||||
if (text.isNotEmpty())
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text)
|
||||
|
||||
startActivity(Intent.createChooser(intent, chooserTitle))
|
||||
|
||||
startActivity(Intent.createChooser(intent, chooserTitle))
|
||||
}
|
||||
|
||||
fun Context.makeCall(chooserTitle: String, number: String): Boolean {
|
||||
@@ -49,7 +46,6 @@ fun Context.makeCall(chooserTitle: String, number: String): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Context.sendSMS(chooserTitle: String, number: String, text: String = ""): Boolean {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("sms:$number"))
|
||||
@@ -62,7 +58,6 @@ fun Context.sendSMS(chooserTitle: String, number: String, text: String = ""): Bo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Context.share(chooserTitle: String, text: String): Boolean {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
@@ -76,7 +71,6 @@ fun Context.share(chooserTitle: String, text: String): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Context.navigate(address: String) {
|
||||
val gmmIntentUri =
|
||||
Uri.parse("google.navigation:q=$address")
|
||||
@@ -86,4 +80,3 @@ fun Context.navigate(address: String) {
|
||||
startActivity(mapIntent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.yogeshpaliyal.keypass.utils
|
||||
import android.util.Log
|
||||
import com.yogeshpaliyal.keypass.BuildConfig
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -47,4 +46,4 @@ fun Any?.logV(tag: String?) {
|
||||
|
||||
fun Any?.logW(tag: String?) {
|
||||
if (BuildConfig.DEBUG) Log.w(tag, this.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.yogeshpaliyal.keypass.MyApplication
|
||||
|
||||
class MySharedPreferences(context : Context) {
|
||||
private val masterKeyAlias = MasterKey.Builder(MyApplication.instance).also {
|
||||
class MySharedPreferences(context: Context) {
|
||||
private val masterKeyAlias = MasterKey.Builder(MyApplication.instance).also {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||
// this is equivalent to using deprecated MasterKeys.AES256_GCM_SPEC
|
||||
|
||||
@@ -23,11 +23,10 @@ class MySharedPreferences(context : Context) {
|
||||
.build()
|
||||
it.setKeyGenParameterSpec(spec)
|
||||
}
|
||||
//it.setUserAuthenticationRequired(true)
|
||||
// it.setUserAuthenticationRequired(true)
|
||||
}
|
||||
.build()
|
||||
|
||||
|
||||
val sharedPref = EncryptedSharedPreferences.create(
|
||||
context,
|
||||
"secret_shared_prefs",
|
||||
@@ -35,4 +34,4 @@ class MySharedPreferences(context : Context) {
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,41 @@
|
||||
package com.yogeshpaliyal.keypass.utils
|
||||
|
||||
class PasswordGenerator(private var length: Int, private var includeUpperCaseLetters : Boolean,
|
||||
private var includeLowerCaseLetters : Boolean,
|
||||
private var includeSymbols : Boolean, private var includeNumbers: Boolean) {
|
||||
class PasswordGenerator(
|
||||
private var length: Int,
|
||||
private var includeUpperCaseLetters: Boolean,
|
||||
private var includeLowerCaseLetters: Boolean,
|
||||
private var includeSymbols: Boolean,
|
||||
private var includeNumbers: Boolean
|
||||
) {
|
||||
|
||||
constructor() : this(10,true, true, true, true)
|
||||
constructor() : this(10, true, true, true, true)
|
||||
|
||||
private val UPPER_CASE = 0
|
||||
private val LOWER_CASE = 1
|
||||
private val NUMBERS = 2
|
||||
private val SYMBOLS = 3
|
||||
|
||||
public fun generatePassword() : String {
|
||||
public fun generatePassword(): String {
|
||||
var password = ""
|
||||
val list = ArrayList<Int>()
|
||||
if(includeUpperCaseLetters)
|
||||
val list = ArrayList<Int>()
|
||||
if (includeUpperCaseLetters)
|
||||
list.add(UPPER_CASE)
|
||||
if(includeLowerCaseLetters)
|
||||
if (includeLowerCaseLetters)
|
||||
list.add(LOWER_CASE)
|
||||
if(includeNumbers)
|
||||
if (includeNumbers)
|
||||
list.add(NUMBERS)
|
||||
if(includeSymbols)
|
||||
if (includeSymbols)
|
||||
list.add(SYMBOLS)
|
||||
|
||||
for(i in 1..length){
|
||||
for (i in 1..length) {
|
||||
val choice = list.random()
|
||||
when(choice){
|
||||
when (choice) {
|
||||
UPPER_CASE -> password += ('A'..'Z').random().toString()
|
||||
LOWER_CASE -> password += ('a'..'z').random().toString()
|
||||
NUMBERS -> password += ('0'..'9').random().toString()
|
||||
SYMBOLS -> password += listOf('!','@','#','$','%','&','*','+','=','-','~','?','/','_').random().toString()
|
||||
SYMBOLS -> password += listOf('!', '@', '#', '$', '%', '&', '*', '+', '=', '-', '~', '?', '/', '_').random().toString()
|
||||
}
|
||||
}
|
||||
return password
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
package com.yogeshpaliyal.keypass.utils
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import androidx.core.content.edit
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.yogeshpaliyal.keypass.MyApplication
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
@@ -16,13 +10,12 @@ import com.yogeshpaliyal.keypass.MyApplication
|
||||
* created on 21-02-2021 11:18
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Pair
|
||||
* 1st => true if key is created now & false if key is created previously
|
||||
*
|
||||
*/
|
||||
fun getOrCreateBackupKey(sp: SharedPreferences,reset: Boolean = false): Pair<Boolean, String> {
|
||||
fun getOrCreateBackupKey(sp: SharedPreferences, reset: Boolean = false): Pair<Boolean, String> {
|
||||
|
||||
return if (sp.contains(BACKUP_KEY) && reset.not()) {
|
||||
Pair(false, sp.getString(BACKUP_KEY, "") ?: "")
|
||||
@@ -40,17 +33,15 @@ fun clearBackupKey(sp: SharedPreferences) {
|
||||
sp.edit {
|
||||
remove(BACKUP_KEY)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun setBackupDirectory(sp: SharedPreferences,string: String) {
|
||||
fun setBackupDirectory(sp: SharedPreferences, string: String) {
|
||||
sp.edit {
|
||||
putString(BACKUP_DIRECTORY, string)
|
||||
}
|
||||
}
|
||||
|
||||
fun setBackupTime(sp: SharedPreferences,time: Long) {
|
||||
fun setBackupTime(sp: SharedPreferences, time: Long) {
|
||||
sp.edit {
|
||||
putLong(BACKUP_DATE_TIME, time)
|
||||
}
|
||||
@@ -66,4 +57,4 @@ fun getBackupTime(sp: SharedPreferences,): Long {
|
||||
|
||||
private const val BACKUP_KEY = "backup_key"
|
||||
private const val BACKUP_DIRECTORY = "backup_directory"
|
||||
private const val BACKUP_DATE_TIME = "backup_date_time"
|
||||
private const val BACKUP_DATE_TIME = "backup_date_time"
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.yogeshpaliyal.keypass.utils
|
||||
|
||||
import java.util.*
|
||||
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
@@ -10,4 +9,4 @@ import java.util.*
|
||||
* created on 22-01-2021 23:14
|
||||
*/
|
||||
|
||||
fun getRandomString()= UUID.randomUUID().toString()
|
||||
fun getRandomString() = UUID.randomUUID().toString()
|
||||
|
||||
@@ -17,19 +17,8 @@
|
||||
package com.yogeshpaliyal.keypass.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Bitmap.Config.ARGB_8888
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.Px
|
||||
import androidx.core.graphics.applyCanvas
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.forEach
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun TextView.setTextAppearanceCompat(context: Context, resId: Int) {
|
||||
|
||||
@@ -32,4 +32,3 @@ fun <T : ViewModel> ViewModelStoreOwner.initViewModel(viewModel: Class<T>): T =
|
||||
this,
|
||||
ViewModelFactory()
|
||||
).get(viewModel)
|
||||
|
||||
|
||||
62
app/src/main/res/values-zh-rCN/strings.xml
Normal file
62
app/src/main/res/values-zh-rCN/strings.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<resources>
|
||||
|
||||
|
||||
<string name="generate_password">生成密码</string>
|
||||
<string name="home">主页</string>
|
||||
<string name="delete">删除</string>
|
||||
|
||||
|
||||
<string name="generate_shortcut_short_label">生成密码</string>
|
||||
|
||||
<string name="backup_restored">备份密码</string>
|
||||
<string name="invalid_keyphrase">无效密码</string>
|
||||
|
||||
<string name="backup_completed">备份完成</string>
|
||||
|
||||
<!-- Sync Preferences -->
|
||||
<string name="credentials_backups">备份</string>
|
||||
<string name="credentials_backups_desc">把密码备份到外部存储</string>
|
||||
<string name="restore_credentials">恢复备份</string>
|
||||
<string name="restore_credentials_desc">从备份中恢复</string>
|
||||
<string name="send_feedback">发送反馈</string>
|
||||
<string name="send_feedback_desc">报告技术问题或建议新功能</string>
|
||||
<string name="share">分享</string>
|
||||
<string name="share_desc">向别人分享该应用</string>
|
||||
<string name="password_length">密码长度</string>
|
||||
<string name="password">密码</string>
|
||||
<string name="uppercase_alphabets">大写字母</string>
|
||||
<string name="lowercase_alphabets">小写字母</string>
|
||||
<string name="symbols">标点符号</string>
|
||||
<string name="numbers">数字</string>
|
||||
<string name="copied_to_clipboard">已复制到剪切板</string>
|
||||
<string name="login_to_enter_keypass">输入密码以进入 KeyPass</string>
|
||||
<string name="authentication_failed">身份认证失败</string>
|
||||
|
||||
<string name="last_backup_date">上次备份: %s</string>
|
||||
<string name="coming_soon">敬请期待</string>
|
||||
<string name="delete_account_title">您确定吗?</string>
|
||||
<string name="delete_account_msg">您确定要删除本条目吗?此操作不可撤销。</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="feedback_to_keypass">向 KeyPass 发送反馈</string>
|
||||
<string name="share_keypass">分享 KeyPass</string>
|
||||
<string name="message_no_accounts">这里空空如也。按下下方的加号以新建。</string>
|
||||
<string name="turn_off_backup">关闭备份</string>
|
||||
<string name="verify_keyphrase">验证备份密码</string>
|
||||
<string name="verify_keyphrase_message">测试备份密码并验证其匹配</string>
|
||||
<string name="backup_folder">备份文件夹</string>
|
||||
<string name="backup">备份</string>
|
||||
<string name="turn_on_backup">开启备份</string>
|
||||
<string name="backup_desc">备份使用密码加密并存储在您的设备上</string>
|
||||
<string name="yes">确定</string>
|
||||
<string name="create_backup">创建备份</string>
|
||||
<string name="alert">警告</string>
|
||||
<string name="copy_keypharse_msg">请立即复制或在纸上写下下面的密码。KeyPass 将不会再次显示该密码。</string>
|
||||
<string name="help">帮助</string>
|
||||
<string name="security">安全</string>
|
||||
<string name="search">搜索</string>
|
||||
<string name="account_name">账户名称</string>
|
||||
<string name="username_email_phone">用户名/邮箱/手机号</string>
|
||||
<string name="tags_comma_separated_optional">标签(选填)</string>
|
||||
<string name="website_url_optional">网站(选填)</string>
|
||||
<string name="notes_optional">附注(选填)</string>
|
||||
</resources>
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.yogeshpaliyal.keypass
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
@@ -14,4 +13,4 @@ class ExampleUnitTest {
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
build.gradle
38
build.gradle
@@ -2,22 +2,21 @@
|
||||
buildscript {
|
||||
|
||||
ext{
|
||||
kotlin_version = "1.4.21"
|
||||
kotlin_version = "1.5.30"
|
||||
lifecycle_version = "2.3.1"
|
||||
room_version = "2.3.0"
|
||||
navigation_version = '2.3.5'
|
||||
ext.hilt_version = '2.35'
|
||||
ext.hilt_version = '2.38.1'
|
||||
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url "https://maven.localazy.com/repository/release/" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:4.1.3"
|
||||
classpath 'com.android.tools.build:gradle:7.0.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'com.google.gms:google-services:4.3.8'
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version"
|
||||
|
||||
|
||||
@@ -27,6 +26,9 @@ buildscript {
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id 'com.diffplug.spotless' version '5.10.2'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
@@ -37,6 +39,30 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
/*task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
subprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
apply plugin: 'com.diffplug.spotless'
|
||||
spotless {
|
||||
kotlin {
|
||||
target '**/*.kt'
|
||||
targetExclude("$buildDir/**/*.kt")
|
||||
targetExclude('bin/**/*.kt')
|
||||
|
||||
java.util.HashMap<String, String> map = new HashMap<>();
|
||||
map.put("disabled_rules","no-wildcard-imports")
|
||||
ktlint("0.40.0").userData(map)
|
||||
// licenseHeaderFile rootProject.file('spotless/copyright.kt')
|
||||
}
|
||||
}
|
||||
}
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Sat May 22 13:20:40 IST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
Reference in New Issue
Block a user