code formatter added

This commit is contained in:
Yogesh Paliyal
2021-03-01 21:24:02 +05:30
parent 41e8d79c48
commit cbc039df8b
48 changed files with 283 additions and 409 deletions

View File

@@ -3,6 +3,7 @@ plugins {
id 'kotlin-android'
id 'kotlin-kapt'
id 'androidx.navigation.safeargs.kotlin'
// id("com.diffplug.spotless") version "5.10.2"
}

Binary file not shown.

View 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"
}
]
}

View File

@@ -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)
}
}
}

View File

@@ -3,12 +3,10 @@ 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
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -31,10 +29,8 @@ abstract class AppDatabase : RoomDatabase() {
fun getInstance(): AppDatabase {
if (!this::_instance.isInitialized)
synchronized(this) {
_instance = Room.databaseBuilder(
MyApplication.instance,
AppDatabase::class.java,
@@ -48,7 +44,6 @@ abstract class AppDatabase : RoomDatabase() {
super.onDestructiveMigration(db)
onCreate(db)
}
})
/* .addMigrations(object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
@@ -64,10 +59,7 @@ abstract class AppDatabase : RoomDatabase() {
.build()
}
return _instance
}
}
}
}

View File

@@ -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
)

View File

@@ -2,7 +2,6 @@ package com.yogeshpaliyal.keypass
import android.app.Application
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -11,14 +10,12 @@ import android.app.Application
*/
class MyApplication : Application() {
companion object{
companion object {
lateinit var instance: MyApplication
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
}

View File

@@ -44,4 +44,4 @@ class MaskedCardView @JvmOverloads constructor(
pathProvider.calculatePath(shapeAppearance, 1f, rectF, path)
super.onSizeChanged(w, h, oldw, oldh)
}
}
}

View File

@@ -5,7 +5,6 @@ import androidx.room.Entity
import androidx.room.PrimaryKey
import com.yogeshpaliyal.universal_adapter.model.BaseDiffUtil
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -31,7 +30,7 @@ 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

View File

@@ -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>
)

View File

@@ -7,7 +7,6 @@ import androidx.room.Query
import com.yogeshpaliyal.keypass.data.AccountModel
import kotlinx.coroutines.flow.Flow
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -24,21 +23,18 @@ abstract class DbDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertOrUpdateAccount(accountModel: List<AccountModel>)
@Query("SELECT * from account")
abstract fun getAllAccounts() : Flow<List<AccountModel>>
abstract fun getAllAccounts(): Flow<List<AccountModel>>
@Query("SELECT * from account where tags = :tag")
abstract fun getAllAccounts(tag: String) : Flow<List<AccountModel>>
abstract fun getAllAccounts(tag: String): Flow<List<AccountModel>>
@Query("SELECT * from account where id = :id")
abstract fun getAccount(id: Long?) : AccountModel?
abstract fun getAccount(id: Long?): AccountModel?
@Query("SELECT DISTINCT tags from account")
abstract fun getTags() : Flow<List<String>>
abstract fun getTags(): Flow<List<String>>
@Query("DELETE from account where id = :id")
abstract fun deleteAccount(id: Long?)
}
}

View File

@@ -1,6 +1,5 @@
package com.yogeshpaliyal.keypass.db_helper
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com

View File

