diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
index 8199eb17..9c508e65 100644
--- a/.idea/deploymentTargetDropDown.xml
+++ b/.idea/deploymentTargetDropDown.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5f96a01c..b6d553fd 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -44,6 +44,7 @@ android {
buildFeatures {
viewBinding = true
compose = true
+ buildConfig = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.4"
@@ -145,10 +146,15 @@ dependencies {
// Compose-lint
lintChecks("com.slack.lint.compose:compose-lint-checks:1.3.1")
+ // Timber
+ implementation ("com.jakewharton.timber:timber:5.0.1")
+
//kotlinx.collections.immutable
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7")
// Circular Progress bar
implementation ("com.mikhaellopez:circularprogressbar:3.1.0")
+ // Coil
+ implementation("io.coil-kt:coil-compose:2.6.0")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5fa82ccf..174a6e3f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,7 +32,7 @@
android:theme="@style/Theme.UnCrack"/>
@@ -43,7 +43,17 @@
+
+
+
+
+
+
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/components/AccountOption.kt b/app/src/main/java/com/geekymusketeers/uncrack/components/AccountOption.kt
new file mode 100644
index 00000000..698fa90f
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/components/AccountOption.kt
@@ -0,0 +1,61 @@
+package com.geekymusketeers.uncrack.components
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import coil.compose.AsyncImage
+import coil.request.ImageRequest
+import com.geekymusketeers.uncrack.presentation.account.AccountItems
+import com.geekymusketeers.uncrack.ui.theme.OnSurfaceLight
+import com.geekymusketeers.uncrack.ui.theme.normal16
+
+@Composable
+fun AccountOption(
+ accountItem: AccountItems,
+ modifier: Modifier = Modifier,
+ onClick: (AccountItems) -> Unit
+) {
+
+ val context = LocalContext.current
+
+ Row(
+ modifier = modifier
+ .fillMaxWidth()
+ .clickable { onClick(accountItem) }
+ .padding(16.dp),
+ horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.Start),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+
+ AsyncImage(
+ model = ImageRequest.Builder(context)
+ .data(accountItem.icon)
+ .size(coil.size.Size.ORIGINAL)
+ .build(), contentDescription = null,
+ modifier = Modifier.size(24.dp)
+ )
+
+ Text(
+ text = accountItem.itemsName,
+ style = normal16.copy(color = OnSurfaceLight)
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun SettingsItemPreview() {
+ AccountOption(AccountItems.BIOMETRIC) {
+ // Do something
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/components/OnboardingComponent.kt b/app/src/main/java/com/geekymusketeers/uncrack/components/OnboardingComponent.kt
index 64e104f0..42ed4537 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/components/OnboardingComponent.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/components/OnboardingComponent.kt
@@ -1,7 +1,7 @@
package com.geekymusketeers.uncrack.components
import androidx.compose.runtime.Composable
-import com.geekymusketeers.uncrack.presentation.introScreens.model.OnBoardingItem
+import com.geekymusketeers.uncrack.presentation.intro.model.OnBoardingItem
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/components/ProfileContainer.kt b/app/src/main/java/com/geekymusketeers/uncrack/components/ProfileContainer.kt
new file mode 100644
index 00000000..202590aa
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/components/ProfileContainer.kt
@@ -0,0 +1,48 @@
+package com.geekymusketeers.uncrack.components
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Add
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import com.geekymusketeers.uncrack.R
+
+@Composable
+fun ProfileContainer(
+ modifier: Modifier = Modifier,
+ onEditButtonClick: () -> Unit
+) {
+ Box(contentAlignment = Alignment.BottomEnd) {
+ Image(
+ painter = painterResource(id = R.drawable.no_user_profile_picture),
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = modifier
+ .size(120.dp)
+ .clip(CircleShape)
+ )
+
+ Button(
+ modifier = Modifier.size(25.dp),
+ shape = CircleShape,
+ colors = ButtonDefaults.buttonColors(containerColor = Color.Blue),
+ contentPadding = PaddingValues(0.dp),
+ onClick = { onEditButtonClick() }
+ ) {
+ Icon(imageVector = Icons.Outlined.Add, contentDescription = null, tint = Color.White)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/components/ThemeDialog.kt b/app/src/main/java/com/geekymusketeers/uncrack/components/ThemeDialog.kt
new file mode 100644
index 00000000..ecb132c9
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/components/ThemeDialog.kt
@@ -0,0 +1,116 @@
+package com.geekymusketeers.uncrack.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.BasicAlertDialog
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.unit.dp
+import com.geekymusketeers.uncrack.R
+import com.geekymusketeers.uncrack.ui.theme.light16
+import com.geekymusketeers.uncrack.ui.theme.medium14
+import com.geekymusketeers.uncrack.ui.theme.normal24
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun ThemeDialog(
+ onDismissRequest: () -> Unit
+) {
+
+ BasicAlertDialog(
+ onDismissRequest = { onDismissRequest() }
+ ) {
+ Column(
+ Modifier
+ .background(MaterialTheme.colorScheme.background, RoundedCornerShape(28.dp))
+ .padding(vertical = 24.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+
+ Icon(
+ imageVector = ImageVector.vectorResource(id = R.drawable.themes),
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onPrimaryContainer
+ )
+
+ Text(
+ text = "Change Theme",
+ style = normal24.copy(MaterialTheme.colorScheme.onSurface)
+ )
+
+ Column {
+
+
+ Text(
+ text = "Dark Mode",
+ modifier = Modifier
+ .clickable {
+ // TODO: Impl the logic
+ onDismissRequest()
+ }
+ .fillMaxWidth()
+ .padding(vertical = 16.dp, horizontal = 32.dp),
+ style = light16.copy(color = MaterialTheme.colorScheme.onSurfaceVariant),
+ )
+
+ Text(
+ text = "Light Mode",
+ modifier = Modifier
+ .clickable {
+ // TODO: Impl the logic
+ onDismissRequest()
+ }
+ .fillMaxWidth()
+ .padding(vertical = 16.dp, horizontal = 32.dp),
+ style = light16.copy(color = MaterialTheme.colorScheme.onSurfaceVariant),
+ )
+
+ Text(
+ text = "Dynamic Theme",
+ modifier = Modifier
+ .clickable {
+ // TODO: Impl the logic
+ onDismissRequest()
+ }
+ .fillMaxWidth()
+ .padding(vertical = 16.dp, horizontal = 32.dp),
+ style = light16.copy(color = MaterialTheme.colorScheme.onSurfaceVariant),
+ )
+ }
+
+ TextButton(
+ onClick = {
+ onDismissRequest()
+ },
+ colors = ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent,
+ contentColor = MaterialTheme.colorScheme.onPrimaryContainer
+ ),
+ modifier = Modifier
+ .align(Alignment.End)
+ .padding(end = 24.dp)
+ ) {
+ Text(
+ text = "Dismiss",
+ style = medium14
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/components/UCTopAppBar.kt b/app/src/main/java/com/geekymusketeers/uncrack/components/UCTopAppBar.kt
new file mode 100644
index 00000000..c800365c
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/components/UCTopAppBar.kt
@@ -0,0 +1,59 @@
+package com.geekymusketeers.uncrack.components
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarColors
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.sp
+import com.geekymusketeers.uncrack.ui.theme.BackgroundLight
+import com.geekymusketeers.uncrack.ui.theme.DMSansFontFamily
+import com.geekymusketeers.uncrack.ui.theme.OnSurfaceLight
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun UCTopAppBar(
+ modifier: Modifier = Modifier,
+ title: String = "",
+ navigationIcon: ImageVector = Icons.AutoMirrored.Filled.ArrowBack,
+ shouldShowBackButton: Boolean = true,
+ fontSize: TextUnit = 22.sp,
+ colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(BackgroundLight),
+ onBackPress: () -> Unit = {},
+) {
+ TopAppBar(
+ modifier = modifier,
+ title = {
+ Text(
+ text = title,
+ fontFamily = DMSansFontFamily,
+ fontSize = fontSize,
+ color = OnSurfaceLight,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ )
+ },
+ navigationIcon = {
+ if (shouldShowBackButton) {
+ IconButton(onClick = {
+ onBackPress()
+ }) {
+ Icon(
+ imageVector = navigationIcon,
+ contentDescription = null
+ )
+ }
+ }
+ },
+ colors = colors
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/data/room/AccountDao.kt b/app/src/main/java/com/geekymusketeers/uncrack/data/dao/AccountDao.kt
similarity index 51%
rename from app/src/main/java/com/geekymusketeers/uncrack/data/room/AccountDao.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/data/dao/AccountDao.kt
index fc5da1e9..71fb45f1 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/data/room/AccountDao.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/data/dao/AccountDao.kt
@@ -1,4 +1,4 @@
-package com.geekymusketeers.uncrack.data.room
+package com.geekymusketeers.uncrack.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
@@ -16,27 +16,12 @@ interface AccountDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addAccount(account: Account)
- @Update
+ @Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun editAccount(account: Account)
@Delete
suspend fun deleteAccount(account: Account)
@Query("SELECT * FROM account_table ORDER BY id ASC")
- fun readAllAccount(): LiveData>
-
- // Favourite
- @Query("SELECT * FROM account_table WHERE isFavourite = 1")
- fun getFavourite(): LiveData>
-
- @Query("SELECT isFavourite from account_table where id = :id")
- suspend fun updateFavourite(id: Int): Boolean
-
- @Query("UPDATE account_table SET isFavourite = 1 WHERE id = :id")
- suspend fun isSelected(id: Int)
-
- @Query("UPDATE account_table SET isFavourite = 0 WHERE id = :id")
- suspend fun isNotSelected(id: Int)
-
-
+ fun readAllAccount(): Flow>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/data/room/CardDao.kt b/app/src/main/java/com/geekymusketeers/uncrack/data/dao/CardDao.kt
similarity index 80%
rename from app/src/main/java/com/geekymusketeers/uncrack/data/room/CardDao.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/data/dao/CardDao.kt
index ff9303a3..a4ed4661 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/data/room/CardDao.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/data/dao/CardDao.kt
@@ -1,8 +1,7 @@
-package com.geekymusketeers.uncrack.data.room
+package com.geekymusketeers.uncrack.data.dao
import androidx.lifecycle.LiveData
import androidx.room.*
-import com.geekymusketeers.uncrack.domain.model.Account
import com.geekymusketeers.uncrack.domain.model.Card
@Dao
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/data/room/KeyDao.kt b/app/src/main/java/com/geekymusketeers/uncrack/data/dao/KeyDao.kt
similarity index 72%
rename from app/src/main/java/com/geekymusketeers/uncrack/data/room/KeyDao.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/data/dao/KeyDao.kt
index e6ed68b0..84b07dc0 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/data/room/KeyDao.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/data/dao/KeyDao.kt
@@ -1,11 +1,11 @@
-package com.geekymusketeers.uncrack.data.room
+package com.geekymusketeers.uncrack.data.dao
-import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.geekymusketeers.uncrack.domain.model.Key
+import kotlinx.coroutines.flow.Flow
@Dao
interface KeyDao {
@@ -14,5 +14,5 @@ interface KeyDao {
suspend fun setMasterKey(key: Key)
@Query("SELECT * FROM master_key")
- fun getMasterKey(): LiveData>
+ fun getMasterKey(): Flow>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/data/datastore/DataStoreUtil.kt b/app/src/main/java/com/geekymusketeers/uncrack/data/datastore/DataStoreUtil.kt
index e1af95d2..99e72b6b 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/data/datastore/DataStoreUtil.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/data/datastore/DataStoreUtil.kt
@@ -14,5 +14,6 @@ class DataStoreUtil @Inject constructor(context: Context) {
companion object {
private val Context.dataStore: DataStore by preferencesDataStore("settings")
val IS_DARK_MODE_KEY = booleanPreferencesKey("dark_mode")
+ val IS_SS_BLOCK_KEY = booleanPreferencesKey("ss_block")
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/data/db/AccountDatabase.kt b/app/src/main/java/com/geekymusketeers/uncrack/data/db/AccountDatabase.kt
index f97b05f9..a4f87146 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/data/db/AccountDatabase.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/data/db/AccountDatabase.kt
@@ -1,41 +1,15 @@
package com.geekymusketeers.uncrack.data.db
-import android.content.Context
import androidx.room.Database
-import androidx.room.Room
import androidx.room.RoomDatabase
-import com.geekymusketeers.uncrack.data.room.AccountDao
+import com.geekymusketeers.uncrack.data.dao.AccountDao
import com.geekymusketeers.uncrack.domain.model.Account
@Database(
entities = [Account::class],
- version = 4
+ version = 4,
+ exportSchema = false
)
-abstract class AccountDatabase : RoomDatabase(){
-
- abstract fun accountDao() : AccountDao
-
- companion object{
- @Volatile
- var INSTANCE : AccountDatabase? = null
-
- @Synchronized
- fun getDatabase(context:Context) : AccountDatabase {
-
- val tempInstance = INSTANCE
-
- if (tempInstance!=null){
- return tempInstance
- }
- synchronized(this) {
- val instance = Room.databaseBuilder(
- context.applicationContext,
- AccountDatabase::class.java,
- "account_database"
- ).fallbackToDestructiveMigration().build()
- INSTANCE = instance
- return instance
- }
- }
- }
+abstract class AccountDatabase : RoomDatabase() {
+ abstract val accountDao : AccountDao
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/data/db/CardDatabase.kt b/app/src/main/java/com/geekymusketeers/uncrack/data/db/CardDatabase.kt
index d16ad07d..d1c2f344 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/data/db/CardDatabase.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/data/db/CardDatabase.kt
@@ -4,7 +4,7 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
-import com.geekymusketeers.uncrack.data.room.CardDao
+import com.geekymusketeers.uncrack.data.dao.CardDao
import com.geekymusketeers.uncrack.domain.model.Card
@Database(
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/data/db/KeyDatabase.kt b/app/src/main/java/com/geekymusketeers/uncrack/data/db/KeyDatabase.kt
index 3beb97c0..30dd59d4 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/data/db/KeyDatabase.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/data/db/KeyDatabase.kt
@@ -4,36 +4,14 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
-import com.geekymusketeers.uncrack.data.room.KeyDao
+import com.geekymusketeers.uncrack.data.dao.KeyDao
import com.geekymusketeers.uncrack.domain.model.Key
-@Database(entities = [Key::class],
- version = 3)
+@Database(
+ entities = [Key::class],
+ version = 3,
+ exportSchema = false
+)
abstract class KeyDatabase : RoomDatabase() {
-
- abstract fun keyDao(): KeyDao
-
- companion object {
- @Volatile
- var INSTANCE : KeyDatabase? = null
-
- @Synchronized
- fun getDatabase(context: Context) : KeyDatabase {
-
- val tempInstance = INSTANCE
-
- if (tempInstance!=null) {
- return tempInstance
- }
- synchronized(this) {
- val instance = Room.databaseBuilder (
- context.applicationContext,
- KeyDatabase::class.java,
- "masterKey_database"
- ).fallbackToDestructiveMigration().build()
- INSTANCE = instance
- return instance
- }
- }
- }
+ abstract val keyDao: KeyDao
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/di/AppModule.kt b/app/src/main/java/com/geekymusketeers/uncrack/di/AppModule.kt
index 29acb1ab..12acbb96 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/di/AppModule.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/di/AppModule.kt
@@ -1,12 +1,22 @@
package com.geekymusketeers.uncrack.di
+import android.app.Application
import android.content.Context
+import androidx.room.Room
import com.geekymusketeers.uncrack.data.datastore.DataStoreUtil
+import com.geekymusketeers.uncrack.data.db.AccountDatabase
+import com.geekymusketeers.uncrack.data.db.KeyDatabase
+import com.geekymusketeers.uncrack.data.db.KeyDatabase_Impl
+import com.geekymusketeers.uncrack.domain.repository.AccountRepository
+import com.geekymusketeers.uncrack.domain.repository.AccountRepositoryImpl
+import com.geekymusketeers.uncrack.domain.repository.KeyRepository
+import com.geekymusketeers.uncrack.domain.repository.KeyRepositoryImpl
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
@@ -15,4 +25,46 @@ object AppModule {
@Provides
fun provideDataStoreUtil(@ApplicationContext context: Context): DataStoreUtil =
DataStoreUtil(context)
+
+ @Provides
+ @Singleton
+ fun provideAccountDatabase(app: Application) : AccountDatabase {
+
+ return Room.databaseBuilder(
+ app,
+ AccountDatabase::class.java,
+ "account_database"
+ )
+ .fallbackToDestructiveMigration()
+ .build()
+ }
+
+ @Provides
+ @Singleton
+ fun provideAccountRepository(
+ db: AccountDatabase
+ ): AccountRepository {
+ return AccountRepositoryImpl(accountDao = db.accountDao)
+ }
+
+ @Provides
+ @Singleton
+ fun provideKeyDatabase(app: Application): KeyDatabase {
+
+ return Room.databaseBuilder(
+ app,
+ KeyDatabase::class.java,
+ "masterKey_database"
+ )
+ .fallbackToDestructiveMigration()
+ .build()
+ }
+
+ @Provides
+ @Singleton
+ fun provideKeyRepository(
+ keyDB: KeyDatabase
+ ): KeyRepository {
+ return KeyRepositoryImpl(keyDao = keyDB.keyDao)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/AccountRepository.kt b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/AccountRepository.kt
index bcffff3b..99adb532 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/AccountRepository.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/AccountRepository.kt
@@ -1,35 +1,15 @@
package com.geekymusketeers.uncrack.domain.repository
-import androidx.lifecycle.LiveData
-import com.geekymusketeers.uncrack.data.room.AccountDao
import com.geekymusketeers.uncrack.domain.model.Account
+import kotlinx.coroutines.flow.Flow
+interface AccountRepository {
-class AccountRepository(private val accountDao: AccountDao) {
- val readAllAccount: LiveData> = accountDao.readAllAccount()
+ suspend fun addAccount(account: Account)
- suspend fun addAccount(account: Account){
- accountDao.addAccount(account)
- }
+ suspend fun editAccount(account: Account)
- suspend fun editAccount(account: Account){
- accountDao.editAccount(account)
- }
+ suspend fun deleteAccount(account: Account)
- suspend fun deleteAccount(account: Account){
- accountDao.deleteAccount(account)
- }
-
- fun getFavouriteAccount(){
- accountDao.getFavourite()
- }
-
- suspend fun updateFavourite(account: Account){
-
- val id = account.id
- val test:Boolean = accountDao.updateFavourite(id)
- if (test) accountDao.isNotSelected(id)
- else accountDao.isSelected(id)
-
- }
+ fun getAllAccounts(): Flow>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/AccountRepositoryImpl.kt b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/AccountRepositoryImpl.kt
new file mode 100644
index 00000000..fc8e4167
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/AccountRepositoryImpl.kt
@@ -0,0 +1,28 @@
+package com.geekymusketeers.uncrack.domain.repository
+
+import androidx.lifecycle.LiveData
+import com.geekymusketeers.uncrack.data.dao.AccountDao
+import com.geekymusketeers.uncrack.domain.model.Account
+import kotlinx.coroutines.flow.Flow
+
+
+class AccountRepositoryImpl(
+ private val accountDao: AccountDao
+): AccountRepository {
+ override suspend fun addAccount(account: Account){
+ accountDao.addAccount(account)
+ }
+
+ override suspend fun editAccount(account: Account){
+ accountDao.editAccount(account)
+ }
+
+ override suspend fun deleteAccount(account: Account){
+ accountDao.deleteAccount(account)
+ }
+
+ override fun getAllAccounts(): Flow> {
+ return accountDao.readAllAccount()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/CardRepository.kt b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/CardRepository.kt
index 3daed7fb..3b4d3b53 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/CardRepository.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/CardRepository.kt
@@ -2,7 +2,7 @@ package com.geekymusketeers.uncrack.domain.repository
import androidx.lifecycle.LiveData
import com.geekymusketeers.uncrack.domain.model.Card
-import com.geekymusketeers.uncrack.data.room.CardDao
+import com.geekymusketeers.uncrack.data.dao.CardDao
class CardRepository(private val cardDao: CardDao) {
val readAllCard: LiveData> = cardDao.readAllCard()
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/KeyRepository.kt b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/KeyRepository.kt
index 7ebb29d6..09cefb50 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/KeyRepository.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/KeyRepository.kt
@@ -1,14 +1,11 @@
package com.geekymusketeers.uncrack.domain.repository
-import androidx.lifecycle.LiveData
import com.geekymusketeers.uncrack.domain.model.Key
-import com.geekymusketeers.uncrack.data.room.KeyDao
+import kotlinx.coroutines.flow.Flow
-class KeyRepository(private val keyDao: KeyDao) {
+interface KeyRepository {
- fun getMasterKey(): LiveData> = keyDao.getMasterKey()
+ suspend fun setMasterKey(key: Key)
- suspend fun setMasterKey(key: Key) {
- keyDao.setMasterKey(key)
- }
+ fun getMasterKey(): Flow>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/KeyRepositoryImpl.kt b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/KeyRepositoryImpl.kt
new file mode 100644
index 00000000..4fda0084
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/domain/repository/KeyRepositoryImpl.kt
@@ -0,0 +1,18 @@
+package com.geekymusketeers.uncrack.domain.repository
+
+import com.geekymusketeers.uncrack.domain.model.Key
+import com.geekymusketeers.uncrack.data.dao.KeyDao
+import kotlinx.coroutines.flow.Flow
+
+class KeyRepositoryImpl(
+ private val keyDao: KeyDao
+): KeyRepository {
+
+ override fun getMasterKey(): Flow> {
+ return keyDao.getMasterKey()
+ }
+
+ override suspend fun setMasterKey(key: Key) {
+ keyDao.setMasterKey(key)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/navigation/Navigation.kt b/app/src/main/java/com/geekymusketeers/uncrack/navigation/Navigation.kt
index 3ba9fddc..9bbabb89 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/navigation/Navigation.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/navigation/Navigation.kt
@@ -13,6 +13,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
+import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
@@ -21,10 +22,17 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.geekymusketeers.uncrack.R
-import com.geekymusketeers.uncrack.presentation.homeScreen.HomeScreen
-import com.geekymusketeers.uncrack.presentation.passwordScreen.PasswordScreen
-import com.geekymusketeers.uncrack.presentation.profileScreen.ProfileScreen
-import com.geekymusketeers.uncrack.presentation.shieldScreen.ShieldScreen
+import com.geekymusketeers.uncrack.presentation.account.AccountScreen
+import com.geekymusketeers.uncrack.presentation.account.PasswordGenerator
+import com.geekymusketeers.uncrack.presentation.account.PasswordGeneratorViewModel
+import com.geekymusketeers.uncrack.presentation.home.HomeScreen
+import com.geekymusketeers.uncrack.presentation.masterKey.ConfirmMasterKeyScreen
+import com.geekymusketeers.uncrack.presentation.masterKey.CreateMasterKeyScreen
+import com.geekymusketeers.uncrack.presentation.masterKey.UpdateMasterKey
+import com.geekymusketeers.uncrack.presentation.password.PasswordScreen
+import com.geekymusketeers.uncrack.presentation.profile.ProfileScreen
+import com.geekymusketeers.uncrack.presentation.shield.ShieldScreen
+import com.geekymusketeers.uncrack.sharedViewModel.ThemeViewModel
import com.geekymusketeers.uncrack.ui.theme.BackgroundLight
import com.geekymusketeers.uncrack.ui.theme.DMSansFontFamily
import com.geekymusketeers.uncrack.ui.theme.FadeIn
@@ -33,18 +41,29 @@ import com.geekymusketeers.uncrack.ui.theme.OnPrimaryContainerLight
import com.geekymusketeers.uncrack.ui.theme.OnSurfaceVariantLight
import com.geekymusketeers.uncrack.ui.theme.PrimaryDark
import com.geekymusketeers.uncrack.util.BackPressHandler
+import com.geekymusketeers.uncrack.viewModel.KeyViewModel
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
-fun Navigation(modifier: Modifier = Modifier) {
+fun Navigation(
+ modifier: Modifier = Modifier,
+ masterKeyViewModel: KeyViewModel = hiltViewModel(),
+ passwordGeneratorViewModel: PasswordGeneratorViewModel = hiltViewModel(),
+ themeViewModel: ThemeViewModel = hiltViewModel()
+) {
val navController = rememberNavController()
val backStackEntry = navController.currentBackStackEntryAsState()
val screensWithoutNavigationBar = persistentListOf(
- "add_password_screen"
+ "add_password_screen",
+ "profile_screen",
+ "update_master_key_screen",
+ "create_new_master_key_screen",
+ "confirm_master_key_screen",
+ "password_generator_screen"
)
BackPressHandler()
@@ -83,6 +102,41 @@ fun Navigation(modifier: Modifier = Modifier) {
composable(route = "profile_screen") {
ProfileScreen()
}
+
+ composable(route = "account_screen") {
+ AccountScreen(
+ navController,
+ themeViewModel
+ )
+ }
+
+ composable(route = "update_master_key_screen") {
+ UpdateMasterKey(
+ navController,
+ masterKeyViewModel
+ )
+ }
+
+ composable(route = "create_new_master_key_screen") {
+ CreateMasterKeyScreen(
+ navController,
+ masterKeyViewModel
+ )
+ }
+
+ composable(route = "confirm_master_key_screen") {
+ ConfirmMasterKeyScreen(
+ navController,
+ masterKeyViewModel
+ )
+ }
+
+ composable(route = "password_generator_screen") {
+ PasswordGenerator(
+ navController,
+ passwordGeneratorViewModel
+ )
+ }
}
}
}
@@ -118,7 +172,7 @@ fun ShowBottomNavigation(
),
BottomNavItem(
name = "Profile",
- route = "profile_screen",
+ route = "account_screen",
icon = ImageVector.vectorResource(id = R.drawable.person_icon)
)
)
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/AccountItems.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/AccountItems.kt
new file mode 100644
index 00000000..99e562ab
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/AccountItems.kt
@@ -0,0 +1,27 @@
+package com.geekymusketeers.uncrack.presentation.account
+
+import com.geekymusketeers.uncrack.R
+
+// TODO: Need to change icons for some of the items
+enum class AccountItems(val itemsName: String, val icon: Int) {
+ // Security
+ CHANGE_MASTER_KEY("Change master password", R.drawable.lock),
+ BIOMETRIC("Unlock with biometric", R.drawable.fingerprint),
+ BLOCK_SS("Block screenshots", R.drawable.block_ss),
+
+ //BACKUP
+ EXPORT_IMPORT("Export/Import", R.drawable.import_export),
+ BACKUP_RESTORE("Backup/Restore", R.drawable.backup_restore),
+
+ // General
+ THEME("Theme", R.drawable.themes),
+ PASSWORD_GENERATOR("Password Generator", R.drawable.generate_password_icon),
+ INVITE_FRIENDS("Invite Friends", R.drawable.share_app),
+ RATE_UNCRACK("Rate UnCrack", R.drawable.rating),
+ SEND_FEEDBACK("Send Feedback", R.drawable.feedback),
+ PRIVACY_POLICY("Privacy Policy", R.drawable.shield),
+
+ // Danger Zone
+ LOG_OUT("Log out", R.drawable.logout),
+ DELETE_ACCOUNT("Delete Account", R.drawable.delete_icon)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/AccountScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/AccountScreen.kt
new file mode 100644
index 00000000..afed5d52
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/AccountScreen.kt
@@ -0,0 +1,295 @@
+package com.geekymusketeers.uncrack.presentation.account
+
+import android.content.Intent
+import android.net.Uri
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import com.geekymusketeers.uncrack.BuildConfig
+import com.geekymusketeers.uncrack.R
+import com.geekymusketeers.uncrack.components.AccountOption
+import com.geekymusketeers.uncrack.components.ProfileContainer
+import com.geekymusketeers.uncrack.components.ThemeDialog
+import com.geekymusketeers.uncrack.sharedViewModel.ThemeViewModel
+import com.geekymusketeers.uncrack.ui.theme.OnPrimaryContainerLight
+import com.geekymusketeers.uncrack.ui.theme.OnSurfaceVariantLight
+import com.geekymusketeers.uncrack.ui.theme.SurfaceTintLight
+import com.geekymusketeers.uncrack.ui.theme.bold18
+import com.geekymusketeers.uncrack.ui.theme.medium14
+import com.geekymusketeers.uncrack.ui.theme.medium32
+import com.geekymusketeers.uncrack.ui.theme.normal14
+import com.geekymusketeers.uncrack.ui.theme.normal16
+import com.geekymusketeers.uncrack.util.Constants.INVITE
+import com.geekymusketeers.uncrack.util.Util
+
+@Composable
+fun AccountScreen(
+ navController: NavHostController,
+ themeViewModel: ThemeViewModel,
+ modifier: Modifier = Modifier
+) {
+
+ val context = LocalContext.current
+ var openThemeDialog by remember { mutableStateOf(false) }
+ var openLogoutDialog by remember { mutableStateOf(false) }
+
+ when {
+ openThemeDialog -> {
+ ThemeDialog(onDismissRequest = { openThemeDialog = false })
+ }
+
+ openLogoutDialog -> {
+ AlertDialog(
+ onDismissRequest = { openLogoutDialog = false },
+ icon = {
+ Icon(
+ painter = painterResource(id = R.drawable.logout),
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onPrimaryContainer
+ )
+ },
+ title = {
+ Text(
+ text = stringResource(R.string.logout),
+ style = normal16.copy(color = OnPrimaryContainerLight)
+ )
+ },
+ text = {
+ Text(
+ text = stringResource(R.string.are_you_sure_you_want_to_logout),
+ style = normal16.copy(color = OnSurfaceVariantLight)
+ )
+ },
+ confirmButton = {
+ TextButton(
+ onClick = {
+ // TODO: IMPL the logout logic
+ openLogoutDialog = false
+ },
+ colors = ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent,
+ contentColor = MaterialTheme.colorScheme.onPrimaryContainer
+ )
+ ) {
+ Text(
+ "Logout",
+ style = medium14
+ )
+ }
+ },
+ dismissButton = {
+ TextButton(
+ onClick = {
+ openLogoutDialog = false
+ },
+ colors = ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent,
+ contentColor = MaterialTheme.colorScheme.onPrimaryContainer
+ )
+ ) {
+ Text(
+ text = stringResource(R.string.cancel),
+ style = medium14
+ )
+ }
+ },
+ containerColor = MaterialTheme.colorScheme.background
+ )
+ }
+ }
+
+ Column(
+ modifier = modifier
+ .fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 52.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable { },
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ ProfileContainer {
+ navController.navigate("profile_screen")
+ }
+
+ Spacer(modifier = Modifier.height(15.dp))
+
+ Text(
+ text = "John Doe",
+ style = medium32.copy(color = OnPrimaryContainerLight)
+ )
+ }
+ }
+
+ Spacer(modifier = Modifier.height(40.dp))
+
+ LazyColumn(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+
+ item {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 18.dp, top = 18.dp),
+ text = stringResource(id = R.string.security),
+ style = bold18.copy(color = OnPrimaryContainerLight)
+ )
+ }
+
+ items(AccountItems.entries.subList(0,3)) {
+ AccountOption(it) { onClick ->
+ when(onClick) {
+ AccountItems.BIOMETRIC -> {}
+ AccountItems.CHANGE_MASTER_KEY -> {
+ navController.navigate("update_master_key_screen")
+ }
+ AccountItems.BLOCK_SS -> {
+ themeViewModel.blockScreenShort()
+ }
+ else -> {}
+ }
+ }
+ }
+
+ item {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 18.dp, top = 18.dp),
+ text = stringResource(R.string.backup),
+ style = bold18.copy(color = OnPrimaryContainerLight)
+ )
+ }
+
+ items(AccountItems.entries.subList(3,5)) {
+ AccountOption(it) { onClick ->
+ when(onClick) {
+ AccountItems.EXPORT_IMPORT -> {}
+ AccountItems.BACKUP_RESTORE -> {}
+ else -> {}
+ }
+ }
+ }
+
+ item {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 18.dp, top = 18.dp),
+ text = stringResource(R.string.general),
+ style = bold18.copy(color = OnPrimaryContainerLight)
+ )
+ }
+
+ items(AccountItems.entries.subList(5,11)) {
+ AccountOption(it) { onClick ->
+ when(onClick) {
+ AccountItems.THEME -> {
+ openThemeDialog = true
+ }
+
+ AccountItems.PASSWORD_GENERATOR -> {
+ navController.navigate("password_generator_screen")
+ }
+
+ AccountItems.INVITE_FRIENDS -> {
+ val sendIntent = Intent(Intent.ACTION_SEND).apply {
+ putExtra(Intent.EXTRA_TEXT, INVITE)
+ type = "text/plain"
+ }
+ val shareIntent = Intent.createChooser(sendIntent, null)
+ context.startActivity(shareIntent)
+ }
+
+ AccountItems.RATE_UNCRACK -> {
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.data = Uri.parse(Util.PLAYSTORE_URL)
+ context.startActivity(intent)
+ }
+
+ AccountItems.SEND_FEEDBACK -> {
+ val openURL = Intent(Intent.ACTION_VIEW)
+ openURL.data = Uri.parse(context.resources.getString(R.string.mailTo))
+ context.startActivity(openURL)
+ }
+
+ AccountItems.PRIVACY_POLICY -> {}
+ else -> {}
+ }
+ }
+ }
+
+ item {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 18.dp, top = 18.dp),
+ text = stringResource(R.string.danger_zone),
+ style = bold18.copy(color = OnPrimaryContainerLight)
+ )
+ }
+
+ items(AccountItems.entries.subList(11, AccountItems.entries.size)) {
+ AccountOption(it) { onClick ->
+ when(onClick) {
+ AccountItems.LOG_OUT -> {
+ openLogoutDialog = true
+ }
+ AccountItems.DELETE_ACCOUNT -> {}
+ else -> {}
+ }
+ }
+ }
+
+ item {
+ Text(
+ modifier = Modifier.padding(top = 20.dp, bottom = 10.dp),
+ text = "Version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})",
+ style = normal14.copy(color = SurfaceTintLight)
+ )
+ Text(
+ modifier = Modifier.padding(bottom = 150.dp),
+ text = stringResource(R.string.by_aritra_das),
+ style = normal14.copy(color = SurfaceTintLight)
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/PasswordGenerator.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/PasswordGenerator.kt
new file mode 100644
index 00000000..a1f2059a
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/PasswordGenerator.kt
@@ -0,0 +1,219 @@
+package com.geekymusketeers.uncrack.presentation.account
+
+import android.widget.Toast
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Slider
+import androidx.compose.material3.SliderDefaults
+import androidx.compose.material3.Switch
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalClipboardManager
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.TextUnitType
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import com.geekymusketeers.uncrack.R
+import com.geekymusketeers.uncrack.components.UCButton
+import com.geekymusketeers.uncrack.components.UCTopAppBar
+import com.geekymusketeers.uncrack.ui.theme.BackgroundLight
+import com.geekymusketeers.uncrack.ui.theme.OnPrimaryContainerLight
+import com.geekymusketeers.uncrack.ui.theme.PrimaryLight
+import com.geekymusketeers.uncrack.ui.theme.SurfaceLight
+import com.geekymusketeers.uncrack.ui.theme.medium24
+import com.geekymusketeers.uncrack.ui.theme.medium30
+import com.geekymusketeers.uncrack.ui.theme.normal16
+import com.geekymusketeers.uncrack.util.Constants.sliderStepRange
+import com.geekymusketeers.uncrack.util.Constants.sliderSteps
+import timber.log.Timber
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun PasswordGenerator(
+ navController: NavHostController,
+ passwordGeneratorViewModel: PasswordGeneratorViewModel,
+ modifier: Modifier = Modifier
+) {
+ val context = LocalContext.current
+ val clipboardManager = LocalClipboardManager.current
+ val password by passwordGeneratorViewModel.password.observeAsState("")
+ val passwordLength by passwordGeneratorViewModel.passwordLength.observeAsState(0.0f)
+ val includeUppercase by passwordGeneratorViewModel.includeUppercase.observeAsState(true)
+ val includeLowercase by passwordGeneratorViewModel.includeLowercase.observeAsState(true)
+ val includeNumbers by passwordGeneratorViewModel.includeNumbers.observeAsState(true)
+ val includeSpecialChars by passwordGeneratorViewModel.includeSpecialChars.observeAsState(true)
+
+ Scaffold(
+ topBar = {
+ UCTopAppBar(
+ modifier = modifier.fillMaxWidth(),
+ title = "Password Generator",
+ onBackPress = { navController.popBackStack() }
+ )
+ }
+ ) { paddingValues ->
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(paddingValues)
+ .padding(16.dp)
+ .background(BackgroundLight),
+ verticalArrangement = Arrangement.Center
+ ) {
+
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ text = buildAnnotatedString {
+ password.forEach {
+ val textColor = when {
+ it.isDigit() -> Color.Blue
+ it.isLetterOrDigit().not() -> Color.Magenta
+ else -> OnPrimaryContainerLight
+ }
+ withStyle(style = SpanStyle(color = textColor)) {
+ append(it.toString())
+ }
+ }
+ },
+ style = medium30,
+ textAlign = TextAlign.Center,
+ letterSpacing = TextUnit(1F, TextUnitType.Sp)
+ )
+
+ Spacer(modifier = Modifier.height(90.dp))
+
+ Text(
+ text = stringResource(R.string.password_generated_length, passwordLength.toInt()),
+ style = medium24.copy(OnPrimaryContainerLight)
+ )
+
+ Spacer(modifier = Modifier.height(10.dp))
+
+ Slider(
+ modifier = Modifier.fillMaxWidth(),
+ value = passwordLength,
+ onValueChange = { newPasswordLength ->
+ passwordGeneratorViewModel.updatePasswordLength(newPasswordLength)
+ },
+ steps = sliderSteps,
+ valueRange = sliderStepRange,
+ colors = SliderDefaults.colors(
+ thumbColor = OnPrimaryContainerLight,
+ activeTrackColor = PrimaryLight,
+ inactiveTrackColor = SurfaceLight,
+ activeTickColor = Color.Transparent,
+ inactiveTickColor = Color.Transparent
+ )
+ )
+
+ Spacer(modifier = Modifier.height(30.dp))
+
+ Text(
+ text = stringResource(R.string.include_following),
+ style = medium24.copy(OnPrimaryContainerLight)
+ )
+
+ Spacer(modifier = Modifier.height(15.dp))
+
+ SwitchItem(
+ label = stringResource(R.string.numbers),
+ checked = includeNumbers
+ ) {
+ passwordGeneratorViewModel.updateIncludeNumbers(it)
+ }
+ SwitchItem(
+ label = stringResource(R.string.uppercase_letters),
+ checked = includeUppercase
+ ) {
+ passwordGeneratorViewModel.updateIncludeUppercase(it)
+ }
+ SwitchItem(
+ label = stringResource(R.string.lowercase_letters),
+ checked = includeLowercase
+ ) {
+ passwordGeneratorViewModel.updateIncludeLowercase(it)
+ }
+ SwitchItem(
+ label = stringResource(R.string.special_symbols),
+ checked = includeSpecialChars
+ ) {
+ passwordGeneratorViewModel.updateIncludeSpecialChars(it)
+ }
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ UCButton(
+ modifier = Modifier.fillMaxWidth(),
+ text = stringResource(R.string.generate),
+ onClick = {
+ passwordGeneratorViewModel.generatePassword()
+ Timber.d("Password ${passwordGeneratorViewModel.generatePassword()}")
+ },
+ leadingIcon = painterResource(id = R.drawable.generate_password)
+ )
+
+ Spacer(modifier = Modifier.height(10.dp))
+
+ UCButton(
+ modifier = Modifier.fillMaxWidth(),
+ text = stringResource(R.string.copy),
+ onClick = {
+ password.let { passwordToCopy ->
+// clipboardManager.setText() //TODO: Need to check
+ }
+ Toast.makeText(context, "Copied", Toast.LENGTH_SHORT).show()
+ },
+ leadingIcon = painterResource(id = R.drawable.copy_password)
+ )
+ }
+ }
+}
+
+
+@Composable
+fun SwitchItem(
+ label: String,
+ checked: Boolean,
+ modifier: Modifier = Modifier,
+ onCheckedChange: (Boolean) -> Unit
+) {
+ Row(
+ modifier = modifier
+ .fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ text = label,
+ style = normal16.copy(OnPrimaryContainerLight)
+ )
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ Switch(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ modifier = Modifier.padding(start = 8.dp)
+ )
+ }
+}
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/PasswordGeneratorViewModel.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/PasswordGeneratorViewModel.kt
new file mode 100644
index 00000000..a3a1b14a
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/account/PasswordGeneratorViewModel.kt
@@ -0,0 +1,85 @@
+package com.geekymusketeers.uncrack.presentation.account
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.geekymusketeers.uncrack.util.Constants.DEFAULT_PASSWORD_LENGTH
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class PasswordGeneratorViewModel @Inject constructor() : ViewModel() {
+
+ private val _password = MutableLiveData()
+ val password: LiveData = _password
+
+ private val _passwordLength = MutableLiveData(DEFAULT_PASSWORD_LENGTH)
+ val passwordLength: LiveData = _passwordLength
+
+ private val _includeUppercase = MutableLiveData(true)
+ val includeUppercase: LiveData = _includeUppercase
+
+ private val _includeLowercase = MutableLiveData(true)
+ val includeLowercase: LiveData = _includeLowercase
+
+ private val _includeNumbers = MutableLiveData(true)
+ val includeNumbers: LiveData = _includeNumbers
+
+ private val _includeSpecialChars = MutableLiveData(true)
+ val includeSpecialChars: LiveData = _includeSpecialChars
+
+ fun generatePassword() {
+ _password.value = generatePassword(
+ length = _passwordLength.value ?: DEFAULT_PASSWORD_LENGTH,
+ includeUppercase = _includeUppercase.value ?: true,
+ includeLowercase = _includeLowercase.value ?: true,
+ includeNumbers = _includeNumbers.value ?: true,
+ includeSpecialChars = _includeSpecialChars.value ?: true
+ )
+ }
+
+ fun updatePasswordLength(newLength: Float) {
+ _passwordLength.value = newLength
+ }
+
+ fun updateIncludeUppercase(include: Boolean) {
+ _includeUppercase.value = include
+ }
+
+ fun updateIncludeLowercase(include: Boolean) {
+ _includeLowercase.value = include
+ }
+
+ fun updateIncludeNumbers(include: Boolean) {
+ _includeNumbers.value = include
+ }
+
+ fun updateIncludeSpecialChars(include: Boolean) {
+ _includeSpecialChars.value = include
+ }
+
+ private fun generatePassword(
+ length: Float,
+ includeUppercase: Boolean,
+ includeLowercase: Boolean,
+ includeNumbers: Boolean,
+ includeSpecialChars: Boolean
+ ): String {
+ val charPool = buildString {
+ if (includeUppercase) {
+ append("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
+ }
+ if (includeLowercase) {
+ append("abcdefghijklmnopqrstuvwxyz")
+ }
+ if (includeNumbers) {
+ append("0123456789")
+ }
+ if (includeSpecialChars) {
+ append("!@#$%^&*()_+")
+ }
+ }
+
+ return (1..length.toInt()).map { charPool.random() }.joinToString("")
+ }
+}
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/authScreens/login/LoginScreens.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/auth/login/LoginScreens.kt
similarity index 83%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/authScreens/login/LoginScreens.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/auth/login/LoginScreens.kt
index 4ccf63e4..f4487cf3 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/authScreens/login/LoginScreens.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/auth/login/LoginScreens.kt
@@ -1,10 +1,13 @@
-package com.geekymusketeers.uncrack.presentation.authScreens.login
+package com.geekymusketeers.uncrack.presentation.auth.login
+import android.app.Activity
+import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -13,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
@@ -25,6 +29,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
@@ -32,6 +37,7 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
+import com.geekymusketeers.uncrack.MainActivity
import com.geekymusketeers.uncrack.R
import com.geekymusketeers.uncrack.components.UCButton
import com.geekymusketeers.uncrack.components.UCTextField
@@ -40,7 +46,10 @@ import com.geekymusketeers.uncrack.ui.theme.OnPrimaryContainerLight
import com.geekymusketeers.uncrack.ui.theme.PrimaryLight
import com.geekymusketeers.uncrack.ui.theme.UnCrackTheme
import com.geekymusketeers.uncrack.ui.theme.medium16
+import com.geekymusketeers.uncrack.util.UtilsKt.findActivity
+import dagger.hilt.android.AndroidEntryPoint
+@AndroidEntryPoint
class LoginScreens : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -57,15 +66,16 @@ class LoginScreens : ComponentActivity() {
setContent {
UnCrackTheme {
- LoginContent()
+ LoginContent(this@LoginScreens)
}
}
}
}
@Composable
-fun LoginContent(modifier: Modifier = Modifier) {
+fun LoginContent(activity: Activity, modifier: Modifier = Modifier) {
+ val context = LocalContext.current
val email by remember {
mutableStateOf("")
}
@@ -145,18 +155,25 @@ fun LoginContent(modifier: Modifier = Modifier) {
text = stringResource(R.string.login),
onClick = {
// TODO: Perform req operation and navigate to Home Screen
+ context.findActivity()?.apply {
+ startActivity(Intent(activity, MainActivity::class.java))
+ }
},
- enabled = false
+// enabled = false
)
- Spacer(modifier = Modifier.height(10.dp))
+ Spacer(modifier = Modifier.height(15.dp))
- Row {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.Center
+ ) {
Text(
text = stringResource(R.string.don_t_have_an_account),
style = medium16.copy(color = OnPrimaryContainerLight)
)
+ Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(R.string.create),
style = medium16.copy(color = PrimaryLight)
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/authScreens/signup/SignupScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/auth/signup/SignupScreen.kt
similarity index 97%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/authScreens/signup/SignupScreen.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/auth/signup/SignupScreen.kt
index e8635dde..628caaa3 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/authScreens/signup/SignupScreen.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/auth/signup/SignupScreen.kt
@@ -1,4 +1,4 @@
-package com.geekymusketeers.uncrack.presentation.authScreens.signup
+package com.geekymusketeers.uncrack.presentation.auth.signup
import android.os.Bundle
import androidx.activity.ComponentActivity
@@ -40,7 +40,9 @@ import com.geekymusketeers.uncrack.ui.theme.OnPrimaryContainerLight
import com.geekymusketeers.uncrack.ui.theme.PrimaryLight
import com.geekymusketeers.uncrack.ui.theme.UnCrackTheme
import com.geekymusketeers.uncrack.ui.theme.medium16
+import dagger.hilt.android.AndroidEntryPoint
+@AndroidEntryPoint
class SignupScreen : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/homeScreen/HomeScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/home/HomeScreen.kt
similarity index 56%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/homeScreen/HomeScreen.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/home/HomeScreen.kt
index 412df2d4..0c1c950a 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/homeScreen/HomeScreen.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/home/HomeScreen.kt
@@ -1,4 +1,4 @@
-package com.geekymusketeers.uncrack.presentation.homeScreen
+package com.geekymusketeers.uncrack.presentation.home
import androidx.compose.runtime.Composable
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/OnboardingScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/OnboardingScreen.kt
similarity index 90%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/OnboardingScreen.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/OnboardingScreen.kt
index 16de9529..c9fc168f 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/OnboardingScreen.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/OnboardingScreen.kt
@@ -1,5 +1,6 @@
-package com.geekymusketeers.uncrack.presentation.introScreens
+package com.geekymusketeers.uncrack.presentation.intro
+import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
@@ -40,18 +41,21 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.geekymusketeers.uncrack.R
import com.geekymusketeers.uncrack.components.OnboardingComponent
-import com.geekymusketeers.uncrack.presentation.authScreens.login.LoginScreens
-import com.geekymusketeers.uncrack.presentation.introScreens.model.OnBoardingItem
+import com.geekymusketeers.uncrack.presentation.auth.login.LoginScreens
+import com.geekymusketeers.uncrack.presentation.intro.model.OnBoardingItem
import com.geekymusketeers.uncrack.ui.theme.DMSansFontFamily
import com.geekymusketeers.uncrack.ui.theme.OnSurfaceLight
import com.geekymusketeers.uncrack.ui.theme.OnSurfaceVariantLight
import com.geekymusketeers.uncrack.ui.theme.PrimaryDark
+import com.geekymusketeers.uncrack.ui.theme.UnCrackTheme
import com.geekymusketeers.uncrack.ui.theme.navigationTopBarHeight
import com.geekymusketeers.uncrack.ui.theme.normal16
import com.geekymusketeers.uncrack.util.UtilsKt.findActivity
import com.geekymusketeers.uncrack.util.onClick
+import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
+@AndroidEntryPoint
class OnboardingScreen : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -67,14 +71,16 @@ class OnboardingScreen : ComponentActivity() {
super.onCreate(savedInstanceState)
setContent {
- OnboardingContent()
+ UnCrackTheme {
+ OnboardingContent(this@OnboardingScreen)
+ }
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
-fun OnboardingContent(modifier: Modifier = Modifier) {
+fun OnboardingContent(activity: Activity, modifier: Modifier = Modifier) {
val scope = rememberCoroutineScope()
val context = LocalContext.current
val pages = OnBoardingItem.onboardingScreenItems(context)
@@ -110,7 +116,7 @@ fun OnboardingContent(modifier: Modifier = Modifier) {
context
.findActivity()
?.apply {
- val loginIntent = Intent(this, LoginScreens::class.java)
+ val loginIntent = Intent(activity, LoginScreens::class.java)
startActivity(loginIntent)
finish()
}
@@ -148,7 +154,7 @@ fun OnboardingContent(modifier: Modifier = Modifier) {
context
.findActivity()
?.apply {
- val loginIntent = Intent(this, LoginScreens::class.java)
+ val loginIntent = Intent(activity, LoginScreens::class.java)
startActivity(loginIntent)
finish()
}
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/SplashScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/SplashScreen.kt
similarity index 92%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/SplashScreen.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/SplashScreen.kt
index c797adb6..61acfcb1 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/SplashScreen.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/SplashScreen.kt
@@ -1,4 +1,4 @@
-package com.geekymusketeers.uncrack.presentation.introScreens
+package com.geekymusketeers.uncrack.presentation.intro
import android.annotation.SuppressLint
import android.app.Activity
@@ -32,8 +32,11 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.geekymusketeers.uncrack.R
import com.geekymusketeers.uncrack.ui.theme.BackgroundLight
+import com.geekymusketeers.uncrack.ui.theme.UnCrackTheme
+import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
+@AndroidEntryPoint
@SuppressLint("CustomSplashScreen")
class SplashScreen : ComponentActivity() {
@@ -50,7 +53,9 @@ class SplashScreen : ComponentActivity() {
super.onCreate(savedInstanceState)
setContent {
- SplashContent(this@SplashScreen)
+ UnCrackTheme {
+ SplashContent(this@SplashScreen)
+ }
}
}
}
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/model/OnBoardingItem.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/model/OnBoardingItem.kt
similarity index 91%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/model/OnBoardingItem.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/model/OnBoardingItem.kt
index 3ff7e003..1758bcc5 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/introScreens/model/OnBoardingItem.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/intro/model/OnBoardingItem.kt
@@ -1,4 +1,4 @@
-package com.geekymusketeers.uncrack.presentation.introScreens.model
+package com.geekymusketeers.uncrack.presentation.intro.model
import android.content.Context
import com.geekymusketeers.uncrack.R
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/ConfirmMasterKeyScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/ConfirmMasterKeyScreen.kt
new file mode 100644
index 00000000..ea937cd9
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/ConfirmMasterKeyScreen.kt
@@ -0,0 +1,107 @@
+package com.geekymusketeers.uncrack.presentation.masterKey
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import com.geekymusketeers.uncrack.R
+import com.geekymusketeers.uncrack.components.UCButton
+import com.geekymusketeers.uncrack.components.UCTextField
+import com.geekymusketeers.uncrack.ui.theme.bold30
+import com.geekymusketeers.uncrack.ui.theme.normal20
+import com.geekymusketeers.uncrack.viewModel.KeyViewModel
+
+@Composable
+fun ConfirmMasterKeyScreen(
+ navController: NavHostController,
+ masterKeyViewModel: KeyViewModel,
+ modifier: Modifier = Modifier
+) {
+
+
+ var confirmMasterKey by remember { mutableStateOf("") }
+
+ var passwordVisibility by remember { mutableStateOf(false) }
+
+ Scaffold(
+ modifier.fillMaxSize()
+ ) { paddingValues ->
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(paddingValues)
+ .padding(16.dp)
+ ) {
+ Text(
+ text = "Welcome Back",
+ style = bold30.copy(color = Color.Black)
+ )
+
+ Spacer(modifier = Modifier.height(10.dp))
+ Text(
+ text = "Kindly provide your Master Key",
+ style = normal20.copy(color = Color.Black)
+ )
+
+ Spacer(modifier = Modifier.height(50.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth(),
+ headerText = "Master Key",
+ hintText = "****************",
+ value = confirmMasterKey,
+ onValueChange = { confirmMasterKey = it },
+ visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+
+ val image = if (passwordVisibility)
+ painterResource(id = R.drawable.visibility_on)
+ else painterResource(id = R.drawable.visibility_off)
+
+ IconButton(onClick =
+ { passwordVisibility = passwordVisibility.not() }
+ ) {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = image,
+ contentDescription = null
+ )
+ }
+ }
+ )
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ UCButton(
+ modifier = Modifier
+ .fillMaxWidth(),
+ text = "Continue",
+ onClick = {
+ // TODO: Perform req operation
+ },
+ enabled = false
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/CreateMasterKeyScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/CreateMasterKeyScreen.kt
new file mode 100644
index 00000000..d8fcf401
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/CreateMasterKeyScreen.kt
@@ -0,0 +1,138 @@
+package com.geekymusketeers.uncrack.presentation.masterKey
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import com.geekymusketeers.uncrack.R
+import com.geekymusketeers.uncrack.components.UCButton
+import com.geekymusketeers.uncrack.components.UCTextField
+import com.geekymusketeers.uncrack.domain.model.Key
+import com.geekymusketeers.uncrack.ui.theme.bold30
+import com.geekymusketeers.uncrack.viewModel.KeyViewModel
+
+@Composable
+fun CreateMasterKeyScreen(
+ navController: NavHostController,
+ masterKeyViewModel: KeyViewModel,
+ modifier: Modifier = Modifier
+) {
+
+ val masterKeyObserver by masterKeyViewModel.masterKeyLiveData.observeAsState("")
+ val confirmMasterKeyObserver by masterKeyViewModel.confirmMasterKeyLiveData.observeAsState("")
+ val enableButtonObserver by masterKeyViewModel.enableButtonLiveData.observeAsState(false)
+ var passwordVisibility by remember { mutableStateOf(false) }
+
+
+ Scaffold(
+ modifier.fillMaxSize()
+ ) { paddingValues ->
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(paddingValues)
+ .padding(16.dp)
+ ) {
+ Text(
+ text = "Create Master Key",
+ style = bold30.copy(color = Color.Black)
+ )
+
+ Spacer(modifier = Modifier.height(50.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth(),
+ headerText = stringResource(id = R.string.master_key),
+ hintText = stringResource(id = R.string.password_hint),
+ value = masterKeyObserver,
+ onValueChange = {
+ masterKeyViewModel.setMasterKey(it)
+ },
+ visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+
+ val image = if (passwordVisibility)
+ painterResource(id = R.drawable.visibility_on)
+ else painterResource(id = R.drawable.visibility_off)
+
+ IconButton(onClick =
+ { passwordVisibility = passwordVisibility.not() }
+ ) {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = image,
+ contentDescription = null
+ )
+ }
+ }
+ )
+
+ Spacer(modifier = Modifier.height(30.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth(),
+ headerText = stringResource(id = R.string.confirm_master_key),
+ hintText = stringResource(id = R.string.password_hint),
+ value = confirmMasterKeyObserver,
+ onValueChange = {
+ masterKeyViewModel.setConfirmMasterKey(it)
+ },
+ visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+
+ val image = if (passwordVisibility)
+ painterResource(id = R.drawable.visibility_on)
+ else painterResource(id = R.drawable.visibility_off)
+
+ IconButton(onClick =
+ { passwordVisibility = passwordVisibility.not() }
+ ) {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = image,
+ contentDescription = null
+ )
+ }
+ }
+ )
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ UCButton(
+ modifier = Modifier
+ .fillMaxWidth(),
+ text = stringResource(R.string.save),
+ onClick = {
+ val key = Key(0,masterKeyObserver)
+ masterKeyViewModel.saveMasterKey(key)
+ navController.navigate("home_screen")
+ },
+ enabled = enableButtonObserver.not()
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/UpdateMasterKey.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/UpdateMasterKey.kt
new file mode 100644
index 00000000..6768a589
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/masterKey/UpdateMasterKey.kt
@@ -0,0 +1,177 @@
+package com.geekymusketeers.uncrack.presentation.masterKey
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import com.geekymusketeers.uncrack.R
+import com.geekymusketeers.uncrack.components.UCButton
+import com.geekymusketeers.uncrack.components.UCTextField
+import com.geekymusketeers.uncrack.components.UCTopAppBar
+import com.geekymusketeers.uncrack.ui.theme.BackgroundLight
+import com.geekymusketeers.uncrack.ui.theme.bold30
+import com.geekymusketeers.uncrack.viewModel.KeyViewModel
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun UpdateMasterKey(
+ navController: NavHostController,
+ masterKeyViewModel: KeyViewModel,
+ modifier: Modifier = Modifier
+) {
+
+
+ var oldMasterKey by remember {
+ mutableStateOf("")
+ }
+
+ var newMasterKey by remember {
+ mutableStateOf("")
+ }
+
+ var confirmMasterKey by remember {
+ mutableStateOf("")
+ }
+
+ var passwordVisibility by remember {
+ mutableStateOf(false)
+ }
+
+
+ Scaffold(
+ modifier.fillMaxSize(),
+ topBar = {
+ UCTopAppBar(
+ modifier = Modifier.fillMaxWidth(),
+ colors = TopAppBarDefaults.topAppBarColors(BackgroundLight),
+ onBackPress = { navController.popBackStack() }
+ )
+ }
+ ) { paddingValues ->
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(paddingValues)
+ .padding(16.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.update_master_key),
+ style = bold30.copy(color = Color.Black)
+ )
+
+ Spacer(modifier = Modifier.height(50.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth(),
+ headerText = stringResource(R.string.old_master_key),
+ hintText = stringResource(id = R.string.password_hint),
+ value = oldMasterKey,
+ onValueChange = { oldMasterKey = it },
+ visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+ val image = if (passwordVisibility)
+ painterResource(id = R.drawable.visibility_on)
+ else painterResource(id = R.drawable.visibility_off)
+
+ IconButton(onClick = { passwordVisibility = passwordVisibility.not() }
+ ) {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = image,
+ contentDescription = null
+ )
+ }
+ }
+ )
+
+ Spacer(modifier = Modifier.height(30.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth(),
+ headerText = stringResource(R.string.new_master_key),
+ hintText = stringResource(id = R.string.password_hint),
+ value = newMasterKey,
+ onValueChange = { newMasterKey = it },
+ visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+ val image = if (passwordVisibility)
+ painterResource(id = R.drawable.visibility_on)
+ else painterResource(id = R.drawable.visibility_off)
+
+ IconButton(onClick = { passwordVisibility = passwordVisibility.not() }
+ ) {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = image,
+ contentDescription = null
+ )
+ }
+ }
+ )
+
+ Spacer(modifier = Modifier.height(30.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth(),
+ headerText = stringResource(id = R.string.confirm_master_key),
+ hintText = stringResource(id = R.string.password_hint),
+ value = confirmMasterKey,
+ onValueChange = { confirmMasterKey = it },
+ visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+ val image = if (passwordVisibility)
+ painterResource(id = R.drawable.visibility_on)
+ else painterResource(id = R.drawable.visibility_off)
+
+ IconButton(onClick = { passwordVisibility = passwordVisibility.not() }
+ ) {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = image,
+ contentDescription = null
+ )
+ }
+ }
+ )
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ UCButton(
+ modifier = Modifier
+ .fillMaxWidth(),
+ text = stringResource(id = R.string.update),
+ onClick = {
+ // TODO: Perform req operation
+ },
+ enabled = false
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/passwordScreen/PasswordScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/password/PasswordScreen.kt
similarity index 56%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/passwordScreen/PasswordScreen.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/password/PasswordScreen.kt
index d019565c..9ed224b2 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/passwordScreen/PasswordScreen.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/password/PasswordScreen.kt
@@ -1,4 +1,4 @@
-package com.geekymusketeers.uncrack.presentation.passwordScreen
+package com.geekymusketeers.uncrack.presentation.password
import androidx.compose.runtime.Composable
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/profile/ProfileScreen.kt
new file mode 100644
index 00000000..f5b84e6b
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/profile/ProfileScreen.kt
@@ -0,0 +1,101 @@
+package com.geekymusketeers.uncrack.presentation.profile
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.geekymusketeers.uncrack.R
+import com.geekymusketeers.uncrack.components.ProfileContainer
+import com.geekymusketeers.uncrack.components.UCButton
+import com.geekymusketeers.uncrack.components.UCTextField
+import com.geekymusketeers.uncrack.components.UCTopAppBar
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun ProfileScreen(
+ modifier: Modifier = Modifier
+) {
+
+ Scaffold(
+ topBar = {
+ UCTopAppBar(
+ title = "Profile",
+ colors = TopAppBarDefaults.topAppBarColors(
+ Color.White
+ )
+ )
+ }
+ ) { paddingValues ->
+
+ Box(
+ modifier = modifier
+ .fillMaxSize()
+ .background(Color.White)
+ .padding(paddingValues)
+ .padding(bottom = 20.dp)
+ .imePadding()
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState()),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+
+ ProfileContainer {
+
+ }
+
+ Spacer(modifier = Modifier.height(20.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(20.dp, 0.dp),
+ headerText = "Name",
+ hintText = stringResource(id = R.string.name_hint),
+ value = "",
+ onValueChange = {}
+ )
+
+ Spacer(modifier = Modifier.height(20.dp))
+
+ UCTextField(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(20.dp, 0.dp),
+ headerText = "Email",
+ hintText = stringResource(id = R.string.email_hint),
+ value = "",
+ onValueChange = {}
+ )
+
+ Spacer(modifier = Modifier.weight(1f))
+
+ UCButton(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp,0.dp),
+ text = stringResource(id = R.string.save),
+ onClick = {}
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/profileScreen/ProfileScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/profileScreen/ProfileScreen.kt
deleted file mode 100644
index 166ae514..00000000
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/profileScreen/ProfileScreen.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.geekymusketeers.uncrack.presentation.profileScreen
-
-import androidx.compose.runtime.Composable
-
-@Composable
-fun ProfileScreen() {
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/presentation/shieldScreen/ShieldScreen.kt b/app/src/main/java/com/geekymusketeers/uncrack/presentation/shield/ShieldScreen.kt
similarity index 56%
rename from app/src/main/java/com/geekymusketeers/uncrack/presentation/shieldScreen/ShieldScreen.kt
rename to app/src/main/java/com/geekymusketeers/uncrack/presentation/shield/ShieldScreen.kt
index 603549c8..93c5edcf 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/presentation/shieldScreen/ShieldScreen.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/presentation/shield/ShieldScreen.kt
@@ -1,4 +1,4 @@
-package com.geekymusketeers.uncrack.presentation.shieldScreen
+package com.geekymusketeers.uncrack.presentation.shield
import androidx.compose.runtime.Composable
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/sharedViewModel/ThemeViewModel.kt b/app/src/main/java/com/geekymusketeers/uncrack/sharedViewModel/ThemeViewModel.kt
index b6f2001a..54d5ea10 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/sharedViewModel/ThemeViewModel.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/sharedViewModel/ThemeViewModel.kt
@@ -5,6 +5,9 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.geekymusketeers.uncrack.data.datastore.DataStoreUtil
import com.geekymusketeers.uncrack.data.datastore.DataStoreUtil.Companion.IS_DARK_MODE_KEY
+import com.geekymusketeers.uncrack.data.datastore.DataStoreUtil.Companion.IS_SS_BLOCK_KEY
+import com.geekymusketeers.uncrack.util.runIO
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -12,13 +15,14 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
-data class ThemeState(val isDarkMode: Boolean)
+data class ThemeState(val isDarkMode: Boolean, val isSsBlocked: Boolean)
+@HiltViewModel
class ThemeViewModel @Inject constructor(
dataStoreUtil: DataStoreUtil
): ViewModel() {
- private val _themeState = MutableStateFlow(ThemeState(false))
+ private val _themeState = MutableStateFlow(ThemeState(isDarkMode = false, isSsBlocked = false))
val themeState: StateFlow = _themeState
private val dataStore = dataStoreUtil.dataStore
@@ -26,7 +30,10 @@ class ThemeViewModel @Inject constructor(
init {
viewModelScope.launch(Dispatchers.IO) {
dataStore.data.map { preferences ->
- ThemeState(preferences[IS_DARK_MODE_KEY] ?: false)
+ ThemeState(
+ isDarkMode = preferences[IS_DARK_MODE_KEY] ?: false,
+ isSsBlocked = preferences[IS_SS_BLOCK_KEY] ?: false
+ )
}.collect {
_themeState.value = it
}
@@ -40,4 +47,10 @@ class ThemeViewModel @Inject constructor(
}
}
}
+
+ fun blockScreenShort() = runIO {
+ dataStore.edit { preferences ->
+ preferences[IS_SS_BLOCK_KEY] = !(preferences[IS_SS_BLOCK_KEY] ?: false)
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/LockMasterKeyFragment.kt b/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/LockMasterKeyFragment.kt
index 53550074..a506f1a8 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/LockMasterKeyFragment.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/LockMasterKeyFragment.kt
@@ -62,35 +62,35 @@ class LockMasterKeyFragment : Fragment() {
private fun clickHandlers() {
buttonLayout.setOnClickListener {
- checkKeyViewModel.getMasterKey().observe(viewLifecycleOwner) { key ->
- val inputMasterKey = binding.inputMasterKey.text.toString()
- showProgress()
- val encryption = Encryption.getDefault("Key", "Salt", ByteArray(16))
- val correctMasterKey = encryption.decryptOrNull(key[0].password)
- if (inputMasterKey.isEmpty() || inputMasterKey.isBlank()){
- binding.apply {
- inputMasterKeyHelperTV.text = getString(R.string.master_key_cannot_be_blank)
- inputMasterKeyHelperTV.visibility = View.VISIBLE
- }
- stopProgress()
- return@observe
- } else {
- if (inputMasterKey == correctMasterKey) {
- lifecycleScope.launch(Dispatchers.Main) {
- delay(1000L)
- goToMainActivity()
- }
- }
- else {
- binding.apply {
- inputMasterKeyHelperTV.text = getString(R.string.incorrect_password)
- inputMasterKeyHelperTV.visibility = View.VISIBLE
- }
- stopProgress()
- return@observe
- }
- }
- }
+// checkKeyViewModel.getMasterKey().observe(viewLifecycleOwner) { key ->
+// val inputMasterKey = binding.inputMasterKey.text.toString()
+// showProgress()
+// val encryption = Encryption.getDefault("Key", "Salt", ByteArray(16))
+// val correctMasterKey = encryption.decryptOrNull(key[0].password)
+// if (inputMasterKey.isEmpty() || inputMasterKey.isBlank()){
+// binding.apply {
+// inputMasterKeyHelperTV.text = getString(R.string.master_key_cannot_be_blank)
+// inputMasterKeyHelperTV.visibility = View.VISIBLE
+// }
+// stopProgress()
+// return@observe
+// } else {
+// if (inputMasterKey == correctMasterKey) {
+// lifecycleScope.launch(Dispatchers.Main) {
+// delay(1000L)
+// goToMainActivity()
+// }
+// }
+// else {
+// binding.apply {
+// inputMasterKeyHelperTV.text = getString(R.string.incorrect_password)
+// inputMasterKeyHelperTV.visibility = View.VISIBLE
+// }
+// stopProgress()
+// return@observe
+// }
+// }
+// }
}
binding.passwordToggle.setOnClickListener {
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/UpdateMasterKeyFragment.kt b/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/UpdateMasterKeyFragment.kt
index 48191810..96364395 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/UpdateMasterKeyFragment.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/ui/auth/master_key/UpdateMasterKeyFragment.kt
@@ -67,60 +67,60 @@ class UpdateMasterKeyFragment : Fragment() {
}
private fun clickHandlers() {
- buttonLayout.setOnClickListener {
- updateKeyViewModel.getMasterKey().observe(viewLifecycleOwner) {masterKey ->
-
- val oldMasterKey = binding.layoutOldMasterKey.text.toString()
- val updatedMasterKey = binding.layoutMasterKey.text.toString()
- val encryption = Encryption.getDefault("Key", "Salt", ByteArray(16))
- val correctOldMasterKey = encryption.decryptOrNull(masterKey[0].password)
- showProgress()
-
- if (oldMasterKey.isEmpty() || oldMasterKey.isBlank()) {
- binding.apply {
- oldMasterKeyHelperTV.text = getString(R.string.old_master_key_cannot_be_blank)
- oldMasterKeyHelperTV.visibility = View.VISIBLE
- }
- stopProgress()
- }
- else {
- if (oldMasterKey!=correctOldMasterKey){
- binding.apply {
- oldMasterKeyHelperTV.text = getString(R.string.old_master_key_is_incorrect)
- oldMasterKeyHelperTV.visibility = View.VISIBLE
- }
- stopProgress()
- }
- else {
- if (updatedMasterKey.isBlank() || updatedMasterKey.isEmpty()) {
- binding.apply {
- updatedMasterKeyHelperTV.text = getString(R.string.master_key_cannot_be_blank)
- updatedMasterKeyHelperTV.visibility = View.VISIBLE
- }
- stopProgress()
- }
- else {
- if (updatedMasterKey.length <= 5) {
- binding.apply {
- updatedMasterKeyHelperTV.text = getString(R.string.at_least_6_letter_long)
- updatedMasterKeyHelperTV.visibility = View.VISIBLE
- }
- stopProgress()
- }
- else {
- lifecycleScope.launch(Dispatchers.Main) {
- delay(800L)
- updateKey()
- Toast.makeText(requireContext(),"Successfully Updated the Master Key",Toast.LENGTH_SHORT).show()
- goToSecurityFragment()
- }
- }
- }
- }
- }
-
- }
- }
+// buttonLayout.setOnClickListener {
+// updateKeyViewModel.getMasterKey().observe(viewLifecycleOwner) {masterKey ->
+//
+// val oldMasterKey = binding.layoutOldMasterKey.text.toString()
+// val updatedMasterKey = binding.layoutMasterKey.text.toString()
+// val encryption = Encryption.getDefault("Key", "Salt", ByteArray(16))
+// val correctOldMasterKey = encryption.decryptOrNull(masterKey[0].password)
+// showProgress()
+//
+// if (oldMasterKey.isEmpty() || oldMasterKey.isBlank()) {
+// binding.apply {
+// oldMasterKeyHelperTV.text = getString(R.string.old_master_key_cannot_be_blank)
+// oldMasterKeyHelperTV.visibility = View.VISIBLE
+// }
+// stopProgress()
+// }
+// else {
+// if (oldMasterKey!=correctOldMasterKey){
+// binding.apply {
+// oldMasterKeyHelperTV.text = getString(R.string.old_master_key_is_incorrect)
+// oldMasterKeyHelperTV.visibility = View.VISIBLE
+// }
+// stopProgress()
+// }
+// else {
+// if (updatedMasterKey.isBlank() || updatedMasterKey.isEmpty()) {
+// binding.apply {
+// updatedMasterKeyHelperTV.text = getString(R.string.master_key_cannot_be_blank)
+// updatedMasterKeyHelperTV.visibility = View.VISIBLE
+// }
+// stopProgress()
+// }
+// else {
+// if (updatedMasterKey.length <= 5) {
+// binding.apply {
+// updatedMasterKeyHelperTV.text = getString(R.string.at_least_6_letter_long)
+// updatedMasterKeyHelperTV.visibility = View.VISIBLE
+// }
+// stopProgress()
+// }
+// else {
+// lifecycleScope.launch(Dispatchers.Main) {
+// delay(800L)
+// updateKey()
+// Toast.makeText(requireContext(),"Successfully Updated the Master Key",Toast.LENGTH_SHORT).show()
+// goToSecurityFragment()
+// }
+// }
+// }
+// }
+// }
+//
+// }
+// }
}
private fun goToSecurityFragment() {
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/ui/fragments/account/HomeFragment.kt b/app/src/main/java/com/geekymusketeers/uncrack/ui/fragments/account/HomeFragment.kt
index db8939d8..9977ceec 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/ui/fragments/account/HomeFragment.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/ui/fragments/account/HomeFragment.kt
@@ -267,21 +267,21 @@ class HomeFragment : Fragment() {
- viewModel = ViewModelProvider(this)[AccountViewModel::class.java]
- viewModel.readAllData.observe(viewLifecycleOwner) { account ->
-
-
- accountList.clear()
- accountList.addAll(account)
-
- accountAdapter.setData(account)
- if (account.isEmpty()) {
- binding.emptyList.visibility = View.VISIBLE
- } else {
- binding.emptyList.visibility = View.GONE
- }
-
- }
+// viewModel = ViewModelProvider(this)[AccountViewModel::class.java]
+// viewModel.getAccounts().observe(viewLifecycleOwner) { account ->
+//
+//
+// accountList.clear()
+// accountList.addAll(account)
+//
+// accountAdapter.setData(account)
+// if (account.isEmpty()) {
+// binding.emptyList.visibility = View.VISIBLE
+// } else {
+// binding.emptyList.visibility = View.GONE
+// }
+//
+// }
// Moving to AddFragment
binding.fab.setOnClickListener {
@@ -387,16 +387,16 @@ class HomeFragment : Fragment() {
}
- override fun onResume() {
- super.onResume()
- viewModel.readAllData.observe(viewLifecycleOwner) { account ->
- accountAdapter.setData(account)
- if (account.isEmpty()) {
- binding.emptyList.visibility = View.VISIBLE
- } else {
- binding.emptyList.visibility = View.GONE
- }
-
- }
- }
+// override fun onResume() {
+// super.onResume()
+// viewModel.readAllData.observe(viewLifecycleOwner) { account ->
+// accountAdapter.setData(account)
+// if (account.isEmpty()) {
+// binding.emptyList.visibility = View.VISIBLE
+// } else {
+// binding.emptyList.visibility = View.GONE
+// }
+//
+// }
+// }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/ui/splash_activity/SplashActivity.kt b/app/src/main/java/com/geekymusketeers/uncrack/ui/splash_activity/SplashActivity.kt
index e5d32eb9..6ce2dc7f 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/ui/splash_activity/SplashActivity.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/ui/splash_activity/SplashActivity.kt
@@ -12,7 +12,7 @@ import com.geekymusketeers.uncrack.databinding.ActivitySplashBinding
import com.geekymusketeers.uncrack.util.Util
import com.geekymusketeers.uncrack.ui.auth.MasterKeyActivity
import com.geekymusketeers.uncrack.viewModel.KeyViewModel
-import com.geekymusketeers.uncrack.viewModel.ViewModelFactory
+//import com.geekymusketeers.uncrack.viewModel.ViewModelFactory
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -25,7 +25,7 @@ class SplashActivity : AppCompatActivity() {
lateinit var binding: ActivitySplashBinding
private var cancellationSignal: CancellationSignal? = null
private lateinit var biometricPrompt: BiometricPrompt
- private val keyViewModel by viewModels { ViewModelFactory() }
+// private val keyViewModel by viewModels { ViewModelFactory() }
override fun onCreate(savedInstanceState: Bundle?) {
@@ -60,28 +60,28 @@ class SplashActivity : AppCompatActivity() {
}
private fun handleMasterKey() {
- keyViewModel.getMasterKey().observe(this) {
- when {
- it.isEmpty() -> {
- CoroutineScope(Dispatchers.Main).launch {
- delay(1000)
- val intent = Intent(this@SplashActivity, MasterKeyActivity::class.java)
- intent.putExtra("flow","createMasterKey")
- startActivity(intent)
- finish()
- }
- }
- else -> {
- CoroutineScope(Dispatchers.Main).launch {
- delay(1000)
- val intent = Intent(this@SplashActivity, MasterKeyActivity::class.java)
- intent.putExtra("flow","askForMasterKey")
- startActivity(intent)
- finish()
- }
- }
- }
- }
+// keyViewModel.getMasterKey().observe(this) {
+// when {
+// it.isEmpty() -> {
+// CoroutineScope(Dispatchers.Main).launch {
+// delay(1000)
+// val intent = Intent(this@SplashActivity, MasterKeyActivity::class.java)
+// intent.putExtra("flow","createMasterKey")
+// startActivity(intent)
+// finish()
+// }
+// }
+// else -> {
+// CoroutineScope(Dispatchers.Main).launch {
+// delay(1000)
+// val intent = Intent(this@SplashActivity, MasterKeyActivity::class.java)
+// intent.putExtra("flow","askForMasterKey")
+// startActivity(intent)
+// finish()
+// }
+// }
+// }
+// }
}
private fun showDialog() {
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/util/Constants.kt b/app/src/main/java/com/geekymusketeers/uncrack/util/Constants.kt
new file mode 100644
index 00000000..7948b6e6
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/util/Constants.kt
@@ -0,0 +1,11 @@
+package com.geekymusketeers.uncrack.util
+
+object Constants {
+
+ val sliderStepRange = 0f..32f
+ const val sliderSteps = 32
+ const val DEFAULT_PASSWORD_LENGTH = 12.0f
+ const val INVITE = """
+ Hey there! I've been using this amazing app and thought you might like it too! 😊 Check it out: https://play.google.com/store/apps/details?id=com.geekymusketeers.uncrack
+ """
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/util/ViewModelExtension.kt b/app/src/main/java/com/geekymusketeers/uncrack/util/ViewModelExtension.kt
new file mode 100644
index 00000000..17242c4c
--- /dev/null
+++ b/app/src/main/java/com/geekymusketeers/uncrack/util/ViewModelExtension.kt
@@ -0,0 +1,13 @@
+package com.geekymusketeers.uncrack.util
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+fun ViewModel.runIO(function: suspend CoroutineScope.() -> Unit) =
+ viewModelScope.launch(Dispatchers.IO) { function() }
+
+fun ViewModel.runDefault(function: suspend CoroutineScope.() -> Unit) =
+ viewModelScope.launch(Dispatchers.Default) { function() }
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/viewModel/AccountViewModel.kt b/app/src/main/java/com/geekymusketeers/uncrack/viewModel/AccountViewModel.kt
index 234bf0ce..08a1ff09 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/viewModel/AccountViewModel.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/viewModel/AccountViewModel.kt
@@ -1,45 +1,46 @@
package com.geekymusketeers.uncrack.viewModel
-import android.app.Application
-import androidx.lifecycle.AndroidViewModel
-import androidx.lifecycle.LiveData
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import com.geekymusketeers.uncrack.data.db.AccountDatabase
import com.geekymusketeers.uncrack.domain.model.Account
import com.geekymusketeers.uncrack.domain.repository.AccountRepository
+import com.geekymusketeers.uncrack.util.runIO
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
+import javax.inject.Inject
-class AccountViewModel(application: Application) : AndroidViewModel(application) {
+@HiltViewModel
+class AccountViewModel @Inject constructor(
+ private val repository: AccountRepository
+) : ViewModel() {
- val readAllData: LiveData>
- private val repository : AccountRepository
- init {
- val accountDao = AccountDatabase.getDatabase(application).accountDao()
- repository = AccountRepository(accountDao)
- readAllData = repository.readAllAccount
+ var accountModel by mutableStateOf(emptyList())
+
+ fun getAccounts() = runIO {
+ repository.getAllAccounts().collect { response ->
+ accountModel = response
+ }
}
- fun addAccount(account: Account){
+ fun addAccount(account: Account) {
viewModelScope.launch{
repository.addAccount(account)
}
}
- fun editAccount(account: Account){
+ fun editAccount(account: Account) {
viewModelScope.launch{
repository.editAccount(account)
}
}
- fun deleteAccount(account: Account){
+ fun deleteAccount(account: Account) {
viewModelScope.launch {
repository.deleteAccount(account)
}
}
- fun updateBookmark(account: Account) {
- viewModelScope.launch {
- repository.updateFavourite(account)
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/viewModel/KeyViewModel.kt b/app/src/main/java/com/geekymusketeers/uncrack/viewModel/KeyViewModel.kt
index 5b38509e..e48e187b 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/viewModel/KeyViewModel.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/viewModel/KeyViewModel.kt
@@ -1,44 +1,57 @@
package com.geekymusketeers.uncrack.viewModel
-import android.app.Application
-import androidx.lifecycle.AndroidViewModel
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.viewModelScope
+import androidx.lifecycle.ViewModel
import com.geekymusketeers.uncrack.domain.model.Key
import com.geekymusketeers.uncrack.domain.repository.KeyRepository
-import com.geekymusketeers.uncrack.data.db.KeyDatabase
-import kotlinx.coroutines.launch
+import com.geekymusketeers.uncrack.util.runIO
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
-class KeyViewModel(application: Application) : AndroidViewModel(application) {
+@HiltViewModel
+class KeyViewModel @Inject constructor(
+ private val repository: KeyRepository
+) : ViewModel() {
- private val keyRepository: KeyRepository
- private val masterKeyLiveData = MutableLiveData()
- private val confirmMasterKeyLiveData = MutableLiveData()
- val enableButtonLiveData = MutableLiveData()
+ var keyModel by mutableStateOf(emptyList())
- init {
- val keyDao = KeyDatabase.getDatabase(application).keyDao()
- keyRepository = KeyRepository(keyDao)
- }
+ private val _masterKeyLiveData = MutableLiveData()
+ val masterKeyLiveData: LiveData = _masterKeyLiveData
+
+ private val _confirmMasterKeyLiveData = MutableLiveData()
+ val confirmMasterKeyLiveData: LiveData = _confirmMasterKeyLiveData
+
+ private val _enableButtonLiveData = MutableLiveData()
+ val enableButtonLiveData: LiveData = _enableButtonLiveData
fun setMasterKey(masterKey: String) {
- masterKeyLiveData.value = masterKey
+ _masterKeyLiveData.value = masterKey
checkMasterKey()
}
fun setConfirmMasterKey(confirmMasterKey: String) {
- confirmMasterKeyLiveData.value = confirmMasterKey
+ _confirmMasterKeyLiveData.value = confirmMasterKey
checkMasterKey()
}
+
fun checkMasterKey() {
- enableButtonLiveData.value = !masterKeyLiveData.value.isNullOrBlank() && !confirmMasterKeyLiveData.value.isNullOrBlank() &&
- masterKeyLiveData.value == confirmMasterKeyLiveData.value
+ _enableButtonLiveData.value =
+ _masterKeyLiveData.value.isNullOrBlank()
+ .not() && _confirmMasterKeyLiveData.value.isNullOrBlank().not() &&
+ _masterKeyLiveData.value == _confirmMasterKeyLiveData.value
}
- fun saveMasterKey(key: Key){
- viewModelScope.launch {
- keyRepository.setMasterKey(key)
+
+ fun saveMasterKey(key: Key) = runIO {
+ repository.setMasterKey(key)
+ }
+
+ fun getMasterKey() = runIO {
+ repository.getMasterKey().collect { response ->
+ keyModel = response
}
}
- fun getMasterKey() : LiveData> = keyRepository.getMasterKey()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/geekymusketeers/uncrack/viewModel/ViewModelFactory.kt b/app/src/main/java/com/geekymusketeers/uncrack/viewModel/ViewModelFactory.kt
index 8d0c733e..cae13702 100644
--- a/app/src/main/java/com/geekymusketeers/uncrack/viewModel/ViewModelFactory.kt
+++ b/app/src/main/java/com/geekymusketeers/uncrack/viewModel/ViewModelFactory.kt
@@ -1,21 +1,21 @@
-package com.geekymusketeers.uncrack.viewModel
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.viewmodel.CreationExtras
-
-
-class ViewModelFactory : ViewModelProvider.Factory {
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class, extras: CreationExtras): T =
- with(modelClass) {
- // Get the Application object from extras
- val application = checkNotNull(extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY])
- when {
- isAssignableFrom(KeyViewModel::class.java) -> {
- KeyViewModel(application)
- }
- else -> throw IllegalArgumentException("Unknown ViewModel class")
- }
- } as T
-}
\ No newline at end of file
+//package com.geekymusketeers.uncrack.viewModel
+//
+//import androidx.lifecycle.ViewModel
+//import androidx.lifecycle.ViewModelProvider
+//import androidx.lifecycle.viewmodel.CreationExtras
+//
+//
+//class ViewModelFactory : ViewModelProvider.Factory {
+// @Suppress("UNCHECKED_CAST")
+// override fun create(modelClass: Class, extras: CreationExtras): T =
+// with(modelClass) {
+// // Get the Application object from extras
+// val application = checkNotNull(extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY])
+// when {
+// isAssignableFrom(KeyViewModel::class.java) -> {
+// KeyViewModel(application)
+// }
+// else -> throw IllegalArgumentException("Unknown ViewModel class")
+// }
+// } as T
+//}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/backup_restore.xml b/app/src/main/res/drawable/backup_restore.xml
new file mode 100644
index 00000000..767441a6
--- /dev/null
+++ b/app/src/main/res/drawable/backup_restore.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/block_ss.xml b/app/src/main/res/drawable/block_ss.xml
new file mode 100644
index 00000000..398aa40a
--- /dev/null
+++ b/app/src/main/res/drawable/block_ss.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/copy_password.xml b/app/src/main/res/drawable/copy_password.xml
new file mode 100644
index 00000000..95bafa83
--- /dev/null
+++ b/app/src/main/res/drawable/copy_password.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/delete_icon.xml b/app/src/main/res/drawable/delete_icon.xml
index 47a8f9c5..aabfca50 100644
--- a/app/src/main/res/drawable/delete_icon.xml
+++ b/app/src/main/res/drawable/delete_icon.xml
@@ -8,6 +8,6 @@
android:pathData="M0,0h24v24h-24z"/>
+ android:fillColor="#FF0000"/>
diff --git a/app/src/main/res/drawable/generate_password.xml b/app/src/main/res/drawable/generate_password.xml
new file mode 100644
index 00000000..4d0a6ece
--- /dev/null
+++ b/app/src/main/res/drawable/generate_password.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/import_export.xml b/app/src/main/res/drawable/import_export.xml
new file mode 100644
index 00000000..7a3a8b9c
--- /dev/null
+++ b/app/src/main/res/drawable/import_export.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/logout.xml b/app/src/main/res/drawable/logout.xml
new file mode 100644
index 00000000..b4e40835
--- /dev/null
+++ b/app/src/main/res/drawable/logout.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/no_user_profile_picture.xml b/app/src/main/res/drawable/no_user_profile_picture.xml
new file mode 100644
index 00000000..c03084a0
--- /dev/null
+++ b/app/src/main/res/drawable/no_user_profile_picture.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7fd8f4e5..86378a03 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -150,6 +150,9 @@
Register
Already have an account
Skip
+ Cancel
+ Are you sure you want to logout?
+ Logout?
Enter your email
johndoe123@gmail.com
Enter your password
@@ -159,6 +162,21 @@
Login
Don\'t have an account?
Create
+ By Aritra Das 💙
+ Save
+ Numbers
+ Uppercase letters
+ Lowercase letters
+ Special symbols
+ Include following:
+ Copy
+ Backup
+ General
+ Danger Zone
+ Update Master Key
+ Old Master Key
+ New Master Key
+ Password Length %1$s
- Others
- PayPal