@@ -2,23 +2,13 @@ package com.yogeshpaliyal.keypass.db_helper
import android.content.ContentResolver
import android.net.Uri
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import androidx.room.withTransaction
import com.google.gson.Gson
import com.yogeshpaliyal.keypass.AppDatabase
import com.yogeshpaliyal.keypass.data.AccountModel
import com.yogeshpaliyal.keypass.data.BackupData
import com.yogeshpaliyal.keypass.utils.getOrCreateBackupKey
import com.yogeshpaliyal.keypass.utils.logD
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext
import java.io.File
import java.io.OutputStream
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
/*
* @author Yogesh Paliyal
@@ -27,24 +17,23 @@ import javax.crypto.SecretKey
* created on 20-02-2021 19:31
*/
suspend fun AppDatabase.createBackup(key: String,contentResolver : ContentResolver,fileUri: Uri?) = withContext(Dispatchers.IO){
fileUri ?: return@withContext false
suspend fun AppDatabase.createBackup(key: String, contentResolver: ContentResolver, fileUri: Uri?) = withContext(Dispatchers.IO) {
fileUri ?: return@withContext false
val data = getDao().getAllAccounts().first()
val json = Gson().toJson(BackupData(this@createBackup.openHelper.readableDatabase.version, data))
val fileStream = contentResolver.openOutputStream(fileUri)
EncryptionHelper.doCryptoEncrypt(key,json, fileStream)
EncryptionHelper.doCryptoEncrypt(key, json, fileStream)
return@withContext true
}
suspend fun AppDatabase.restoreBackup(key: String,contentResolver : ContentResolver,fileUri: Uri?) = withContext(Dispatchers.IO){
suspend fun AppDatabase.restoreBackup(key: String, contentResolver: ContentResolver, fileUri: Uri?) = withContext(Dispatchers.IO) {
fileUri ?: return@withContext false
val restoredFile = try {
EncryptionHelper.doCryptoDecrypt(key, contentResolver.openInputStream(fileUri))
}catch (e:Exception){
val restoredFile = try {
EncryptionHelper.doCryptoDecrypt(key, contentResolver.openInputStream(fileUri))
} catch (e: Exception) {
e.printStackTrace()
return@withContext false
}
@@ -57,4 +46,3 @@ suspend fun AppDatabase.restoreBackup(key: String,contentResolver : ContentResol
}
return@withContext true
}

View File

@@ -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")
}
}
}

View File

@@ -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)
}
}

View File

@@ -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
}
}
}
}

View File

@@ -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) {
}
}
}

View File

@@ -11,24 +11,22 @@ import com.yogeshpaliyal.keypass.databinding.ActivityAuthenticationBinding
import com.yogeshpaliyal.keypass.ui.nav.DashboardActivity
import java.util.concurrent.Executor
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,
@@ -40,7 +38,7 @@ class AuthenticationActivity : AppCompatActivity() {
"Authentication error: $errString", Toast.LENGTH_SHORT
)
.show()
// finish()
// finish()
}
override fun onAuthenticationSucceeded(
@@ -59,8 +57,8 @@ class AuthenticationActivity : AppCompatActivity() {
)
.show()
}
})
}
)
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(getString(R.string.app_name))
@@ -76,16 +74,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()
}
}
}

View File

@@ -8,7 +8,6 @@ import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.yogeshpaliyal.keypass.AppDatabase
import com.yogeshpaliyal.keypass.R
@@ -18,7 +17,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -26,17 +24,16 @@ import kotlinx.coroutines.withContext
* created on 31-01-2021 10:38
*/
class DetailActivity : AppCompatActivity() {
lateinit var binding : FragmentDetailBinding
lateinit var binding: FragmentDetailBinding
companion object{
companion object {
private const val ARG_ACCOUNT_ID = "ARG_ACCOUNT_ID"
@JvmStatic
fun start(context: Context?, accountId: Long? = null) {
val starter = Intent(context, DetailActivity::class.java)
.putExtra(ARG_ACCOUNT_ID,accountId)
.putExtra(ARG_ACCOUNT_ID, accountId)
context?.startActivity(starter)
}
}
@@ -45,7 +42,6 @@ class DetailActivity : AppCompatActivity() {
initViewModel(DetailViewModel::class.java)
}
private val accountId by lazy {
intent?.extras?.getLong(ARG_ACCOUNT_ID) ?: -1
}
@@ -57,9 +53,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)
@@ -68,7 +67,7 @@ class DetailActivity : AppCompatActivity() {
onBackPressed()
}
binding.bottomAppBar.setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_delete){
if (item.itemId == R.id.action_delete) {
deleteAccount()
return@setOnMenuItemClickListener true
}
@@ -93,7 +92,8 @@ class DetailActivity : AppCompatActivity() {
MaterialAlertDialogBuilder(this)
.setTitle("Are you sure?")
.setMessage("Do you really want to delete this entry, it can't be restored")
.setPositiveButton("Delete"
.setPositiveButton(
"Delete"
) { dialog, which ->
dialog?.dismiss()
lifecycleScope.launch(Dispatchers.IO) {
@@ -105,10 +105,9 @@ class DetailActivity : AppCompatActivity() {
}
}
}
.setNegativeButton("Cancel"){dialog, which ->
.setNegativeButton("Cancel") { dialog, which ->
dialog.dismiss()
}.show()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@@ -120,4 +119,4 @@ class DetailActivity : AppCompatActivity() {
return super.onOptionsItemSelected(item)
}
}
}

View File

@@ -9,7 +9,6 @@ import com.yogeshpaliyal.keypass.data.AccountModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -27,8 +26,5 @@ class DetailViewModel(application: Application) : AndroidViewModel(application)
AppDatabase.getInstance().getDao().getAccount(accountId) ?: AccountModel()
)
}
}
}
}

View File

@@ -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
@@ -10,9 +9,8 @@ import androidx.core.content.getSystemService
import com.yogeshpaliyal.keypass.databinding.ActivityGeneratePasswordBinding
import com.yogeshpaliyal.keypass.utils.PasswordGenerator
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)
@@ -25,15 +23,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, "Copied to clipboard", Toast.LENGTH_SHORT).show()
}
}
private fun generatePassword(){
private fun generatePassword() {
val password = PasswordGenerator(
10, binding.cbCapAlphabets.isChecked,
binding.cbLowerAlphabets.isChecked,
@@ -43,4 +40,4 @@ class GeneratePasswordActivity : AppCompatActivity() {
binding.etPassword.setText(password)
}
}
}

View File

@@ -6,16 +6,13 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.data.AccountModel
import com.yogeshpaliyal.keypass.databinding.FragmentHomeBinding
import com.yogeshpaliyal.keypass.db_helper.EncryptionHelper
import com.yogeshpaliyal.keypass.listener.UniversalClickListener
import com.yogeshpaliyal.keypass.ui.detail.DetailActivity
import com.yogeshpaliyal.keypass.utils.initViewModel
import com.yogeshpaliyal.keypass.utils.logD
import com.yogeshpaliyal.universal_adapter.adapter.UniversalAdapterViewType
import com.yogeshpaliyal.universal_adapter.adapter.UniversalRecyclerAdapter
import com.yogeshpaliyal.universal_adapter.utils.Resource
@@ -25,7 +22,6 @@ import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -33,7 +29,7 @@ import kotlinx.coroutines.withContext
* created on 31-01-2021 09:25
*/
class HomeFragment : Fragment() {
private lateinit var binding : FragmentHomeBinding
private lateinit var binding: FragmentHomeBinding
private val mViewModel by lazy {
initViewModel(HomeViewModel::class.java)
@@ -41,16 +37,17 @@ class HomeFragment : Fragment() {
private val args: HomeFragmentArgs by navArgs()
private val mAdapter by lazy {
val adapterOptions = UniversalAdapterOptions<AccountModel>(this,
content = UniversalAdapterViewType.Content(R.layout.item_accounts,mListener = mListener),
noData = UniversalAdapterViewType.NoData(R.layout.layout_no_accounts))
val adapterOptions = UniversalAdapterOptions<AccountModel>(
this,
content = UniversalAdapterViewType.Content(R.layout.item_accounts, mListener = mListener),
noData = UniversalAdapterViewType.NoData(R.layout.layout_no_accounts)
)
UniversalRecyclerAdapter<AccountModel>(adapterOptions)
}
val mListener = object : UniversalClickListener<AccountModel>{
val mListener = object : UniversalClickListener<AccountModel> {
override fun onItemClick(view: View, model: AccountModel) {
DetailActivity.start(context, model.id)
}
@@ -61,7 +58,7 @@ class HomeFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentHomeBinding.inflate(layoutInflater,container,false)
binding = FragmentHomeBinding.inflate(layoutInflater, container, false)
return binding.root
}
@@ -69,16 +66,12 @@ class HomeFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.adapter = mAdapter
lifecycleScope.launch(Dispatchers.IO){
lifecycleScope.launch(Dispatchers.IO) {
mViewModel.loadData(args.tag).collect {
withContext(Dispatchers.Main) {
mAdapter.updateData(Resource.success(ArrayList(it)))
}
}
}
}
}
}

View File

@@ -2,14 +2,7 @@ package com.yogeshpaliyal.keypass.ui.home
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.yogeshpaliyal.keypass.AppDatabase
import com.yogeshpaliyal.keypass.data.AccountModel
import com.yogeshpaliyal.universal_adapter.utils.Resource
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
/*
* @author Yogesh Paliyal
@@ -19,12 +12,9 @@ import kotlinx.coroutines.launch
*/
class HomeViewModel(application: Application) : AndroidViewModel(application) {
private val dao by lazy {
AppDatabase.getInstance().getDao()
}
suspend fun loadData(tag : String?)= if (tag.isNullOrBlank())dao.getAllAccounts() else dao.getAllAccounts(tag)
}
suspend fun loadData(tag: String?) = if (tag.isNullOrBlank())dao.getAllAccounts() else dao.getAllAccounts(tag)
}

View File

@@ -21,7 +21,6 @@ import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.databinding.FragmentBottomNavDrawerBinding
import com.yogeshpaliyal.keypass.utils.initViewModel
import com.yogeshpaliyal.keypass.utils.themeColor
import kotlin.LazyThreadSafetyMode.NONE
/**
@@ -31,8 +30,6 @@ class BottomNavDrawerFragment :
Fragment(),
NavigationAdapter.NavigationAdapterListener {
private lateinit var binding: FragmentBottomNavDrawerBinding
private val behavior: BottomSheetBehavior<FrameLayout> by lazy(NONE) {
@@ -45,11 +42,8 @@ class BottomNavDrawerFragment :
private val bottomSheetCallback = BottomNavigationDrawerCallback()
private val navigationListeners: MutableList<NavigationAdapter.NavigationAdapterListener> =
mutableListOf()
mutableListOf()
private val foregroundShapeDrawable: MaterialShapeDrawable by lazy(NONE) {
val foregroundContext = binding.foregroundContainer.context
@@ -78,7 +72,6 @@ class BottomNavDrawerFragment :
}
}
private val closeDrawerOnBackPressed = object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
close()
@@ -111,7 +104,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() }
@@ -130,7 +123,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.
@@ -141,8 +133,6 @@ class BottomNavDrawerFragment :
})
}
behavior.addBottomSheetCallback(bottomSheetCallback)
behavior.state = STATE_HIDDEN
@@ -153,11 +143,9 @@ class BottomNavDrawerFragment :
adapter.submitList(it)
}
mViewModel.setNavigationMenuItemChecked(0)
}
}
fun open() {
behavior.state = STATE_HALF_EXPANDED
}
@@ -178,8 +166,6 @@ class BottomNavDrawerFragment :
navigationListeners.add(listener)
}
override fun onNavMenuItemClicked(item: NavigationModelItem.NavMenuItem) {
mViewModel.setNavigationMenuItemChecked(item.id)
close()
@@ -190,15 +176,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()
}
}
}
}

View File

@@ -9,7 +9,6 @@ import com.yogeshpaliyal.keypass.AppDatabase
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -20,13 +19,13 @@ class BottomNavViewModel(application: Application) : AndroidViewModel(applicatio
private val _navigationList: MutableLiveData<List<NavigationModelItem>> = MutableLiveData()
private val tagsDb = AppDatabase.getInstance().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 {
@@ -36,8 +35,6 @@ class BottomNavViewModel(application: Application) : AndroidViewModel(applicatio
}
}
/**
* Set the currently selected menu item.
*
@@ -56,18 +53,13 @@ class BottomNavViewModel(application: Application) : AndroidViewModel(applicatio
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
}
}
}

View File

@@ -97,4 +97,4 @@ class BottomNavigationDrawerCallback : BottomSheetBehavior.BottomSheetCallback()
fun removeOnStateChangedAction(action: OnStateChangedAction): Boolean {
return onStateChangedActions.remove(action)
}
}
}

View File

@@ -11,30 +11,24 @@ import androidx.annotation.MenuRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.findNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.transition.MaterialElevationScale
import com.yogeshpaliyal.keypass.AppDatabase
import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.databinding.ActivityDashboardBinding
import com.yogeshpaliyal.keypass.ui.detail.DetailActivity
import com.yogeshpaliyal.keypass.ui.generate.GeneratePasswordActivity
import com.yogeshpaliyal.keypass.ui.home.HomeFragmentDirections
import com.yogeshpaliyal.keypass.ui.settings.MySettingsFragmentDirections
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
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
}
@@ -47,22 +41,19 @@ class DashboardActivity : AppCompatActivity(),
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
binding = ActivityDashboardBinding.inflate(layoutInflater)
setContentView(binding.root)
//setSupportActionBar(binding.bottomAppBar)
// setSupportActionBar(binding.bottomAppBar)
findNavController(R.id.nav_host_fragment).addOnDestinationChangedListener(
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()) {
@@ -72,7 +63,6 @@ class DashboardActivity : AppCompatActivity(),
}
}*/
binding.btnAdd.setOnClickListener {
currentNavigationFragment?.apply {
exitTransition = MaterialElevationScale(false).apply {
@@ -83,25 +73,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)
@@ -114,8 +105,6 @@ class DashboardActivity : AppCompatActivity(),
}
setOnMenuItemClickListener(this@DashboardActivity)
}
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
@@ -129,8 +118,6 @@ class DashboardActivity : AppCompatActivity(),
return true
}
override fun onDestinationChanged(
controller: NavController,
destination: NavDestination,
@@ -146,8 +133,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)
@@ -165,7 +152,6 @@ class DashboardActivity : AppCompatActivity(),
bottomNavDrawer.close()
}
private fun hideBottomAppBar() {
binding.run {
bottomAppBar.performHide()
@@ -202,21 +188,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()
}
}
}
}

View File

@@ -86,4 +86,4 @@ class NavigationAdapter(
) {
holder.bind(getItem(position))
}
}
}

View File

@@ -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,
)
)
}

View File

@@ -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
}
}
}
}
}

View File

@@ -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>(
}
}
}
}
}

View File

@@ -1,10 +1,8 @@
package com.yogeshpaliyal.keypass.ui.settings
import android.R.attr.label
import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@@ -25,7 +23,6 @@ import com.yogeshpaliyal.keypass.db_helper.restoreBackup
import com.yogeshpaliyal.keypass.utils.*
import kotlinx.coroutines.launch
class MySettingsFragment : PreferenceFragmentCompat() {
private val CHOOSE_BACKUPS_LOCATION_REQUEST_CODE = 26212
private val CHOOSE_RESTORE_FILE_REQUEST_CODE = 26213
@@ -35,7 +32,7 @@ class MySettingsFragment : PreferenceFragmentCompat() {
}
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
when(preference?.key){
when (preference?.key) {
"feedback" -> {
context?.email("Feedback to KeyPass", "techpaliyal@gmail.com")
return true
@@ -66,19 +63,19 @@ class MySettingsFragment : PreferenceFragmentCompat() {
return super.onPreferenceTreeClick(preference)
}
private fun selectBackupDirectory(){
private fun selectBackupDirectory() {
val selectedDirectory = Uri.parse(getBackupDirectory())
context?.let {
if(it.canUserAccessBackupDirectory()){
if (it.canUserAccessBackupDirectory()) {
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 {
@@ -88,30 +85,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) {
@@ -123,7 +118,7 @@ class MySettingsFragment : PreferenceFragmentCompat() {
setBackupDirectory(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) {
@@ -140,7 +135,7 @@ class MySettingsFragment : PreferenceFragmentCompat() {
"Restore"
) { dialog, which ->
lifecycleScope.launch {
val result = AppDatabase.getInstance().restoreBackup(binding.etKeyPhrase.text.toString(),contentResolver, selectedFile)
val result = AppDatabase.getInstance().restoreBackup(binding.etKeyPhrase.text.toString(), contentResolver, selectedFile)
if (result) {
dialog?.dismiss()
Toast.makeText(
@@ -148,7 +143,7 @@ class MySettingsFragment : PreferenceFragmentCompat() {
getString(R.string.backup_restored),
Toast.LENGTH_SHORT
).show()
}else{
} else {
Toast.makeText(
context,
getString(R.string.invalid_keyphrase),
@@ -157,13 +152,11 @@ class MySettingsFragment : PreferenceFragmentCompat() {
}
}
}.show()
}
}
}
fun backup(selectedDirectory: Uri){
fun backup(selectedDirectory: Uri) {
val keyPair = getOrCreateBackupKey()
@@ -174,10 +167,11 @@ class MySettingsFragment : PreferenceFragmentCompat() {
lifecycleScope.launch {
context?.contentResolver?.let {
AppDatabase.getInstance().createBackup(keyPair.second,
it,
tempFile?.uri
)
AppDatabase.getInstance().createBackup(
keyPair.second,
it,
tempFile?.uri
)
if (keyPair.first) {
val binding = LayoutBackupKeypharseBinding.inflate(layoutInflater)
binding.txtCode.text = getOrCreateBackupKey().second
@@ -191,14 +185,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()
}
}
}
}
}
}

View File

@@ -1,7 +1,7 @@
package com.yogeshpaliyal.keypass.ui.settings_activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.yogeshpaliyal.keypass.R
class SettingsActivity : AppCompatActivity() {
@@ -9,4 +9,4 @@ class SettingsActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
}
}
}

View File

@@ -132,4 +132,4 @@ fun Float.normalize(
return outputMin * (1 - (this - inputMin) / (inputMax - inputMin)) +
outputMax * ((this - inputMin) / (inputMax - inputMin))
}
}

View File

@@ -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
}

View File

@@ -6,7 +6,6 @@ import android.text.TextUtils
import androidx.documentfile.provider.DocumentFile
import java.security.SecureRandom
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -20,21 +19,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(): Boolean {
val backupDirectoryUri = getUri(getBackupDirectory()) ?: 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)) {

View File

@@ -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
})
}
}
}

View File

@@ -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)

View File

@@ -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)
}
}

View File

@@ -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 = "",
@@ -38,7 +36,6 @@ fun Context.email(
return true
}
return false
}
fun Context.makeCall(chooserTitle: String, number: String): Boolean {
@@ -53,7 +50,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"))
@@ -66,7 +62,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)
@@ -80,7 +75,6 @@ fun Context.share(chooserTitle: String, text: String): Boolean {
}
}
fun Context.navigate(address: String) {
val gmmIntentUri =
Uri.parse("google.navigation:q=$address")
@@ -90,4 +84,3 @@ fun Context.navigate(address: String) {
startActivity(mapIntent)
}
}

View File

@@ -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())
}
}

View File

@@ -1,35 +1,39 @@
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
) {
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
}
}
}

View File

@@ -9,7 +9,6 @@ import androidx.security.crypto.MasterKey
import com.yogeshpaliyal.keypass.MyApplication
import java.util.*
/*
* @author Yogesh Paliyal
* techpaliyal@gmail.com
@@ -17,27 +16,28 @@ import java.util.*
* created on 21-02-2021 11:18
*/
fun getSharedPreferences() : SharedPreferences{
fun getSharedPreferences(): SharedPreferences {
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
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
// this is equivalent to using deprecated MasterKeys.AES256_GCM_SPEC
// this is equivalent to using deprecated MasterKeys.AES256_GCM_SPEC
val spec = KeyGenParameterSpec.Builder(
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
it.setKeyGenParameterSpec(spec)
}
//it.setUserAuthenticationRequired(true)
// this is equivalent to using deprecated MasterKeys.AES256_GCM_SPEC
val spec = KeyGenParameterSpec.Builder(
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
it.setKeyGenParameterSpec(spec)
}
// it.setUserAuthenticationRequired(true)
}
.build()
return EncryptedSharedPreferences.create(MyApplication.instance,
return EncryptedSharedPreferences.create(
MyApplication.instance,
"secret_shared_prefs",
masterKeyAlias,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
@@ -45,38 +45,35 @@ fun getSharedPreferences() : SharedPreferences{
)
}
/**
* Pair
* 1st => true if key is created now & false if key is created previously
*
*/
fun getOrCreateBackupKey(reset: Boolean = false): Pair<Boolean,String>{
fun getOrCreateBackupKey(reset: Boolean = false): Pair<Boolean, String> {
val sp = getSharedPreferences()
return if (sp.contains(BACKUP_KEY) && reset.not()){
Pair(false,sp.getString(BACKUP_KEY,"") ?: "")
}else{
return if (sp.contains(BACKUP_KEY) && reset.not()) {
Pair(false, sp.getString(BACKUP_KEY, "") ?: "")
} else {
val randomKey = getRandomString(16)
sp.edit {
putString(BACKUP_KEY, randomKey)
}
Pair(true,randomKey)
Pair(true, randomKey)
}
}
fun setBackupDirectory(string: String){
fun setBackupDirectory(string: String) {
getSharedPreferences().edit {
putString(BACKUP_DIRECTORY, string)
}
}
fun getBackupDirectory(): String{
fun getBackupDirectory(): String {
val sp = getSharedPreferences()
return sp.getString(BACKUP_DIRECTORY,"") ?: ""
return sp.getString(BACKUP_DIRECTORY, "") ?: ""
}
private const val BACKUP_KEY = "backup_key"
private const val BACKUP_DIRECTORY = "backup_directory"
private const val BACKUP_DIRECTORY = "backup_directory"

View File

@@ -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()

View File

@@ -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) {

View File

@@ -32,4 +32,3 @@ fun <T : ViewModel> ViewModelStoreOwner.initViewModel(viewModel: Class<T>): T =
this,
ViewModelFactory()
).get(viewModel)

View File

@@ -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)
}
}
}

View File

@@ -21,6 +21,9 @@ buildscript {
// in the individual module build.gradle files
}
}
plugins {
id 'com.diffplug.spotless' version '5.10.2'
}
allprojects {
repositories {
@@ -31,6 +34,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')
}
}
}