From 445e130ebfa155fc618caefc5a5dee6ac41d1033 Mon Sep 17 00:00:00 2001 From: Agboola Onasanya Date: Mon, 28 Oct 2024 20:47:35 +0000 Subject: [PATCH] Migrate from Bucket --- app/.gitignore | 1 + app/build.gradle.kts | 131 ++++++++ app/google-services.json | 29 ++ app/proguard-rules.pro | 21 ++ .../tees/mywallet/ExampleInstrumentedTest.kt | 24 ++ app/src/main/AndroidManifest.xml | 37 +++ .../java/ica/tees/mywallet/MainActivity.kt | 30 ++ .../java/ica/tees/mywallet/MyWalletApp.kt | 41 +++ .../components/AppViewModelProvider.kt | 72 ++++ .../mywallet/components/MyWalletNavigation.kt | 187 +++++++++++ .../components/SystemBackButtonHandler.kt | 54 +++ .../tees/mywallet/components/UiComponents.kt | 307 ++++++++++++++++++ .../java/ica/tees/mywallet/data/ApiCalls.kt | 98 ++++++ .../ica/tees/mywallet/data/AppContainer.kt | 26 ++ .../java/ica/tees/mywallet/data/DataSource.kt | 297 +++++++++++++++++ .../mywallet/data/InputTransaformation.kt | 81 +++++ .../java/ica/tees/mywallet/data/Validator.kt | 61 ++++ .../java/ica/tees/mywallet/event/CardEvent.kt | 15 + .../ica/tees/mywallet/event/LoginEvent.kt | 9 + .../ica/tees/mywallet/event/PasswordEvent.kt | 10 + .../ica/tees/mywallet/event/SignUpEvent.kt | 11 + .../java/ica/tees/mywallet/model/CardModel.kt | 213 ++++++++++++ .../java/ica/tees/mywallet/model/HomeModel.kt | 35 ++ .../ica/tees/mywallet/model/LoginModel.kt | 117 +++++++ .../ica/tees/mywallet/model/PasswordModel.kt | 116 +++++++ .../ica/tees/mywallet/model/SignUpModel.kt | 138 ++++++++ .../ica/tees/mywallet/screen/AddCardScreen.kt | 226 +++++++++++++ .../tees/mywallet/screen/AddPasswordScreen.kt | 162 +++++++++ .../ica/tees/mywallet/screen/CardsScreen.kt | 222 +++++++++++++ .../ica/tees/mywallet/screen/HomeScreen.kt | 183 +++++++++++ .../ica/tees/mywallet/screen/LoginScreen.kt | 152 +++++++++ .../ica/tees/mywallet/screen/MainScreen.kt | 113 +++++++ .../tees/mywallet/screen/PasswordScreen.kt | 186 +++++++++++ .../ica/tees/mywallet/screen/SignUpScreen.kt | 174 ++++++++++ .../ica/tees/mywallet/state/CardUIState.kt | 18 + .../ica/tees/mywallet/state/LoginUIState.kt | 11 + .../tees/mywallet/state/PasswordUIState.kt | 13 + .../ica/tees/mywallet/state/SignUpUIState.kt | 14 + .../java/ica/tees/mywallet/ui/theme/Color.kt | 20 ++ .../java/ica/tees/mywallet/ui/theme/Theme.kt | 92 ++++++ .../java/ica/tees/mywallet/ui/theme/Type.kt | 34 ++ app/src/main/res/drawable/card_icon.png | Bin 0 -> 706 bytes app/src/main/res/drawable/eye_password.png | Bin 0 -> 666 bytes app/src/main/res/drawable/home.png | Bin 0 -> 886 bytes .../res/drawable/ic_launcher_background.xml | 170 ++++++++++ .../res/drawable/ic_launcher_foreground.xml | 30 ++ app/src/main/res/drawable/logo_mastercard.png | Bin 0 -> 2209 bytes app/src/main/res/drawable/logo_other.png | Bin 0 -> 1150 bytes app/src/main/res/drawable/logo_visa.png | Bin 0 -> 65057 bytes app/src/main/res/drawable/password.png | Bin 0 -> 882 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4014 bytes .../mipmap-hdpi/ic_launcher_background.png | Bin 0 -> 854 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 1874 bytes .../mipmap-hdpi/ic_launcher_monochrome.png | Bin 0 -> 1811 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2368 bytes .../mipmap-mdpi/ic_launcher_background.png | Bin 0 -> 462 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 876 bytes .../mipmap-mdpi/ic_launcher_monochrome.png | Bin 0 -> 846 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5150 bytes .../mipmap-xhdpi/ic_launcher_background.png | Bin 0 -> 1319 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 2547 bytes .../mipmap-xhdpi/ic_launcher_monochrome.png | Bin 0 -> 2539 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 9290 bytes .../mipmap-xxhdpi/ic_launcher_background.png | Bin 0 -> 2951 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 5221 bytes .../mipmap-xxhdpi/ic_launcher_monochrome.png | Bin 0 -> 5045 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 12432 bytes .../mipmap-xxxhdpi/ic_launcher_background.png | Bin 0 -> 4235 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 7404 bytes .../mipmap-xxxhdpi/ic_launcher_monochrome.png | Bin 0 -> 7332 bytes app/src/main/res/values/colors.xml | 10 + app/src/main/res/values/strings.xml | 25 ++ app/src/main/res/values/themes.xml | 6 + app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 ++ .../java/ica/tees/mywallet/ExampleUnitTest.kt | 17 + build.gradle.kts | 18 + gradle.properties | 23 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 +++++++++++ gradlew.bat | 89 +++++ settings.gradle.kts | 18 + 84 files changed, 4416 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/google-services.json create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/ica/tees/mywallet/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/ica/tees/mywallet/MainActivity.kt create mode 100644 app/src/main/java/ica/tees/mywallet/MyWalletApp.kt create mode 100644 app/src/main/java/ica/tees/mywallet/components/AppViewModelProvider.kt create mode 100644 app/src/main/java/ica/tees/mywallet/components/MyWalletNavigation.kt create mode 100644 app/src/main/java/ica/tees/mywallet/components/SystemBackButtonHandler.kt create mode 100644 app/src/main/java/ica/tees/mywallet/components/UiComponents.kt create mode 100644 app/src/main/java/ica/tees/mywallet/data/ApiCalls.kt create mode 100644 app/src/main/java/ica/tees/mywallet/data/AppContainer.kt create mode 100644 app/src/main/java/ica/tees/mywallet/data/DataSource.kt create mode 100644 app/src/main/java/ica/tees/mywallet/data/InputTransaformation.kt create mode 100644 app/src/main/java/ica/tees/mywallet/data/Validator.kt create mode 100644 app/src/main/java/ica/tees/mywallet/event/CardEvent.kt create mode 100644 app/src/main/java/ica/tees/mywallet/event/LoginEvent.kt create mode 100644 app/src/main/java/ica/tees/mywallet/event/PasswordEvent.kt create mode 100644 app/src/main/java/ica/tees/mywallet/event/SignUpEvent.kt create mode 100644 app/src/main/java/ica/tees/mywallet/model/CardModel.kt create mode 100644 app/src/main/java/ica/tees/mywallet/model/HomeModel.kt create mode 100644 app/src/main/java/ica/tees/mywallet/model/LoginModel.kt create mode 100644 app/src/main/java/ica/tees/mywallet/model/PasswordModel.kt create mode 100644 app/src/main/java/ica/tees/mywallet/model/SignUpModel.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/AddCardScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/AddPasswordScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/CardsScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/HomeScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/LoginScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/MainScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/PasswordScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/screen/SignUpScreen.kt create mode 100644 app/src/main/java/ica/tees/mywallet/state/CardUIState.kt create mode 100644 app/src/main/java/ica/tees/mywallet/state/LoginUIState.kt create mode 100644 app/src/main/java/ica/tees/mywallet/state/PasswordUIState.kt create mode 100644 app/src/main/java/ica/tees/mywallet/state/SignUpUIState.kt create mode 100644 app/src/main/java/ica/tees/mywallet/ui/theme/Color.kt create mode 100644 app/src/main/java/ica/tees/mywallet/ui/theme/Theme.kt create mode 100644 app/src/main/java/ica/tees/mywallet/ui/theme/Type.kt create mode 100644 app/src/main/res/drawable/card_icon.png create mode 100644 app/src/main/res/drawable/eye_password.png create mode 100644 app/src/main/res/drawable/home.png create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/logo_mastercard.png create mode 100644 app/src/main/res/drawable/logo_other.png create mode 100644 app/src/main/res/drawable/logo_visa.png create mode 100644 app/src/main/res/drawable/password.png create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/ica/tees/mywallet/ExampleUnitTest.kt create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..9f2719c --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,131 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("com.google.gms.google-services") + id("kotlin-android") + id("com.google.devtools.ksp") + +} + +android { + + configurations.all { + resolutionStrategy.dependencySubstitution { + substitute(module("org.hamcrest:hamcrest-core:1.1")).using(module("junit:junit:4.13.2")) + } + } + + namespace = "ica.tees.mywallet" + compileSdk = 34 + + defaultConfig { + applicationId = "ica.tees.mywallet" + minSdk = 24 +// targetSdk = 33 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + viewBinding = true + } + composeOptions { + kotlinCompilerExtensionVersion = "1.4.3" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } + + +} + + + +dependencies { + + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.10.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") + + implementation("androidx.core:core-ktx:1.12.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") + implementation("androidx.activity:activity-compose:1.8.1") + implementation(platform("androidx.compose:compose-bom:2023.10.01")) + implementation("androidx.compose.material:material-icons-extended-android:1.5.4") + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.ui:ui-graphics") + implementation("androidx.compose.ui:ui-tooling-preview") + implementation("androidx.compose.material3:material3") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01")) + androidTestImplementation("androidx.compose.ui:ui-test-junit4") + debugImplementation("androidx.compose.ui:ui-tooling") + debugImplementation("androidx.compose.ui:ui-test-manifest") + implementation("androidx.fragment:fragment-ktx:1.6.2") + + val nav_version = "2.7.5" + + implementation("androidx.navigation:navigation-compose:$nav_version") + implementation("androidx.navigation:navigation-fragment-ktx:$nav_version") + implementation("androidx.navigation:navigation-ui-ktx:$nav_version") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2") + + //firebase + implementation("com.google.firebase:firebase-firestore:24.10.0") + implementation(platform("com.google.firebase:firebase-bom:32.6.0")) + implementation("com.google.firebase:firebase-auth-ktx") + implementation("com.google.firebase:firebase-storage-ktx") + //authentication + + //Room + //noinspection GradleDependency + implementation("androidx.room:room-runtime:${rootProject.extra["room_version"]}") + implementation("androidx.core:core-ktx:1.12.0") + ksp("androidx.room:room-compiler:${rootProject.extra["room_version"]}") + //noinspection GradleDependency + implementation("androidx.room:room-ktx:${rootProject.extra["room_version"]}") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + + // define a BOM and its version + implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0")) + + // define any required OkHttp artifacts without version + implementation("com.squareup.okhttp3:okhttp") + implementation("com.squareup.okhttp3:logging-interceptor") + + implementation("com.googlecode.json-simple:json-simple:1.1.1") + +} + +//kapt { +// correctErrorTypes = true +//} diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..74d909a --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "841021611450", + "project_id": "thewallet-1d35d", + "storage_bucket": "thewallet-1d35d.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:841021611450:android:67f8db38bf46393e929183", + "android_client_info": { + "package_name": "ica.tees.mywallet" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyDrueny5znsdv6q5hLlhlF2ILenXRwJ5EE" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/ica/tees/mywallet/ExampleInstrumentedTest.kt b/app/src/androidTest/java/ica/tees/mywallet/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..f7b5cb0 --- /dev/null +++ b/app/src/androidTest/java/ica/tees/mywallet/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package ica.tees.mywallet + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("ica.tees.mywallet", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9d302be --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/MainActivity.kt b/app/src/main/java/ica/tees/mywallet/MainActivity.kt new file mode 100644 index 0000000..8689d2b --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/MainActivity.kt @@ -0,0 +1,30 @@ +package ica.tees.mywallet + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import ica.tees.mywallet.components.MyWallet +import ica.tees.mywallet.ui.theme.MyWalletTheme +import android.content.Intent +import android.net.Uri + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + MyWalletTheme { + MyWallet() + } + } + } +} + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + MyWalletTheme { + MyWallet() + } +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/MyWalletApp.kt b/app/src/main/java/ica/tees/mywallet/MyWalletApp.kt new file mode 100644 index 0000000..5708b4a --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/MyWalletApp.kt @@ -0,0 +1,41 @@ +package ica.tees.mywallet + +import android.app.Application +import com.google.firebase.Firebase +import com.google.firebase.FirebaseApp +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.firestore +import com.google.firebase.firestore.firestoreSettings +import com.google.firebase.firestore.memoryCacheSettings +import com.google.firebase.firestore.persistentCacheSettings +import ica.tees.mywallet.data.AppContainer +import ica.tees.mywallet.data.AppDataContainer + +class MyWalletApp : Application() { + + // var client = OkHttpClient() + lateinit var container: AppContainer + lateinit var auth: FirebaseAuth + lateinit var db: FirebaseFirestore + + val settings = firestoreSettings { + // Use memory cache + setLocalCacheSettings(memoryCacheSettings {}) + // Use persistent disk cache (default) + setLocalCacheSettings(persistentCacheSettings {}) + } + + + override fun onCreate() { + super.onCreate() + // client = OkHttpClient.Builder().build() + container = AppDataContainer(this) + auth = FirebaseAuth.getInstance() + db.firestoreSettings = settings + db = FirebaseFirestore.getInstance() + FirebaseApp.initializeApp(this) + + } +} + diff --git a/app/src/main/java/ica/tees/mywallet/components/AppViewModelProvider.kt b/app/src/main/java/ica/tees/mywallet/components/AppViewModelProvider.kt new file mode 100644 index 0000000..6fb6620 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/components/AppViewModelProvider.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ica.tees.mywallet.components + +import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory +import androidx.lifecycle.viewmodel.CreationExtras +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory +import ica.tees.mywallet.MyWalletApp +import ica.tees.mywallet.model.CardModel +import ica.tees.mywallet.model.HomeModel +import ica.tees.mywallet.model.LoginModel +import ica.tees.mywallet.model.PasswordModel +import ica.tees.mywallet.model.SignUpModel + + +object AppViewModelProvider { + val Factory = viewModelFactory { + initializer { + CardModel( + //this.createSavedStateHandle(), + myWalletApp().container.cardRepository + ) + } + + initializer { + PasswordModel( + myWalletApp().container.passwordRepository + ) + } + + initializer { + HomeModel( + myWalletApp().container.cardRepository, + myWalletApp().container.passwordRepository + ) + } + + initializer { + LoginModel( + myWalletApp().container.userRepository, + myWalletApp().auth + ) + } + + initializer { + SignUpModel( + myWalletApp().container.userRepository, + myWalletApp().db + ) + } + + } +} + + +fun CreationExtras.myWalletApp(): MyWalletApp = + (this[AndroidViewModelFactory.APPLICATION_KEY] as MyWalletApp) diff --git a/app/src/main/java/ica/tees/mywallet/components/MyWalletNavigation.kt b/app/src/main/java/ica/tees/mywallet/components/MyWalletNavigation.kt new file mode 100644 index 0000000..1339ddb --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/components/MyWalletNavigation.kt @@ -0,0 +1,187 @@ +package ica.tees.mywallet.components + +import androidx.annotation.StringRes +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import ica.tees.mywallet.data.Card +import ica.tees.mywallet.data.User +import ica.tees.mywallet.screen.AddCardScreen +import ica.tees.mywallet.screen.AddPasswordScreen +import ica.tees.mywallet.screen.CardsScreen +import ica.tees.mywallet.screen.LoginForm +import ica.tees.mywallet.screen.MainScreen +import ica.tees.mywallet.screen.PasswordScreen +import ica.tees.mywallet.screen.SignupForm + +@Composable +fun MyWallet( +) { + var returnValueNew by remember { mutableStateOf(false) } + var canNavigateBack by remember { mutableStateOf(false) } + val navController = rememberNavController() + var firstName by rememberSaveable { mutableStateOf("") } + var theName by rememberSaveable { mutableStateOf("") } + var showOnHome by rememberSaveable { mutableStateOf(false) } + + Scaffold( + + topBar = { + ScaffoldTopBar( + modifier = Modifier, + canNavigateBack = canNavigateBack, + navigateUp = { navController.navigateUp() }, + barText = firstName, + showOnHome = showOnHome + ) + } + ) { innerPadding -> + + NavHost( + navController = navController, + startDestination = MyWalletScreen.Login.name, + modifier = Modifier + .padding(innerPadding) + + ) { + composable(route = MyWalletScreen.Login.name) { + canNavigateBack = false + showOnHome = false + LoginForm( + modifier = Modifier, + navController = navController, + onButtonClicked = { userList: List -> + firstName = userList.first().firstName + theName = userList.first().userName + } + ) + } + composable(route = MyWalletScreen.SignUp.name) { + canNavigateBack = false + showOnHome = false + SignupForm( + modifier = Modifier, + navController = navController, + onButtonClicked = { returnValue: Boolean -> + returnValueNew = returnValue + if (returnValueNew) { + navController.navigate(route = MyWalletScreen.Login.name) + } + } + ) + } + composable(route = MyWalletScreen.Home.name) { + canNavigateBack = false + showOnHome = true + MainScreen( + modifier = Modifier, + navController = navController, + theName = theName + ) + } + composable(MyWalletScreen.Cards.name) { + canNavigateBack = false + showOnHome = true + CardsScreen( + modifier = Modifier, + navController = navController, + theName = theName + ) + } + composable(route = MyWalletScreen.Passwords.name) { + canNavigateBack = false + showOnHome = true + PasswordScreen( + modifier = Modifier, + navController = navController, + theName = theName + ) + } + composable(route = MyWalletScreen.AddCards.name) { + canNavigateBack = true + showOnHome = false + AddCardScreen( + modifier = Modifier, + navController = navController, + theName = theName, + ) + } + composable(route = MyWalletScreen.AddPasswords.name) { + canNavigateBack = true + showOnHome = false + AddPasswordScreen( + modifier = Modifier, + navController = navController, + theName = theName + ) + } + + } + } +} + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ScaffoldTopBar( + canNavigateBack: Boolean, + navigateUp: () -> Unit, + modifier: Modifier, + barText: String, + showOnHome: Boolean +) { + + TopAppBar( + + title = { + if (showOnHome) { + Text(text = "Welcome, $barText") + } + }, + colors = TopAppBarDefaults.mediumTopAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer + ), + modifier = modifier, + navigationIcon = { + if (canNavigateBack) { + IconButton(onClick = navigateUp) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Back" + ) + } + } + } + ) +} + + +enum class MyWalletScreen { + Login, + SignUp, + Home, + Cards, + AddCards, + Passwords, + AddPasswords, +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/components/SystemBackButtonHandler.kt b/app/src/main/java/ica/tees/mywallet/components/SystemBackButtonHandler.kt new file mode 100644 index 0000000..935ac65 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/components/SystemBackButtonHandler.kt @@ -0,0 +1,54 @@ +package ica.tees.mywallet.components + +import androidx.activity.ComponentActivity +import androidx.activity.OnBackPressedCallback +import androidx.activity.OnBackPressedDispatcherOwner +import androidx.compose.runtime.* +import androidx.compose.ui.platform.LocalLifecycleOwner + +private val LocalBackPressedDispatcher = + staticCompositionLocalOf { null } + + +private class ComposableBackNavigationHandler(enabled: Boolean) : OnBackPressedCallback(enabled) { + lateinit var onBackPressed: () -> Unit + + override fun handleOnBackPressed() { + onBackPressed() + } + +} + + +@Composable +internal fun ComposableHandler( + enabled: Boolean = true, + onBackPressed: () -> Unit +) { + val dispatcher = (LocalBackPressedDispatcher.current ?: return).onBackPressedDispatcher + + val handler = remember { ComposableBackNavigationHandler(enabled) } + + DisposableEffect(dispatcher) { + dispatcher.addCallback(handler) + + + onDispose { handler.remove() } + } + + LaunchedEffect(enabled) { + handler.isEnabled = enabled + handler.onBackPressed = onBackPressed + } +} + +@Composable +internal fun SystemBackButtonHandler(onBackPressed: () -> Unit) { + CompositionLocalProvider( + LocalBackPressedDispatcher provides LocalLifecycleOwner.current as ComponentActivity + ) { + ComposableHandler { + onBackPressed() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/components/UiComponents.kt b/app/src/main/java/ica/tees/mywallet/components/UiComponents.kt new file mode 100644 index 0000000..c4ef4c3 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/components/UiComponents.kt @@ -0,0 +1,307 @@ +package ica.tees.mywallet.components + +import androidx.annotation.StringRes +import androidx.compose.foundation.Image +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.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.ClickableText +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ElevatedCard +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +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.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import ica.tees.mywallet.data.Card +import ica.tees.mywallet.data.Password +import ica.tees.mywallet.ui.theme.Primary + + +@Composable +fun ClickableLoginTextComponent(tryingToLogin: Boolean = true, onTextSelected: (String) -> Unit) { + val initialText = + if (tryingToLogin) "Already have an account? " else "Don’t have an account yet? " + val loginText = if (tryingToLogin) "Login" else "Register" + + val annotatedString = buildAnnotatedString { + append(initialText) + withStyle(style = SpanStyle(color = Primary)) { + pushStringAnnotation(tag = loginText, annotation = loginText) + append(loginText) + } + } + + ClickableText( + modifier = Modifier + .fillMaxWidth() + .heightIn(min = 40.dp), + style = TextStyle( + fontSize = 21.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + textAlign = TextAlign.Center + ), + text = annotatedString, + onClick = { offset -> + + annotatedString.getStringAnnotations(offset, offset) + .firstOrNull()?.also { span -> + if (span.item == loginText) { + onTextSelected(span.item) + } + } + + }, + ) +} + +@Composable +fun TextFieldComponent( + value: String, + onValueChanged: (String) -> Unit, + @StringRes label: Int, + keyboardOptions: KeyboardOptions, + leadingIcon: ImageVector, + visualTransformation: VisualTransformation = VisualTransformation.None, + +) { + + TextField( + modifier = Modifier + .fillMaxWidth(), + value = value, + leadingIcon = { Icon(imageVector = leadingIcon, contentDescription = "") }, + onValueChange = onValueChanged, + visualTransformation = visualTransformation, + label = { Text(stringResource(label)) }, + singleLine = true, + keyboardOptions = keyboardOptions, + + ) +} + +@Composable +fun PasswordFieldComponent( + value: String, + onValueChanged: (String) -> Unit, + @StringRes label: Int, + keyboardOptions: KeyboardOptions, + leadingIcon: ImageVector +) { + + var passwordVisible by remember { mutableStateOf(false) } + + TextField( + modifier = Modifier + .fillMaxWidth(), + value = value, + onValueChange = onValueChanged, + label = { Text(stringResource(label)) }, + singleLine = true, + leadingIcon = { Icon(imageVector = leadingIcon, contentDescription = "") }, + keyboardOptions = keyboardOptions, + visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + val image = if (passwordVisible) + Icons.Filled.Visibility + else Icons.Filled.VisibilityOff + + // Localized description for accessibility services + val description = if (passwordVisible) "Hide password" else "Show password" + + // Toggle button to hide or display password + IconButton(onClick = { passwordVisible = !passwordVisible }) { + Icon(imageVector = image, description) + } + } + ) +} + + +@Composable +fun ButtonComponent( + modifier: Modifier, + onButtonClicked: () -> Unit = {}, + enabled: Boolean, + @StringRes buttonText: Int + +) { + + Button( + onClick = onButtonClicked, + shape = RoundedCornerShape(5.dp), + colors = ButtonDefaults.buttonColors(containerColor = Color(0xff9e9e9e)), + modifier = modifier + .fillMaxWidth(), + enabled = enabled + + ) { + + Text(text = stringResource(buttonText)) + } +} + + +@Composable +fun DisplayDialogCard( + showDialog: Boolean, + onDismissRequest: () -> Unit, + selectedIndex: Int, + modifier: Modifier, + cardsLists: List +) { + + if (showDialog) { + Dialog( + onDismissRequest = onDismissRequest, + properties = DialogProperties( + decorFitsSystemWindows = true, + usePlatformDefaultWidth = true + ) + + ) { +// (LocalView.current.parent as DialogWindowProvider)?.window?.setDimAmount(1f) + Card( + modifier = modifier + .fillMaxWidth() + .padding(1.dp), + ) { + Row { + Column { + ElevatedCard( + elevation = + CardDefaults.cardElevation( + defaultElevation = 15.dp + ), + modifier = modifier.size(width = 160.dp, height = 100.dp) + + + ) { + Image( + painter = painterResource(cardsLists[selectedIndex].cardType), + contentDescription = null, + modifier = modifier + .fillMaxWidth() + .size(width = 80.dp, height = 40.dp) + .padding(end = 10.dp, top = 5.dp) + .wrapContentWidth(Alignment.End) + ) + } + } + Spacer(modifier = Modifier.width(20.dp)) + Column { + Text( + text = cardsLists[selectedIndex].bankName, + fontWeight = FontWeight.Bold, + fontSize = 20.sp, + modifier = modifier + ) + Text( + text = cardsLists[selectedIndex].cardName + ) + Text( + text = cardsLists[selectedIndex].cardNumber + ) + Text( + text = cardsLists[selectedIndex].cardExpiry + ) + Text( + text = cardsLists[selectedIndex].cardSecurity + ) + } + } + } + } + } +} + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DisplayDialogPassword( + showDialog: Boolean, + onDismissRequest: () -> Unit, + selectedIndex: Int, + modifier: Modifier, + passwordLists: List +) { + + if (showDialog) { + + Dialog( + + onDismissRequest = onDismissRequest, + properties = DialogProperties( + decorFitsSystemWindows = true, + usePlatformDefaultWidth = true + ) + ) { + Card( + modifier = modifier + .fillMaxWidth() + .padding(1.dp), + + ) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Center + ) { + Text( + passwordLists[selectedIndex].accountName, + fontWeight = FontWeight.Bold + ) + SelectionContainer { + Column( + modifier = modifier + ) { + Text(text = passwordLists[selectedIndex].email) + Text(text = passwordLists[selectedIndex].password) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/data/ApiCalls.kt b/app/src/main/java/ica/tees/mywallet/data/ApiCalls.kt new file mode 100644 index 0000000..dd1b447 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/data/ApiCalls.kt @@ -0,0 +1,98 @@ +package ica.tees.mywallet.data + +import android.util.JsonReader +import android.util.Log +import androidx.annotation.StringRes +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import org.json.simple.JSONObject +import org.json.simple.parser.JSONParser +import java.net.SocketTimeoutException +import java.util.concurrent.TimeUnit + + +class ApiCalls { + + private val client = OkHttpClient.Builder() + .connectTimeout(5, TimeUnit.SECONDS) + .writeTimeout(1, TimeUnit.SECONDS) + .readTimeout(1, TimeUnit.SECONDS) + .build() + + private val errorMsg: JSONObject = JSONObject() + private var jsonReturnObject = JSONObject() + private var jsonHeaderObject = JSONObject() + private val jsonApiObject = JSONObject() + var response: Response? = null + + fun validateCard(cardNumber: String): JSONObject { + + errorMsg["code"] = "001" + errorMsg["valid"] = "false" + errorMsg["result"] = "No Result" + val errorMsgMain = JSONObject() + errorMsgMain["BIN"] = errorMsg + val apiEndPoint = "https://bin-ip-checker.p.rapidapi.com/?bin=" + val apiKey = "f5204a5f14msh4f6ce93e987ac89p10f514jsn1152d1ec2f1a" + + try { + + jsonApiObject.put("bin", cardNumber.substring(0, 6)) + + val mediaType = "application/json".toMediaTypeOrNull() + val body = jsonApiObject.toString().toRequestBody(mediaType) + val request = Request.Builder() + .url("${apiEndPoint}${cardNumber.substring(0, 6)}") + .post(body) + .addHeader("content-type", "application/json") + .addHeader("X-RapidAPI-Key", apiKey) + .addHeader("X-RapidAPI-Host", "bin-ip-checker.p.rapidapi.com") + .build() + + response = client.newCall(request).execute() +// Log.d("BANKNAME", response.body.toString()) +// jsonHeaderObject = JSONParser().parse( +// response?.body?.string() ?: errorMsgMain.toString() +// ) as JSONObject +// val code = jsonHeaderObject.get("code").toString() + + jsonReturnObject = JSONParser().parse(response?.body?.string() ?: errorMsgMain.toString()) as JSONObject +// Log.d("BANKNAME", jsonReturnObject.toJSONString()) + return jsonReturnObject + + } catch (exception: SocketTimeoutException) { + exception.localizedMessage + // jsonReturnObject = JSONParser().parse(response?.body?.string() ?: errorMsgMain.toString()) as JSONObject + return errorMsgMain + } + + } +} + +//sealed class UiText { +// +// data class StringValue(val str: String) : UiText() +// +// class StringResource( +// @StringRes val resourceId: Int, +// vararg val args: Any +// ) : UiText() +// +// @Composable +// fun asString(): String { +// return when (this) { +// is StringValue -> { +// str +// } +// +// is StringResource -> { +// stringResource(id = resourceId, formatArgs = args) +// } +// } +// } +//} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/data/AppContainer.kt b/app/src/main/java/ica/tees/mywallet/data/AppContainer.kt new file mode 100644 index 0000000..54fb2c4 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/data/AppContainer.kt @@ -0,0 +1,26 @@ +package ica.tees.mywallet.data + +import android.content.Context + +interface AppContainer { + + val cardRepository: CardRepository + val passwordRepository: PasswordRepository + val userRepository: UserRepository +} + +class AppDataContainer(private val context: Context) : AppContainer { + + override val cardRepository: CardRepository by lazy { + OfflineCardRepository(MyWalletDatabase.getDatabase(context).CardDao()) + } + + override val passwordRepository: PasswordRepository by lazy { + OfflinePasswordRepository(MyWalletDatabase.getDatabase(context).PasswordDao()) + } + + override val userRepository: UserRepository by lazy { + OfflineUserRepository(MyWalletDatabase.getDatabase(context).UserDao()) + } + +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/data/DataSource.kt b/app/src/main/java/ica/tees/mywallet/data/DataSource.kt new file mode 100644 index 0000000..7a457ab --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/data/DataSource.kt @@ -0,0 +1,297 @@ +package ica.tees.mywallet.data + +import android.content.Context +import androidx.room.Dao +import androidx.room.Database +import androidx.room.Delete +import androidx.room.Entity +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.PrimaryKey +import androidx.room.Query +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.Update +import ica.tees.mywallet.R +import kotlinx.coroutines.flow.Flow +import java.util.Currency +import java.util.UUID + +data class TabItem( + val title: String, + val unselectedIcon: Int, + val selectedIcon: Int +) + +private fun menuList(): MutableList { + + val menus: MutableList = mutableListOf() + for (i in menuName.indices) { + menus.add(TabItem(menuName[i], menuImage[i], menuImage[i])) + } + return menus +} + +private val menuName = listOf( + "Home", + "Cards", + "Passwords" +) + +private val menuImage = listOf( + + R.drawable.home, + R.drawable.card_icon, + R.drawable.password +) + + +object DataSource { + val tabItem = menuList() +} + + +enum class FieldType { + EXPIRATION, + CARD_NUMBER +} + +////DATABASE RELATED ITEMS +//DATABASE +@Database( + entities = [Card::class, Password::class, + User::class], + version = 1, + exportSchema = false +) +abstract class MyWalletDatabase : RoomDatabase() { + + abstract fun PasswordDao(): PasswordDao + abstract fun CardDao(): CardDao + abstract fun UserDao(): UserDao + + companion object { + + @Volatile + private var Instance: MyWalletDatabase? = null + + fun getDatabase(context: Context): MyWalletDatabase { + + return Instance ?: synchronized(this) { + + Room.databaseBuilder(context, MyWalletDatabase::class.java, "wallet_database") + .fallbackToDestructiveMigration() + .build() + .also { Instance = it } + } + } + } +} +//DATABASE + +//ENTITY +@Entity(tableName = "card") +data class Card( + @PrimaryKey + val id: UUID, + val count: Int, + val cardName: String, + val cardNumber: String, + val cardSecurity: String, + val cardExpiry: String, + val bankName: String, + val cardType: Int, + val userName: String, + val currency: String +) + +@Entity(tableName = "password") +data class Password( + @PrimaryKey + val id: UUID, + val count: Int, + val accountName: String, + val email: String, + val password: String, + val userName: String, +) + +@Entity(tableName = "user") +data class User( + @PrimaryKey + val id: UUID, + val firstName: String, + val lastName: String, + val userName: String, +) +//ENTITY + + +//DAO +@Dao +interface CardDao { + + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insert(cards: Card) + + @Update + suspend fun update(cards: Card) + + @Delete + suspend fun delete(cards: Card) + + @Query("SELECT * FROM card WHERE id = :id") + fun findById(id: UUID): Flow> + + @Query("SELECT * from card WHERE count > 0 AND userName = :userName ORDER BY count DESC LIMIT 1") + fun getTopCard(userName: String): Flow> + + @Query("SELECT * FROM card ORDER BY bankName ASC") + fun getAllCards(): Flow> + + @Query("SELECT * FROM card ORDER BY cardName ASC") + fun getUserCard(): Flow> +} + +@Dao +interface PasswordDao { + + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insert(passwords: Password) + + @Update + suspend fun update(passwords: Password) + + @Delete + fun delete(passwords: Password) + + @Query("SELECT * FROM password WHERE id = :id") + fun findById(id: UUID): Flow> + + @Query("SELECT * from password WHERE count > 0 AND userName = :userName ORDER BY count DESC LIMIT 5") + fun getTopPassword(userName: String): Flow> + + @Query("SELECT * FROM password ORDER BY accountName ASC") + fun getAllPasswords(): Flow> + + @Query("SELECT * FROM password ORDER BY accountName ASC") + fun getUserPassword(): Flow> +} + +@Dao +interface UserDao { + + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insert(user: User) + + @Update + suspend fun update(user: User) + + @Delete + suspend fun delete(user: User) + + @Query("SELECT * FROM user WHERE userName = :userName") + fun findByUser(userName: String): Flow> +} +//DAO + + +//REPO +interface CardRepository { + + fun getAllItemsStream(): Flow> + + fun getItemStream(id: UUID): Flow> + + fun getTopCard(userName: String): Flow> + + fun getUserCard(): Flow> + + suspend fun insertItem(cards: Card) + + suspend fun deleteItem(cards: Card) + + suspend fun updateItem(cards: Card) + +} + + +interface PasswordRepository { + + fun getAllItemsStream(): Flow> + + fun getItemStream(id: UUID): Flow> + + fun getTopPassword(userName: String): Flow> + + fun getUserPassword(): Flow> + + suspend fun insertItem(passwords: Password) + + suspend fun deleteItem(passwords: Password) + + suspend fun updateItem(passwords: Password) + +} + +interface UserRepository { + + suspend fun insertItem(user: User) + + suspend fun deleteItem(user: User) + + suspend fun updateItem(user: User) + + fun getUserByName(userName: String): Flow> + +} +//REPO + + +//OFFLINE REPO +class OfflineUserRepository(private val userDao: UserDao) : UserRepository { + + override suspend fun insertItem(user: User) = userDao.insert(user) + + override suspend fun deleteItem(user: User) = userDao.delete(user) + + override suspend fun updateItem(user: User) = userDao.update(user) + + override fun getUserByName(userName: String): Flow> = userDao.findByUser(userName) +} + + +class OfflineCardRepository(private val cardsDao: CardDao) : CardRepository { + override fun getAllItemsStream(): Flow> = cardsDao.getAllCards() + + override fun getItemStream(id: UUID): Flow> = cardsDao.findById(id) + + override fun getTopCard(userName: String): Flow> = cardsDao.getTopCard(userName) + + override fun getUserCard(): Flow> = cardsDao.getUserCard() + + override suspend fun insertItem(cards: Card) = cardsDao.insert(cards) + + override suspend fun deleteItem(cards: Card) = cardsDao.delete(cards) + + override suspend fun updateItem(cards: Card) = cardsDao.update(cards) + +} + +class OfflinePasswordRepository(private val passwordsDao: PasswordDao) : PasswordRepository { + override fun getAllItemsStream(): Flow> = passwordsDao.getAllPasswords() + + override fun getTopPassword(userName: String): Flow> = passwordsDao.getTopPassword(userName) + + override fun getUserPassword(): Flow> = passwordsDao.getUserPassword() + + override fun getItemStream(id: UUID): Flow> = passwordsDao.findById(id) + + override suspend fun insertItem(passwords: Password) = passwordsDao.insert(passwords) + + override suspend fun deleteItem(passwords: Password) = passwordsDao.delete(passwords) + + override suspend fun updateItem(passwords: Password) = passwordsDao.update(passwords) + +} +//OFFLINE REPO \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/data/InputTransaformation.kt b/app/src/main/java/ica/tees/mywallet/data/InputTransaformation.kt new file mode 100644 index 0000000..95ebfb9 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/data/InputTransaformation.kt @@ -0,0 +1,81 @@ +package ica.tees.mywallet.data + +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.input.OffsetMapping +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation + +class InputTransaformation(private val fieldType: FieldType) : VisualTransformation { + + override fun filter(text: AnnotatedString): TransformedText = when(fieldType) { + FieldType.EXPIRATION -> expirationFilter(text) + FieldType.CARD_NUMBER -> cardNumberFilter(text) + } + + private fun expirationFilter(text: AnnotatedString): TransformedText { + val trimmed = if(text.text.length >= 4) text.text.substring(0..3) else text.text + var out = "" + + for(i in trimmed.indices) { + out += trimmed[i] + if(i == 1) out += "/" // Adding slash after second character + } + + val offsetTranslator = object: OffsetMapping { + override fun originalToTransformed(offset: Int): Int { + if(offset <= 1) return offset // From 0 to 1, offset doesn't change + if(offset <= 4) return offset + 1 // From 2 to 4, offset take into account the added slash + return 5 + } + + override fun transformedToOriginal(offset: Int): Int { + if(offset <= 2) return offset + if(offset <= 5) return offset - 1 + return 4 + } + } + + return TransformedText( + AnnotatedString(out), + offsetTranslator + ) + } + + /** + * Convert the input of cardNumber field to "xxxx xxxx xxxx xxxx" format + */ + private fun cardNumberFilter(text: AnnotatedString): TransformedText { + val trimmer = if(text.text.length >= 16) text.text.substring(0..15) else text.text + var out = "" + + for(i in trimmer.indices) { + out += trimmer[i] + if(i == 3) out += " " + if(i == 7) out += " " + if(i == 11) out += " " + } + + val offsetTranslator = object: OffsetMapping { + override fun originalToTransformed(offset: Int): Int { + if(offset <= 3) return offset + if(offset <= 7) return offset + 1 + if(offset <= 11) return offset + 2 + if(offset <= 16) return offset + 3 + return 19 + } + + override fun transformedToOriginal(offset: Int): Int { + if(offset <= 4) return offset + if(offset <= 8) return offset - 1 + if(offset <= 12) return offset - 2 + if(offset <= 17) return offset - 3 + return 16 + } + } + + return TransformedText( + AnnotatedString(out), + offsetTranslator + ) + } +} diff --git a/app/src/main/java/ica/tees/mywallet/data/Validator.kt b/app/src/main/java/ica/tees/mywallet/data/Validator.kt new file mode 100644 index 0000000..559120b --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/data/Validator.kt @@ -0,0 +1,61 @@ +package ica.tees.mywallet.data + +object Validator { + fun validateFirstName(fName: String): ValidationResult { + return ValidationResult( + (fName.isNotEmpty() && fName.length >= 2) + ) + } + + fun validateLastName(lName: String): ValidationResult { + return ValidationResult( + (lName.isNotEmpty() && lName.length >= 2) + ) + } + + fun validateName(name: String): ValidationResult { + return ValidationResult( + (name.isNotEmpty() && name.length >= 3) + ) + } + + fun validateEmail(email: String): ValidationResult { + return ValidationResult( + (email.isNotEmpty()) + ) + } + + fun validatePassword(password: String): ValidationResult { + return ValidationResult( + (password.isNotEmpty() && password.length >= 4) + ) + } + + fun validateCardNumber(cardNumber: String): ValidationResult { + return ValidationResult( + (cardNumber.isNotEmpty() && cardNumber.length == 16) + ) + } + + fun validateCvv(cvv: String): ValidationResult { + return ValidationResult( + (cvv.isNotEmpty() && cvv.length == 3) + ) + } + + fun validateExpiry(expiry: String): ValidationResult { + return ValidationResult( + (expiry.isNotEmpty() && expiry.length >= 4) + ) + } + + fun validateBankName(bank: String): ValidationResult { + return ValidationResult( + (bank.isNotEmpty() && bank.length >= 2) + ) + } +} + +data class ValidationResult( + val status: Boolean = false +) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/event/CardEvent.kt b/app/src/main/java/ica/tees/mywallet/event/CardEvent.kt new file mode 100644 index 0000000..c923d43 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/event/CardEvent.kt @@ -0,0 +1,15 @@ +package ica.tees.mywallet.event + +sealed class CardEvent { + + data class CardNumberChanged(val cardNumber: String) : CardEvent() + data class CardSecurity(val cardSecurity: String) : CardEvent() + data class CardNameChanged(val cardName: String) : CardEvent() + data class CardExpiryChanged(val cardExpiry: String) : CardEvent() + data class BankNameChanged(val bankName: String) : CardEvent() + data class CurrencyChanged(val currency: String): CardEvent() + data class CardTypeChanged(val cardType: String): CardEvent() + data class UserNameOnInitialise(val userName: String) : CardEvent() + object CardButtonClicked : CardEvent() + +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/event/LoginEvent.kt b/app/src/main/java/ica/tees/mywallet/event/LoginEvent.kt new file mode 100644 index 0000000..5649a80 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/event/LoginEvent.kt @@ -0,0 +1,9 @@ +package ica.tees.mywallet.event + +sealed class LoginEvent { + + data class EmailChanged(val email: String) : LoginEvent() + data class PasswordChanged(val password: String) : LoginEvent() + object LoginButtonClicked : LoginEvent() + +} diff --git a/app/src/main/java/ica/tees/mywallet/event/PasswordEvent.kt b/app/src/main/java/ica/tees/mywallet/event/PasswordEvent.kt new file mode 100644 index 0000000..1044903 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/event/PasswordEvent.kt @@ -0,0 +1,10 @@ +package ica.tees.mywallet.event + +sealed class PasswordEvent { + + data class EmailChanged(val email: String) : PasswordEvent() + data class PasswordChanged(val password: String) : PasswordEvent() + data class AccountNameChanged(val accountName: String) : PasswordEvent() + object PasswordButtonClicked : PasswordEvent() + +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/event/SignUpEvent.kt b/app/src/main/java/ica/tees/mywallet/event/SignUpEvent.kt new file mode 100644 index 0000000..165a954 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/event/SignUpEvent.kt @@ -0,0 +1,11 @@ +package ica.tees.mywallet.event + +sealed class SignUpEvent { + + data class FirstNameChanged(val firstName: String) : SignUpEvent() + data class LastNameChanged(val lastName: String) : SignUpEvent() + data class EmailChanged(val email: String) : SignUpEvent() + data class PasswordChanged(val password: String) : SignUpEvent() + object SignUpButtonClicked : SignUpEvent() + +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/model/CardModel.kt b/app/src/main/java/ica/tees/mywallet/model/CardModel.kt new file mode 100644 index 0000000..1e2bb39 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/model/CardModel.kt @@ -0,0 +1,213 @@ +package ica.tees.mywallet.model + +import android.os.StrictMode +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import ica.tees.mywallet.R +import ica.tees.mywallet.data.ApiCalls +import ica.tees.mywallet.data.Card +import ica.tees.mywallet.data.CardRepository +import ica.tees.mywallet.data.Validator +import ica.tees.mywallet.event.CardEvent +import ica.tees.mywallet.state.CardUIState +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import org.json.simple.JSONObject +import java.util.UUID + +class CardModel( + // savedStateHandle: SavedStateHandle, + private val cardsRepository: CardRepository +) : ViewModel() { + + + var jsonObject = JSONObject() + var cardUIState = MutableStateFlow(CardUIState()) + var _uiState: StateFlow = cardUIState.asStateFlow() + val cardDataList: StateFlow = + cardsRepository.getUserCard().map { CardsList(it) }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000L), + initialValue = CardsList() + ) + + var allValidationPassed = mutableStateOf(false) + + fun onEvent(event: CardEvent) { + when (event) { + is CardEvent.UserNameOnInitialise -> { + + cardUIState.value.userName = event.userName + + cardUIState.value = cardUIState.value.copy( + userName = event.userName + ) + } + + is CardEvent.CardNumberChanged -> { + cardUIState.value = cardUIState.value.copy( + cardNumber = event.cardNumber + ) + } + + is CardEvent.CardExpiryChanged -> { + cardUIState.value = cardUIState.value.copy( + cardExpiry = event.cardExpiry + ) + } + + is CardEvent.CardSecurity -> { + cardUIState.value = cardUIState.value.copy( + cardSecurity = event.cardSecurity + ) + } + + is CardEvent.BankNameChanged -> { + cardUIState.value = cardUIState.value.copy( + bankName = event.bankName + ) + } + + is CardEvent.CardNameChanged -> { + cardUIState.value = cardUIState.value.copy( + cardName = event.cardName + ) + } + + is CardEvent.CurrencyChanged -> { + cardUIState.value = cardUIState.value.copy( + currency = event.currency + ) + } + + is CardEvent.CardTypeChanged -> { + cardUIState.value = cardUIState.value.copy( + cardType = event.cardType + ) + } + + is CardEvent.CardButtonClicked -> { + viewModelScope.launch { + addCard() + } + } + } + validateAddCardUIDataWithRules() + } + + private fun validateAddCardUIDataWithRules() { + val cardNumberResult = Validator.validateCardNumber( + cardNumber = cardUIState.value.cardNumber + ) + + val bankNameResult = Validator.validateBankName( + bank = cardUIState.value.bankName + ) + + val cardNameResult = Validator.validateName( + name = cardUIState.value.cardName + ) + + val cvvResult = Validator.validateCvv( + cvv = cardUIState.value.cardSecurity + ) + + val expiryResult = Validator.validateExpiry( + expiry = cardUIState.value.cardExpiry + ) + + cardUIState.value = cardUIState.value.copy( + cardNumberError = cardNumberResult.status, + bankNameError = bankNameResult.status, + cardNameError = cardNameResult.status, + cardSecurityError = cvvResult.status, + cardExpiryError = expiryResult.status, + + ) + + allValidationPassed.value = + cardNumberResult.status && bankNameResult.status && cardNameResult.status && cvvResult.status && expiryResult.status + + } + + private fun addCard() { + + val cardImage = + when (cardUIState.value.cardType) { + "MASTERCARD" -> R.drawable.logo_mastercard + "VISA" -> R.drawable.logo_visa + else -> R.drawable.logo_other + } + + val uuid = UUID.randomUUID() + viewModelScope.launch { + cardsRepository.insertItem( + cards = Card( + uuid, + 0, + cardUIState.value.cardName, + cardUIState.value.cardNumber, + cardUIState.value.cardSecurity, + cardUIState.value.cardExpiry, + cardUIState.value.bankName, + cardImage, + cardUIState.value.userName, + cardUIState.value.currency + ) + ) + } + } + + fun validateCard(): String { + + val policy = StrictMode.ThreadPolicy.Builder().permitAll().build() + StrictMode.setThreadPolicy(policy) + + jsonObject = ApiCalls().validateCard(cardUIState.value.cardNumber) + val code = jsonObject.get("code").toString() + + if (code.startsWith("200")) { + + var bin: JSONObject? = jsonObject.get("BIN") as JSONObject + var issuer: JSONObject? = bin?.get("issuer") as JSONObject + var bankName = issuer?.get("name").toString() + var brand = bin.get("brand").toString() + var currency = bin.get("currency").toString() + + return bankName + "|" + brand + "|" + currency + } else { + + return "||" + } + + } + + suspend fun updateCard(card: Card) { + + val newCount = card.count + 1 + val newCard = Card( + card.id, newCount, card.cardName, + card.cardNumber, card.cardSecurity, card.cardExpiry, + card.bankName, card.cardType, card.userName, card.currency + ) + + cardsRepository.updateItem(newCard) + } +} + +data class CardsList(val cardList: List = listOf()) + + +// fun cardDataList(userName: String): StateFlow = +// cardsRepository.getUserCard(userName).map { CardsList(it) }.stateIn( +// scope = viewModelScope, +// started = SharingStarted.WhileSubscribed(5_000L), +// initialValue = CardsList() +// ) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/model/HomeModel.kt b/app/src/main/java/ica/tees/mywallet/model/HomeModel.kt new file mode 100644 index 0000000..c06eb43 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/model/HomeModel.kt @@ -0,0 +1,35 @@ +package ica.tees.mywallet.model + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import ica.tees.mywallet.data.Card +import ica.tees.mywallet.data.CardRepository +import ica.tees.mywallet.data.Password +import ica.tees.mywallet.data.PasswordRepository +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +class HomeModel( + private val cardRepository: CardRepository, + private val passwordRepository: PasswordRepository +) : ViewModel() { + + fun cardDataList(userName: String): StateFlow = + cardRepository.getTopCard(userName).map { CardsListHome(it) }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000L), + initialValue = CardsListHome() + ) + + fun passwordDataList(userName: String): StateFlow = + passwordRepository.getTopPassword(userName).map { PasswordListHome(it) }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000L), + initialValue = PasswordListHome() + ) +} + +data class PasswordListHome(val passwordList: List = listOf()) +data class CardsListHome(val cardsList: List = listOf()) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/model/LoginModel.kt b/app/src/main/java/ica/tees/mywallet/model/LoginModel.kt new file mode 100644 index 0000000..83b03dd --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/model/LoginModel.kt @@ -0,0 +1,117 @@ +package ica.tees.mywallet.model + +import android.util.Log +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.google.firebase.auth.FirebaseAuth +import ica.tees.mywallet.data.User +import ica.tees.mywallet.data.UserRepository +import ica.tees.mywallet.data.Validator +import ica.tees.mywallet.event.LoginEvent +import ica.tees.mywallet.state.LoginUIState +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +class LoginModel( + private val userRepository: UserRepository, + private val auth: FirebaseAuth +) : ViewModel() { + + // var loginStatus: MutableLiveData = MutableLiveData() + val loginUIState = mutableStateOf(LoginUIState()) + var allValidationsPassed = mutableStateOf(false) + var loginInProgress = mutableStateOf(false) + var loginStatus by mutableStateOf(false) + var failureMessage = mutableStateOf("") + + var userList: StateFlow = MutableStateFlow(UserList()) + + fun onEvent(event: LoginEvent) { + when (event) { + is LoginEvent.EmailChanged -> { + loginUIState.value = loginUIState.value.copy( + email = event.email + ) + } + + is LoginEvent.PasswordChanged -> { + loginUIState.value = loginUIState.value.copy( + password = event.password + ) + } + + is LoginEvent.LoginButtonClicked -> { + login(email = loginUIState.value.email, password = loginUIState.value.password) + } + } + validateLoginUIDataWithRules() + } + + + private fun validateLoginUIDataWithRules() { + val emailResult = Validator.validateEmail( + email = loginUIState.value.email + ) + + val passwordResult = Validator.validatePassword( + password = loginUIState.value.password + ) + + loginUIState.value = loginUIState.value.copy( + emailError = emailResult.status, passwordError = passwordResult.status + ) + + allValidationsPassed.value = emailResult.status && passwordResult.status + } + + private fun login(email: String, password: String) { + + loginInProgress.value = true + + auth + .signInWithEmailAndPassword(email, password) + .addOnSuccessListener { + loginStatus = true + loginInProgress.value = false + failureMessage.value = "" + Log.d("LoginModel - Success", loginStatus.toString()) + loginStatus = true + } + .addOnFailureListener { + + loginStatus = false + loginInProgress.value = false + failureMessage.value = it.localizedMessage ?: "No Error" + Log.d("LoginModel - Failure", loginStatus.toString()) + } +// .addOnCompleteListener { +// loginInProgress.value = false +// +// +// if (it.isSuccessful) { +// loginStatus.value = true +// failureMessage.value = "" +// } else { +// loginStatus.value = false +// failureMessage.value = it.exception?.localizedMessage ?: "No Error" +// +// } +// } + + userList = userRepository.getUserByName(loginUIState.value.email).map { UserList(it) } + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000L), + initialValue = UserList() + ) + } + +} + +data class UserList(val userList: List = listOf()) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/model/PasswordModel.kt b/app/src/main/java/ica/tees/mywallet/model/PasswordModel.kt new file mode 100644 index 0000000..718311b --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/model/PasswordModel.kt @@ -0,0 +1,116 @@ +package ica.tees.mywallet.model + +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import ica.tees.mywallet.data.Card +import ica.tees.mywallet.data.Password +import ica.tees.mywallet.data.PasswordRepository +import ica.tees.mywallet.data.Validator +import ica.tees.mywallet.event.PasswordEvent +import ica.tees.mywallet.state.CardUIState +import ica.tees.mywallet.state.PasswordUIState +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import java.util.UUID + +class PasswordModel(private val passwordRepository: PasswordRepository) : ViewModel() { + + var passwordUIState = MutableStateFlow(PasswordUIState()) + var _uiState: StateFlow = passwordUIState.asStateFlow() + + var allValidationsPassed = mutableStateOf(false) + val passwordDataList: StateFlow = + passwordRepository.getUserPassword().map { PasswordList(it) }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000L), + initialValue = PasswordList() + ) + + suspend fun onEvent(event: PasswordEvent) { + + when (event) { + + is PasswordEvent.PasswordChanged -> { + passwordUIState.value = passwordUIState.value.copy( + password = event.password + ) + } + + is PasswordEvent.AccountNameChanged -> { + passwordUIState.value = passwordUIState.value.copy( + accountName = event.accountName + ) + } + + is PasswordEvent.EmailChanged -> { + + passwordUIState.value = passwordUIState.value.copy( + email = event.email + ) + } + + is PasswordEvent.PasswordButtonClicked -> { + addPassword() + } + } + validateLoginUIDataWithRules() + + } + + private fun validateLoginUIDataWithRules() { + val emailResult = Validator.validateEmail( + email = passwordUIState.value.email + ) + + val passwordResult = Validator.validatePassword( + password = passwordUIState.value.password + ) + + val accountNameResult = Validator.validateName( + name = passwordUIState.value.accountName + ) + + passwordUIState.value = passwordUIState.value.copy( + emailError = emailResult.status, + passwordError = passwordResult.status, + accountError = accountNameResult.status + ) + + allValidationsPassed.value = + emailResult.status && passwordResult.status && accountNameResult.status + } + + private suspend fun addPassword() { + + val uuid = UUID.randomUUID() + passwordRepository.insertItem( + passwords = Password( + uuid, + 0, + passwordUIState.value.accountName, + passwordUIState.value.email, + passwordUIState.value.password, + passwordUIState.value.userName + ) + ) + } + + suspend fun updateCard(password: Password) { + + val newCount = password.count + 1 + val newPassword = Password( + password.id, newCount, password.accountName, + password.email, password.password, password.userName + ) + + passwordRepository.updateItem(newPassword) + } +} + + +data class PasswordList(val passwordList: List = listOf()) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/model/SignUpModel.kt b/app/src/main/java/ica/tees/mywallet/model/SignUpModel.kt new file mode 100644 index 0000000..203f86c --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/model/SignUpModel.kt @@ -0,0 +1,138 @@ +package ica.tees.mywallet.model + +import android.util.Log +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.google.firebase.Firebase +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.firestore +import ica.tees.mywallet.data.User +import ica.tees.mywallet.data.UserRepository +import ica.tees.mywallet.data.Validator +import ica.tees.mywallet.event.SignUpEvent +import ica.tees.mywallet.state.SignUpUIState +import kotlinx.coroutines.launch +import java.util.UUID + +class SignUpModel( + private val userRepository: UserRepository, + private val db: FirebaseFirestore, +) : ViewModel() { + + val adb = Firebase.firestore + var signUpUIState = mutableStateOf(SignUpUIState()) + var signUpStatus = mutableStateOf(false) + var allValidationsPassed = mutableStateOf(false) + var failureMessage = mutableStateOf("") + + suspend fun onEvent(event: SignUpEvent) { + + when (event) { + + is SignUpEvent.EmailChanged -> { + signUpUIState.value = signUpUIState.value.copy( + email = event.email + ) + } + + is SignUpEvent.FirstNameChanged -> { + signUpUIState.value = signUpUIState.value.copy( + firstName = event.firstName + ) + } + + is SignUpEvent.LastNameChanged -> { + signUpUIState.value = signUpUIState.value.copy( + lastName = event.lastName + ) + } + + is SignUpEvent.PasswordChanged -> { + signUpUIState.value = signUpUIState.value.copy( + password = event.password + ) + } + + SignUpEvent.SignUpButtonClicked -> { + createUser() + } + } + validateLoginUIDataWithRules() + } + + private fun validateLoginUIDataWithRules() { + val emailResult = Validator.validateEmail( + email = signUpUIState.value.email + ) + + val passwordResult = Validator.validatePassword( + password = signUpUIState.value.password + ) + + val firstNameResult = Validator.validateFirstName( + fName = signUpUIState.value.firstName + ) + + val lastNameResult = Validator.validateLastName( + lName = signUpUIState.value.lastName + ) + + signUpUIState.value = signUpUIState.value.copy( + emailError = emailResult.status, + passwordError = passwordResult.status, + firstNameError = firstNameResult.status, + lastNameError = lastNameResult.status, + ) + + allValidationsPassed.value = + emailResult.status && passwordResult.status && firstNameResult.status && lastNameResult.status + } + + private suspend fun createUser() { + + val email = signUpUIState.value.email + val password = signUpUIState.value.password + + FirebaseAuth + .getInstance() + .createUserWithEmailAndPassword(email, password) + .addOnCompleteListener { it -> + + if (it.isSuccessful) { + signUpStatus.value = true + //viewModelScope.launch { + if (signUpStatus.value) { + + //adb.collection() + adb.collection("myWallet/users") + .add(hashMapOf( + "id" to UUID.randomUUID().toString(), + "firstName" to signUpUIState.value.firstName, + "lastName" to signUpUIState.value.lastName, + "email" to signUpUIState.value.email + )) + + .addOnSuccessListener { + Log.d("SIGNUP",it.id) + } + .addOnFailureListener{ + it -> + it.localizedMessage?.let { it1 -> Log.d("SIGNUP", it1) } + } +// userRepository.insertItem( +// user = User( +// UUID.randomUUID(), +// signUpUIState.value.firstName, +// signUpUIState.value.lastName, +// signUpUIState.value.email +// ) +// ) + // } + } + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/screen/AddCardScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/AddCardScreen.kt new file mode 100644 index 0000000..88834e5 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/AddCardScreen.kt @@ -0,0 +1,226 @@ +package ica.tees.mywallet.screen + +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.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CurrencyExchange +import androidx.compose.material.icons.filled.DateRange +import androidx.compose.material.icons.filled.Face +import androidx.compose.material.icons.filled.Money +import androidx.compose.material.icons.filled.Numbers +import androidx.compose.material3.Button +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.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardCapitalization +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import ica.tees.mywallet.R +import ica.tees.mywallet.components.AppViewModelProvider +import ica.tees.mywallet.components.TextFieldComponent +import ica.tees.mywallet.data.FieldType +import ica.tees.mywallet.data.InputTransaformation +import ica.tees.mywallet.event.CardEvent +import ica.tees.mywallet.model.CardModel +import kotlinx.coroutines.launch + +@Composable +fun AddCardScreen( + modifier: Modifier, + navController: NavHostController, + theName: String, + cardModel: CardModel = viewModel(factory = AppViewModelProvider.Factory) +) { + + val coroutineScope = rememberCoroutineScope() + var bankName by remember { mutableStateOf("") } + var nameOnCard by remember { mutableStateOf("") } + var cardNumber by remember { mutableStateOf("") } + var expiryDate by remember { mutableStateOf("") } + var cvv by remember { mutableStateOf("") } + var currency by remember { mutableStateOf("") } + + Column( + modifier = modifier + .fillMaxSize() + .padding(20.dp), + ) { + + Spacer(modifier = Modifier.height(50.dp)) + Text( + text = "Kindly Enter Card Detail", + fontSize = 20.sp, + modifier = modifier + .fillMaxWidth() + ) + Spacer(modifier = modifier.height(10.dp)) + Column( + modifier = modifier + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + TextFieldComponent( + value = cardNumber, + visualTransformation = InputTransaformation(FieldType.CARD_NUMBER), + onValueChanged = { + coroutineScope.launch { + cardModel.onEvent(CardEvent.CardNumberChanged(it)) + cardNumber = it + if (cardNumber.length == 6) { + val returnVal: String? = cardModel.validateCard() + val bankNameNull: String? = returnVal?.split("|")?.get(0) + val currencyNull: String? = returnVal?.split("|")?.get(2) + val brandNull: String? = returnVal?.split("|")?.get(1) + if (bankNameNull != null) { + cardModel.onEvent(CardEvent.BankNameChanged(bankNameNull)) + bankName = bankNameNull + } + if (currencyNull != null) { + cardModel.onEvent(CardEvent.CurrencyChanged(currencyNull)) + currency = currencyNull + } + if (brandNull != null) { + cardModel.onEvent(CardEvent.CardTypeChanged(brandNull)) + } + } + } + }, + label = R.string.card_number, + leadingIcon = Icons.Default.Numbers, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Number, + imeAction = if (cardNumber.length == 16) ImeAction.Next else ImeAction.None + ), + ) + Spacer(modifier = modifier.height(10.dp)) + TextFieldComponent( + value = bankName, + onValueChanged = { + coroutineScope.launch { + cardModel.onEvent(CardEvent.BankNameChanged(it)) + bankName = it + } + }, + label = R.string.bank_name, + leadingIcon = Icons.Default.Money, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Text, + imeAction = if (cardNumber.length >= 3) ImeAction.Next else ImeAction.None + ), + ) + Spacer(modifier = modifier.height(10.dp)) + TextFieldComponent( + value = currency, + onValueChanged = { + coroutineScope.launch { + cardModel.onEvent(CardEvent.CurrencyChanged(it)) + currency = it + } + }, + label = R.string.currency, + leadingIcon = Icons.Default.CurrencyExchange, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Text, + capitalization = KeyboardCapitalization.Characters, + imeAction = if (cardNumber.length >= 3) ImeAction.Next else ImeAction.None + ), + ) + Spacer(modifier = modifier.height(10.dp)) + TextFieldComponent( + value = nameOnCard, + onValueChanged = { + coroutineScope.launch { + cardModel.onEvent(CardEvent.CardNameChanged(it)) + nameOnCard = it + } + }, + label = R.string.name_on_card, + leadingIcon = Icons.Default.Face, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Text, + capitalization = KeyboardCapitalization.Characters, + imeAction = if (cardNumber.length >= 3) ImeAction.Next else ImeAction.None + ), + + ) + Spacer(modifier = modifier.height(10.dp)) + TextFieldComponent( + value = expiryDate, + visualTransformation = InputTransaformation(FieldType.EXPIRATION), + onValueChanged = { + coroutineScope.launch { + cardModel.onEvent(CardEvent.CardExpiryChanged(it)) + expiryDate = it + } + }, + label = R.string.expiry_date, + leadingIcon = Icons.Default.DateRange, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Number, + imeAction = if (expiryDate.length == 4) ImeAction.Next else ImeAction.None + ) + ) + Spacer(modifier = modifier.height(10.dp)) + TextFieldComponent( + value = cvv, + onValueChanged = { + coroutineScope.launch { + cardModel.onEvent(CardEvent.CardSecurity(it)) + cvv = it + } + }, + label = R.string.cvv, + leadingIcon = Icons.Default.Numbers, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Number, + imeAction = if (cvv.length == 3) ImeAction.Done else ImeAction.None + ), + ) + Spacer(modifier = modifier.height(50.dp)) + Button( + onClick = { + coroutineScope.launch { + cardModel._uiState.value.userName = theName + cardModel.onEvent(CardEvent.CardButtonClicked) + navController.navigateUp() + } + }, + enabled = cardModel.allValidationPassed.value, + modifier = modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp) + ) /**/{ + Text(text = stringResource(R.string.add_card)) + } + } + } +} + + +@Preview +@Composable +fun AddCardScreenPreview() { + AddCardScreen( + modifier = Modifier, + navController = rememberNavController(), + "" + ) +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/screen/AddPasswordScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/AddPasswordScreen.kt new file mode 100644 index 0000000..b261282 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/AddPasswordScreen.kt @@ -0,0 +1,162 @@ +package ica.tees.mywallet.screen + +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.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AlternateEmail +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Email +import androidx.compose.material.icons.filled.Face +import androidx.compose.material.icons.filled.Password +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import ica.tees.mywallet.R +import ica.tees.mywallet.components.AppViewModelProvider +import ica.tees.mywallet.components.PasswordFieldComponent +import ica.tees.mywallet.components.TextFieldComponent +import ica.tees.mywallet.event.LoginEvent +import ica.tees.mywallet.event.PasswordEvent +import ica.tees.mywallet.model.CardModel +import ica.tees.mywallet.model.PasswordModel +import kotlinx.coroutines.launch + +class AddPassword { +} + +@Composable +fun AddPasswordScreen( + modifier: Modifier, + navController: NavHostController, + theName: String, + passwordModel: PasswordModel = viewModel(factory = AppViewModelProvider.Factory) +) { + + val coroutineScope = rememberCoroutineScope() + var accountName by remember { mutableStateOf("") } + var accountLogin by remember { mutableStateOf("") } + var accountPassword by remember { mutableStateOf("") } + + Column( + modifier = modifier + .fillMaxSize() + .padding(20.dp), + ) { + + Spacer(modifier = modifier.height(50.dp)) + Text( + text = "Kindly Enter Account Detail", + fontSize = 20.sp, + modifier = modifier + .fillMaxWidth() + + ) + Spacer(modifier = modifier.height(10.dp)) + Column( + modifier = modifier + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + TextFieldComponent( + value = accountName, + onValueChanged = { + coroutineScope.launch { + passwordModel.onEvent(PasswordEvent.AccountNameChanged(it)) + accountName = it + } + }, + label = R.string.account_name, + leadingIcon = Icons.Default.Face, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next + ) + ) + Spacer(modifier = modifier.height(10.dp)) + TextFieldComponent( + value = accountLogin, + onValueChanged = { + coroutineScope.launch { + passwordModel.onEvent(PasswordEvent.EmailChanged(it)) + accountLogin = it + } + }, + label = R.string.enter_your_email, + leadingIcon = Icons.Default.AlternateEmail, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next + ) + ) + Spacer(modifier = modifier.height(10.dp)) + PasswordFieldComponent( + value = accountPassword, + onValueChanged = { + coroutineScope.launch { + passwordModel.onEvent(PasswordEvent.PasswordChanged(it)) + accountPassword = it + } + }, + label = R.string.account_password, + leadingIcon = Icons.Default.Password, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Done + ) + ) + Spacer(modifier = modifier.height(50.dp)) + Button( + onClick = { + coroutineScope.launch { + passwordModel._uiState.value.userName = theName + passwordModel.onEvent(PasswordEvent.PasswordButtonClicked) + navController.navigateUp() + } + }, + enabled = passwordModel.allValidationsPassed.value, + modifier = modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp) + ) /**/{ + Text(text = stringResource(R.string.add_password)) + } + } + } + +} + +@Preview +@Composable +private fun AppPasswordScreenPreview() { + var navController = rememberNavController() + + AddPasswordScreen(Modifier, navController,"") +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/screen/CardsScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/CardsScreen.kt new file mode 100644 index 0000000..f83f3a5 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/CardsScreen.kt @@ -0,0 +1,222 @@ +package ica.tees.mywallet.screen + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +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.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ElevatedButton +import androidx.compose.material3.ElevatedCard +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import ica.tees.mywallet.components.AppViewModelProvider +import ica.tees.mywallet.components.DisplayDialogCard +import ica.tees.mywallet.components.MyWalletScreen +import ica.tees.mywallet.data.Card +import ica.tees.mywallet.model.CardModel +import ica.tees.mywallet.model.LoginModel +import ica.tees.mywallet.state.CardUIState +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch + +@Composable +fun CardsScreen( + modifier: Modifier, + navController: NavHostController, + theName: String, + cardModel: CardModel = viewModel(factory = AppViewModelProvider.Factory), +) { + + val uiState by cardModel._uiState.collectAsState() + uiState.userName = theName + val cardList by cardModel.cardDataList.collectAsState() + + val state = rememberLazyListState() + var showDialog by remember { mutableStateOf(false) } + var selectedIndex by remember { mutableIntStateOf(0) } + + Column( + modifier = modifier + .padding(start = 20.dp) + .fillMaxSize() + ) { + Spacer(modifier = modifier.height(50.dp)) + DisplayDialogCard( + showDialog = showDialog, + modifier = modifier, + onDismissRequest = { showDialog = !showDialog }, + selectedIndex = selectedIndex, + cardsLists = cardList.cardList + ) + CardList( + modifier = modifier, + state = state, + onClick = { showDialogClicked: Boolean, selectedIndexClicked: Int -> + showDialog = showDialogClicked + selectedIndex = selectedIndexClicked + }, + cardsLists = cardList.cardList, + theName = theName, + cardModel = cardModel + ) + + } + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.End, + modifier = modifier + .fillMaxSize() + .padding(bottom = 10.dp,end = 10.dp) + + ) { + + ElevatedButton( + onClick = { + navController.navigate(route = MyWalletScreen.AddCards.name) + }, + shape = CircleShape, + modifier = modifier + .size(70.dp) + ) { + Icon( + Icons.Filled.Add, + contentDescription = null, + modifier = modifier.size(ButtonDefaults.IconSize) + ) + } + } +} + +@Composable +fun CardList( + modifier: Modifier, + onClick: (Boolean, Int) -> Unit, + state: LazyListState, + cardsLists: List, + theName: String, + cardModel: CardModel +) { + + val coroutineScope = rememberCoroutineScope() + var selectedValue by remember { mutableIntStateOf(0) } + val isSelected by remember { mutableStateOf(true) } + + if (cardsLists.isNotEmpty()) { + LazyColumn( + state = state, + contentPadding = PaddingValues(top = 10.dp, bottom = 10.dp), + verticalArrangement = Arrangement.spacedBy(10.dp), + + ) { + itemsIndexed(cardsLists) { index, item -> + if (item.userName == theName) { + Row( + modifier = Modifier + + ) { + Column { + ElevatedCard( + modifier = modifier + .size(width = 120.dp, height = 80.dp) + .selectable( + selected = selectedValue == index, + enabled = true, + onClick = { + coroutineScope.launch { + selectedValue = index + onClick(isSelected, index) + cardModel.updateCard(item) + } + }) + .clickable(enabled = true, onClick = { + coroutineScope.launch { + selectedValue = index + onClick(isSelected, index) + cardModel.updateCard(item) + } + }), + elevation = CardDefaults.cardElevation( + defaultElevation = 15.dp + ), + ) { + Image( + painter = painterResource(item.cardType), + contentDescription = null, + modifier = modifier + .fillMaxWidth() + .size(width = 80.dp, height = 40.dp) + .padding(end = 10.dp, top = 5.dp) + .wrapContentWidth(Alignment.End) + ) + } + } + Spacer(modifier = Modifier.width(20.dp)) + Column { + Text( + text = item.bankName, + fontWeight = FontWeight.Bold, + fontSize = 20.sp, + modifier = modifier + ) + Text( + text = item.cardNumber.replaceRange(0, 12, "**** **** **** ") + ) + } + } + } + } + } + } else { + + Text(text = "No Cards Added") + } +} + +@Preview +@Composable +fun CardsScreenPreview() { + + val navController = rememberNavController() + CardsScreen( + modifier = Modifier, navController, "" + ) +} diff --git a/app/src/main/java/ica/tees/mywallet/screen/HomeScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/HomeScreen.kt new file mode 100644 index 0000000..0229744 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/HomeScreen.kt @@ -0,0 +1,183 @@ +package ica.tees.mywallet.screen + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxWithConstraints +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.layout.requiredHeight +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Divider +import androidx.compose.material3.ElevatedCard +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +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.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import ica.tees.mywallet.components.AppViewModelProvider +import ica.tees.mywallet.data.Card +import ica.tees.mywallet.data.Password +import ica.tees.mywallet.model.HomeModel + + +@Composable +fun HomeScreen( + modifier: Modifier, + theName: String, + homeModel: HomeModel = viewModel(factory = AppViewModelProvider.Factory) +) { + + val cardList by homeModel.cardDataList(theName).collectAsState() + val passwordList by homeModel.passwordDataList(theName).collectAsState() + + Column( + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + .fillMaxSize() + ) { + Spacer(modifier = modifier.height(50.dp)) + BoxWithConstraints { + CardViewHomePage( + modifier = modifier, + card = cardList.cardsList + ) + + } + Spacer(modifier.height(80.dp)) + BoxWithConstraints { + PasswordViewHomePage( + modifier = modifier, + passwords = passwordList.passwordList + ) + } + + + } +} + +@Composable +fun CardViewHomePage( + modifier: Modifier, + card: List +) { + + var showDialog by remember { mutableStateOf(false) } + + if (card.isNotEmpty()) { + ElevatedCard( + content = { + Row( + modifier = modifier + .padding(20.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = card[0].cardNumber, + fontSize = 20.sp + ) + Image( + painter = painterResource(card[0].cardType), + contentDescription = null, + modifier = modifier + .fillMaxWidth() + .wrapContentWidth(Alignment.End) + .requiredWidth(80.dp) + .requiredHeight(40.dp) + ) + } + Text( + text = card[0].cardName, + fontSize = 25.sp, + modifier = modifier + .padding(start = 20.dp) + ) + Row( + modifier = modifier + .padding(start = 20.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = card[0].cardExpiry, + fontSize = 20.sp + ) + Text( + text = card[0].cardSecurity, + fontSize = 20.sp, + modifier = modifier + .fillMaxWidth() + .padding(end = 20.dp) + .wrapContentWidth(Alignment.End) + ) + } + }, + modifier = modifier + .requiredWidth(width = 340.dp) + .requiredHeight(height = 170.dp) + .clip(shape = RoundedCornerShape(20.dp)) + + ) + } else { + + Text(text = "No Cards") + } +} + + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun PasswordViewHomePage( + modifier: Modifier, + passwords: List +) { + + if (passwords.isNotEmpty()) { + LazyColumn( + state = rememberLazyListState(), + //verticalArrangement = Arrangement.SpaceBetween, + modifier = modifier + .padding(20.dp) + .fillMaxSize(), + ) { + items(passwords) { passwords -> + Text(passwords.accountName) + Text(passwords.email) + Divider(thickness = 1.dp) + } + } + } else { + Text(text = "No Passwords") + } +} + + +@Preview(widthDp = 360, heightDp = 800) +@Composable +private fun HomePagePreview() { + + // HomeScreen(Modifier,"",) +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/screen/LoginScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/LoginScreen.kt new file mode 100644 index 0000000..47f01bf --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/LoginScreen.kt @@ -0,0 +1,152 @@ +package ica.tees.mywallet.screen + +import android.util.Log +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +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.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AlternateEmail +import androidx.compose.material.icons.filled.Password +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +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.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import ica.tees.mywallet.R +import ica.tees.mywallet.components.AppViewModelProvider +import ica.tees.mywallet.components.ButtonComponent +import ica.tees.mywallet.components.ClickableLoginTextComponent +import ica.tees.mywallet.components.MyWalletScreen +import ica.tees.mywallet.components.PasswordFieldComponent +import ica.tees.mywallet.components.TextFieldComponent +import ica.tees.mywallet.data.User +import ica.tees.mywallet.event.LoginEvent +import ica.tees.mywallet.model.LoginModel + +@Composable +fun LoginForm( + modifier: Modifier, + onButtonClicked: (List) -> Unit, + navController: NavController, + loginModel: LoginModel = viewModel(factory = AppViewModelProvider.Factory) +) { + var username by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } + + val userList by loginModel.userList.collectAsState() + + Column( + modifier = Modifier + .fillMaxSize() + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + + ) { + Text( + text = stringResource(R.string.login_to_my_wallet), + fontWeight = FontWeight.Bold, + fontSize = 30.sp + ) + Spacer(modifier = modifier.height(30.dp)) + TextFieldComponent( + value = username, + onValueChanged = { + loginModel.onEvent(LoginEvent.EmailChanged(it)) + username = it + }, + label = R.string.enter_your_email, + leadingIcon = Icons.Default.AlternateEmail, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next + ) + ) + Spacer(modifier = modifier.height(15.dp)) + PasswordFieldComponent( + value = password, + onValueChanged = { + loginModel.onEvent(LoginEvent.PasswordChanged(it)) + password = it + }, + label = R.string.enter_your_password, + leadingIcon = Icons.Filled.Password, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Done + ) + ) + Spacer(modifier = modifier.height(15.dp)) + + ButtonComponent( + onButtonClicked = { + + loginModel.onEvent(LoginEvent.LoginButtonClicked) + Log.d("LoginScreen",loginModel.loginStatus.toString()) + if (loginModel.loginStatus) { + onButtonClicked(userList.userList) + navController.navigate(route = MyWalletScreen.Home.name) + } + }, + modifier = modifier, + enabled = loginModel.allValidationsPassed.value, + buttonText = R.string.login + ) + Spacer(modifier = modifier.height(30.dp)) + Text( + text = loginModel.failureMessage.value, + color = Color.Red, + fontWeight = FontWeight.SemiBold, + modifier = modifier + + ) + ClickableLoginTextComponent( + tryingToLogin = false, onTextSelected = { + navController.navigate(route = MyWalletScreen.SignUp.name) + }) + + if (loginModel.loginInProgress.value) { + CircularProgressIndicator() + } + } + +// SystemBackButtonHandler { +// navController.navigate(route = MyWalletScreen.Home.name) +// } +} + + +@Preview +@Composable +private fun LoginFormPreview() { + + LoginForm( + modifier = Modifier, + onButtonClicked = { users: List -> }, + rememberNavController(), + ) +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/screen/MainScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/MainScreen.kt new file mode 100644 index 0000000..c390af7 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/MainScreen.kt @@ -0,0 +1,113 @@ +package ica.tees.mywallet.screen + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import ica.tees.mywallet.data.DataSource.tabItem +import ica.tees.mywallet.model.LoginModel + +@Composable +fun MainScreen( + modifier: Modifier, + navController: NavHostController, + theName: String +) { + + var selectedIndex by rememberSaveable { mutableIntStateOf(0) } + + Scaffold( + bottomBar = { + TabRow( + modifier = modifier + .padding(top = 10.dp), + selectedTabIndex = selectedIndex + ) { + tabItem.forEachIndexed { index, item -> + Tab( + selected = index == selectedIndex, + onClick = { + selectedIndex = index + }, + text = { + Text(text = item.title) + }, + icon = { + Icon(painter = painterResource(item.selectedIcon), contentDescription = item.title) + }, + ) + } + } + + } + ) { innerPadding -> + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .fillMaxSize() + .padding(innerPadding) + ) { + when (selectedIndex) { + 0 -> HomeScreen( + modifier = modifier, + theName = theName, + + ) + + 1 -> CardsScreen( + modifier = Modifier, + navController = navController, + theName = theName + ) + + 2 -> PasswordScreen( + modifier = modifier, + navController = navController, + theName = theName, + ) + } + } + } + +} + + +@Preview +@Composable +fun BottomNavPreview() { + val navController = rememberNavController() + MainScreen(modifier = Modifier, rememberNavController(), "") +} + + +// LaunchedEffect(indexSelected) { +// pagerState.animateScrollToPage(indexSelected) +// } +// LaunchedEffect(pagerState.currentPage, pagerState.isScrollInProgress) { +// if (!pagerState.isScrollInProgress) { +// indexSelected = pagerState.currentPage +// } +// } + +/**/ +// val pagerState = rememberPagerState { +// tabItem.size +// } \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/screen/PasswordScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/PasswordScreen.kt new file mode 100644 index 0000000..0e744e6 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/PasswordScreen.kt @@ -0,0 +1,186 @@ +package ica.tees.mywallet.screen + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Divider +import androidx.compose.material3.ElevatedButton +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import ica.tees.mywallet.components.AppViewModelProvider +import ica.tees.mywallet.components.DisplayDialogPassword +import ica.tees.mywallet.components.MyWalletScreen +import ica.tees.mywallet.data.Password +import ica.tees.mywallet.model.PasswordModel +import kotlinx.coroutines.launch + +@Composable +fun PasswordScreen( + modifier: Modifier, + navController: NavHostController, + theName: String, + passwordModel: PasswordModel = viewModel(factory = AppViewModelProvider.Factory) +) { + + val uiState by passwordModel._uiState.collectAsState() + uiState.userName = theName + val passwordList by passwordModel.passwordDataList.collectAsState() + + val state = rememberLazyListState() + var showDialog by remember { mutableStateOf(false) } + var selectedIndex by remember { mutableIntStateOf(0) } + + Column( + modifier = modifier + .padding(start = 20.dp) + .fillMaxSize(), + ) { + Spacer(modifier = Modifier.height(50.dp)) + PasswordList( + modifier = modifier, + onClick = { showDialogClicked: Boolean, selectedIndexClicked: Int -> + showDialog = showDialogClicked + selectedIndex = selectedIndexClicked + }, + state = state, + accountList = passwordList.passwordList, + theName = theName, + passwordModel = passwordModel + ) + DisplayDialogPassword( + showDialog = showDialog, + modifier = modifier, + onDismissRequest = { showDialog = !showDialog }, + selectedIndex = selectedIndex, + passwordLists = passwordList.passwordList + + ) + } + Row( + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.End, + modifier = modifier + .fillMaxSize() + .padding(bottom = 10.dp,end = 10.dp) + ) { + ElevatedButton( + onClick = { + navController.navigate(route = MyWalletScreen.AddPasswords.name) + }, + shape = CircleShape, + modifier = modifier + .size(70.dp) + ) { + Icon( + Icons.Filled.Add, + contentDescription = null, + modifier = modifier.size(ButtonDefaults.IconSize) + ) + } + } +} + +@Composable +fun PasswordList( + modifier: Modifier, + onClick: (Boolean, Int) -> Unit, + state: LazyListState, + accountList: List, + theName: String, + passwordModel: PasswordModel +) { + + val coroutineScope = rememberCoroutineScope() + var selectedValue by remember { mutableIntStateOf(0) } + val isSelected by remember { mutableStateOf(true) } + + if (accountList.isNotEmpty()) { + LazyColumn( + state = state, + contentPadding = PaddingValues(top = 10.dp, bottom = 10.dp), + verticalArrangement = Arrangement.spacedBy(10.dp), + ) { + itemsIndexed(accountList) { index, item -> + if (item.userName == theName) { + Column( + modifier = modifier + .selectable( + selected = selectedValue == index, + onClick = { + coroutineScope.launch { + selectedValue = index + onClick(isSelected,index) + passwordModel.updateCard(item) + } + } + ) + .clickable(enabled = true, onClick = { + coroutineScope.launch { + selectedValue = index + onClick(isSelected,index) + passwordModel.updateCard(item) + } + }) + ) { + Text( + item.accountName, + fontWeight = FontWeight.Bold + ) + SelectionContainer { + Column( + modifier = modifier + ) { + Text(text = item.email) + } + } + Divider(thickness = 2.dp) + Spacer(modifier = Modifier.height(5.dp)) + } + } + } + } + } else { + Text(text = "Not Password to Display") + } +} + + +@Preview +@Composable +private fun PasswordScreenPreview() { + PasswordScreen(modifier = Modifier, + navController = rememberNavController(),"") +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/screen/SignUpScreen.kt b/app/src/main/java/ica/tees/mywallet/screen/SignUpScreen.kt new file mode 100644 index 0000000..5d07fa8 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/screen/SignUpScreen.kt @@ -0,0 +1,174 @@ +package ica.tees.mywallet.screen + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AlternateEmail +import androidx.compose.material.icons.filled.Face +import androidx.compose.material.icons.filled.Password +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.rememberCoroutineScope +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.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import ica.tees.mywallet.R +import ica.tees.mywallet.components.AppViewModelProvider +import ica.tees.mywallet.components.ButtonComponent +import ica.tees.mywallet.components.ClickableLoginTextComponent +import ica.tees.mywallet.components.MyWalletScreen +import ica.tees.mywallet.components.PasswordFieldComponent +import ica.tees.mywallet.components.TextFieldComponent +import ica.tees.mywallet.event.SignUpEvent +import ica.tees.mywallet.model.SignUpModel +import kotlinx.coroutines.launch + +class SignUpScreen { +} + +@Composable +fun SignupForm( + modifier: Modifier, + navController: NavController, + onButtonClicked: (Boolean) -> Unit = {}, + signUpModel: SignUpModel = viewModel(factory = AppViewModelProvider.Factory) +) { + + val coroutineScope = rememberCoroutineScope() + var firstName by remember { mutableStateOf("") } + var lastName by remember { mutableStateOf("") } + var email by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } + + Column( + modifier = modifier + .fillMaxSize() + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + text = "Create Wallet Account", + fontWeight = FontWeight.Bold, + fontSize = 30.sp + ) + Spacer(modifier = modifier.height(30.dp)) + TextFieldComponent( + value = firstName, + onValueChanged = { + coroutineScope.launch { + signUpModel.onEvent(SignUpEvent.FirstNameChanged(it)) + firstName = it + } + }, + label = R.string.enter_your_firstname, + leadingIcon = Icons.Default.Face, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next + ) + ) + Spacer(modifier = modifier.height(15.dp)) + TextFieldComponent( + value = lastName, + onValueChanged = { + coroutineScope.launch { + signUpModel.onEvent(SignUpEvent.LastNameChanged(it)) + lastName = it + } + }, + label = R.string.enter_your_lastname, + leadingIcon = Icons.Default.Face, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next + ) + ) + Spacer(modifier = modifier.height(15.dp)) + TextFieldComponent( + value = email, + onValueChanged = { + coroutineScope.launch { + signUpModel.onEvent(SignUpEvent.EmailChanged(it)) + email = it + } + }, + label = R.string.enter_your_email, + leadingIcon = Icons.Default.AlternateEmail, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next + ) + ) + Spacer(modifier = modifier.height(15.dp)) + PasswordFieldComponent( + value = password, + onValueChanged = { + coroutineScope.launch { + signUpModel.onEvent(SignUpEvent.PasswordChanged(it)) + password = it + } + }, + label = R.string.enter_your_password, + leadingIcon = Icons.Filled.Password, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Done + ) + ) + Spacer(modifier = modifier.height(15.dp)) + ButtonComponent( + onButtonClicked = { + coroutineScope.launch { + signUpModel.onEvent(SignUpEvent.SignUpButtonClicked) + if (signUpModel.signUpStatus.value) { + onButtonClicked(true) + } else { + onButtonClicked(false) + } + } + }, + modifier = modifier, + enabled = signUpModel.allValidationsPassed.value, + buttonText = R.string.signup + ) + Spacer(modifier = modifier.height(15.dp)) + Text( + text = signUpModel.failureMessage.value, + color = Color.Red, + fontWeight = FontWeight.SemiBold, + modifier = modifier + + ) + Spacer(modifier = modifier.height(15.dp)) + ClickableLoginTextComponent( + tryingToLogin = true, onTextSelected = { + navController.navigate(route = MyWalletScreen.Login.name) + }) + } +} + + +@Preview(widthDp = 360, heightDp = 800) +@Composable +private fun SignupFormPreview() { + SignupForm(Modifier, rememberNavController()) +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/state/CardUIState.kt b/app/src/main/java/ica/tees/mywallet/state/CardUIState.kt new file mode 100644 index 0000000..d66aaa5 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/state/CardUIState.kt @@ -0,0 +1,18 @@ +package ica.tees.mywallet.state + +data class CardUIState( + + var bankName: String = "", + var cardNumber: String = "", + var cardName: String = "", + var cardSecurity: String = "", + var cardExpiry: String = "", + var cardType: String = "", + var userName: String = "", + var currency: String = "", + var bankNameError: Boolean = false, + var cardNumberError: Boolean = false, + var cardNameError: Boolean = false, + var cardSecurityError: Boolean = false, + var cardExpiryError: Boolean = false, +) diff --git a/app/src/main/java/ica/tees/mywallet/state/LoginUIState.kt b/app/src/main/java/ica/tees/mywallet/state/LoginUIState.kt new file mode 100644 index 0000000..e8a2fdc --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/state/LoginUIState.kt @@ -0,0 +1,11 @@ +package ica.tees.mywallet.state + +data class LoginUIState( + + var email: String = "", + var password: String = "", + var userName: String = "", + var emailError: Boolean = false, + var passwordError: Boolean = false + +) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/state/PasswordUIState.kt b/app/src/main/java/ica/tees/mywallet/state/PasswordUIState.kt new file mode 100644 index 0000000..4c18f40 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/state/PasswordUIState.kt @@ -0,0 +1,13 @@ +package ica.tees.mywallet.state + +data class PasswordUIState ( + + var email :String = "", + var password :String = "", + var accountName :String = "", + var userName: String = "", + var accountError: Boolean = false, + var emailError :Boolean = false, + var passwordError : Boolean = false + +) diff --git a/app/src/main/java/ica/tees/mywallet/state/SignUpUIState.kt b/app/src/main/java/ica/tees/mywallet/state/SignUpUIState.kt new file mode 100644 index 0000000..6a17c51 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/state/SignUpUIState.kt @@ -0,0 +1,14 @@ +package ica.tees.mywallet.state + +data class SignUpUIState ( + + var firstName: String = "", + var lastName: String = "", + var email: String = "", + var password: String = "", + var firstNameError: Boolean = false, + var lastNameError: Boolean = false, + var emailError: Boolean = false, + var passwordError: Boolean = false + +) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/ui/theme/Color.kt b/app/src/main/java/ica/tees/mywallet/ui/theme/Color.kt new file mode 100644 index 0000000..7387b97 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/ui/theme/Color.kt @@ -0,0 +1,20 @@ +package ica.tees.mywallet.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) + + +val Primary = Color(0xFF92A3FD) +val Secondary = Color(0xFF9DCEFF) +val TextColor = Color(0xFF1D1617) +val AccentColor = Color(0xFFC58BF2) +val GrayColor = Color(0xFF7B6F72) +val WhiteColor = Color(0xFFFFFFFF) +val BgColor = Color(0xFFF7F8F8) \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/ui/theme/Theme.kt b/app/src/main/java/ica/tees/mywallet/ui/theme/Theme.kt new file mode 100644 index 0000000..fa731e2 --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/ui/theme/Theme.kt @@ -0,0 +1,92 @@ +package ica.tees.mywallet.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Primary, + tertiary = Primary, + secondary = Secondary +) + +private val LightColorScheme = lightColorScheme( + primary = Primary, + tertiary = Primary, + secondary = Secondary + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + + +//private val DarkColorScheme = darkColorScheme( +// primary = Purple80, +// secondary = PurpleGrey80, +// tertiary = Pink80 +//) +// +//private val LightColorScheme = lightColorScheme( +// primary = Purple40, +// secondary = PurpleGrey40, +// tertiary = Pink40 +// +// /* Other default colors to override +// background = Color(0xFFFFFBFE), +// surface = Color(0xFFFFFBFE), +// onPrimary = Color.White, +// onSecondary = Color.White, +// onTertiary = Color.White, +// onBackground = Color(0xFF1C1B1F), +// onSurface = Color(0xFF1C1B1F), +// */ +//) + +@Composable +fun MyWalletTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/ica/tees/mywallet/ui/theme/Type.kt b/app/src/main/java/ica/tees/mywallet/ui/theme/Type.kt new file mode 100644 index 0000000..18c5c6f --- /dev/null +++ b/app/src/main/java/ica/tees/mywallet/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package ica.tees.mywallet.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/drawable/card_icon.png b/app/src/main/res/drawable/card_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cbb49507e5b2e4531710ea53c17e126599b6b416 GIT binary patch literal 706 zcmV;z0zLhSP)iPh&#cBf_vTg02Os5h=}OI zmFPwhF8Dx1R1{PcAOFvD#ybvo=H9t8!_4sqzk7#sW-jNO?>sL6G|*+bZ-CRZ0uD@Q zxYJ6j@g=&Tm5w6WNLzo?2Xu|zq?=M90o;HYlp>pjds2|n6+1A4ZD&CWhGTpHY5iRe zJs=X!6K8=n3z^7$nz1sl1v5w^+iQ-H3|xm9e22?4YAhxPuqz*Fj~hPF=O~_e+C=vd z9(}Zfj?)>dFxMEkjBqwxe-SZm8IUz$j6Oy2tkQn?=OX<>-$8BMR%ixl!`YJSfh5gB zZ=kxKTSf=zUFSny0i*(00)M=O%DmOsVcJOB>71>63Mxx^1876A{x3VnQWVB5TO-%$ zS4X{c^(xzMR~Hh%I)Vit)}kl_3G=_P~9vMgLqiCVQFFYw>^2LwS7!Hwd|VIhbhhyysF zsMv}NK@>;WxT;uBz_e|G88*0my<}aGM<^c zbfexnp2&Mhf7Qxr=$v+{N?n&ara6MQ_cOZmHMD znjbdz?pJ$3^@6@6Be`DFK^bFS(~4|Z4xgI4%{;d;JAEDnIiUEa+|hTJS~{w;0+sI% zhc}ib%9Lh{jY(`~g}7jUa-B8f92RXB%6@rKh-)oD90^OuGHku2Vj)j5GS z0yBRLe&P)odr@CoC{{ydegXdCqb7K57YYK!j|k_HEb@!+2ka)eZn}{(So)i=i~lU# z1@$tswO37e9V#KYz_g7`{G@P5$J6W;*iG<&9jm`VgU(WAvLS|0vgcu2<&XyMV8GA3NR)`E@+ z)=s^`F~>tW>m1SXm6&+LYRp6p_DbA_N?c3e4erCfpL51J7!f}O`{HJG*pAoWuEZ!> zFtI`Sz#%?579?f9nTbAa;;ti>CPsv7kP_>J6ONnz6Q0)b1D@gyr}Q<A ziXVqNGZ&z?$3EEG##V`n7WUX9o~_*LBi@yHE-u1gp6b?v10t#CqWikBiuY-2pS-%tU_*J>$m2 zJCERdP}}NIM&hF;IErwwa_6aeRKnY7=(e$$;InoLUwXtR{=xBgOp6~xwwaH!s;j+4 z_}*n;CgG2#!mYynIg5|C6W=qh5@P<)0O$4Rs6TMf^(M5w&xdL!Ch`LsyJHU`*r%Po z7H&iSZR2XE?ZUTO;{haquXXnPZmeuP$kN0Ps4cb*@k0Z@s&Pm=4Apz>0=^$ug}?DX z3jeUwDoO)IBjo9y!``fCtaGmSMMwkRgr|hR9dUfSz7eiP0E9HagAP9@x(skTTtXm} zi@0c%28u>$plFl^ibiRmXe5miKZPHW4xEK*9&tR+enR?LXu8>t%jre`o2mTjfB*mh M07*qoM6N<$f?yPxVgLXD literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/logo_mastercard.png b/app/src/main/res/drawable/logo_mastercard.png new file mode 100644 index 0000000000000000000000000000000000000000..5b8cc08e327be1f9415005cffa92323e4927e37f GIT binary patch literal 2209 zcmV;S2wwMzP)ISGPP}Qg00#yQuphD`Gs;blq5J4>u zRgFZ8DvA;snj%$wsH7i)RP{waL@7}pY9NG1NF2YCIDW0YyWZVwE9q**kO3%sF%B%q*cq6cml2qg5fj5wLm%m?g%IR7={H$K85h+Xm-JAxcPnWPJ!YMjG`24A05)p`IWa832z*yzrizw zFTyZ^o;Z9hsoWV|3HvOouQaQ^tekAhI#a)PrJk-4Wd@}yRn$4FlGQzurna`u(s7UGfubnO0NLV8=R0E5| z1DDUm+&_6YOrss*Yl^pBRx}NoEh-dP60E*oQqQ+#0u(~W<#>eM3d87u!fGnv<$2^4 zlT}gOrrCh_j6M+@(A>mFqjOh{pIsAS=L}pdi(&IVrCUxjzwH%F>8&L)9#?tLo#^$*tFGUoAx*cz)zazgaUr^nvj_`y{E411g zA1unc8ex9Cm`C@#G)&`_QF>;>^YbVrUBN5&Q5Z(KdU?A{FKt&#cxpX zJMCI+tv{m*IOhW>6(h+zn$gWYk50lc>2pEufkg;_Ew$HHo-KL>p%4oOY5(QRjPUf< zRx!5#WOTBl9K!60Iuwf6#6qvFf`3Q&Bi%hXa`|%JVo$?9!iN(uOzKPxym$e<&lZ`T zQ|6%y66&W5Q|5)&iT)(}e7iW)Bn%?c00?}D|g%dEd7td zApS@awOgXF>OD9gSurO#GN`VK63W8Pnq5OLbFo?D{5fkhg0@vY(69LPP8h@rdzb1S zNu6?=L$|`LnH#V`eZKpLjeK>q#~S+x2EAl!k6$j%L$O zR>6LWu=MX9)Lw|>HIZ96_g=o*#!01yR9sT@e{>eazae$=jFUg5Tz+a6rO7oQ8Xh%|jxe@2Tf+_9g6*jRMx~+y}qRz41m)&UYx5 ztd1wR(O+f39S(+Zoce}}-se^pQ+xp}wHB-hkIXj`#CiqU$uUA+OsCqp9Ew|2O>w1% zxxhF0_!c+(nHH>{DE9ZZnWw&RU0s@@YdwgKL{>MH?BqH$(TC;gWz`9g8t@dI@+*4F jXUnsw*)~;<-`lNS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+ z;1OBO!0`JA2r~+3ij)Hd*-JcqUD=e25M6Dba4#HxcBzPS?`cQiH48& z=k}X$h%Ztx-;@#hKuJmaN~++NjrIy!99pY8eoaLQ%0RhZMZHobKE> zCe{|5C^7NL@fF)!r7b4?M~pUay#85r=G4hk*)LCJbvqle{HW*O#81~h zhw08R6ycw4reXH#;<8=5U3KkywT~RSe^cdAgI+W+9Mg|vepkvr#VK$~dzo>z40R1mbq$R|3=OP|jIE4KwG9lc3=FQ{UKN3&AvZrIGp!Q0hGlI+PkcG217F=0}De_14GmE+n(72 zl?Wl36P#I<%3xw?S8ye)vkd~Q~3iQ36erZ8Yequ_ozNwjhiE*l< zo2P-kv4Me+J}?$iGE3r<6N^&fGn4c4;tee<42+HRfNsjlRR9$z44$rjF6*2UngD|H Bus#3) literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/logo_visa.png b/app/src/main/res/drawable/logo_visa.png new file mode 100644 index 0000000000000000000000000000000000000000..4660b2e7622628d4fa79b2d3ec412df3477e0f60 GIT binary patch literal 65057 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..345888d --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f58fb5dc419fff4d3d2cfbc2e4825ebb883ba23d GIT binary patch literal 4014 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..6c858c47307052a4cbf08d9fb22f565c059a73b1 GIT binary patch literal 1874 zcmeHISx{346b%Bh2%3j1kpM!7XhDe(AylLo`T}`m42v{ug`y~E!y;%Ap(TJzA1X@% zf>45)Oem-kp|ZF@RE$a?M2RedONK=-$|4Y1f=QZgpPl}9`f<;>GxwbPac1t^yg;g- zv7x0Q0)a4w$Y8LBxxbhGY7Mr}nWHtNbu`$|2T>=sk|7X!Mi590Nspdld(~PWM4pjC z+qF`#VQ?;KClh4{ z=+3H(ai1FydeHIWSA(7t^Mek^*KGE@=;+;}$7ia%9NhIyZDVvZIJ)}!0F$Gm1#Wd& zU9lUq+CoGCl=C?bNI=gYxm#!w%P|0jIVL*D1|jOuDj?-QE=5HM`-jXS&rMUT#wba@ z8G3mmi%Qw)EaR0onZ1|3ny$w*_cudB_J><|XzWx`uR8fcv-5}n^cdUbDC?+oUHjRH zPy0#M0_Aq<1yN+pfWTzo!fZD0fqkb(C48=Bw2iga7&9C}2!MtNBb^>xcmT>ENfNdB zr!4NC61WO*GCTZA5^sROgM*4{W31|5KZ`| zL+LCthH(Chm!hobI-^XseKzc3p<>C)d4AoKqtEMjI1&Pg&HCO^wh#Ya{mULQ0#I&e zl*mu<%0!a^>Ljd}4zlMtR)nkPhrOHohvJmt=Y=bc>`jq%}(HQ>(bVPP%)9b>U0Kh1cm+;EE`BI;>Ec&&N z^kOBxD-@@t2b5*IcRA~lCI?XKC>at_)-99|eJT|yBxm?a%!p(drQ;si%7K5-Z5~E;2W5kbaTYSDj?7Sz8k%f8r#yJa8H&#@u)aq`3DM+rT&C zyu}9tXo|@BJ#hpZD*2TU@1K3E2Ex-w zlYUFll2}$W{)XTzTN*(>zOAb7!5g%C>$}Yw*97Myg`kufC11bAdF6dliLhu42kgDW z(HeZ5cVOAt#fL6V7&dd!*2csIvbhczDltW6S;=22pYNair#NR*g1xUEF#(hvOWAFI zg}*CR_{6ai1if8t+Q{6pb$zC(-MR&aRSp+_aA=t zdgA^9JrW|cqQ`8Y9FLIXsCL)%U?=hDV4<7qG_x@>m~peG!0Z!kMKxTzo>j2TCW`RV zKRxM$HBET>yfQJPh8M+ZrVLfg30R?x=bneQkFux*H%(MHP&9wCbMJao2C350{NtRy z?S7j`M?DQ8%zJjNf-gQU?bKQYqq0dm3K5v`hU(O81ZH&%(5<<%6A72CY_nmlFmV2V d+rLG^(Dn#)zP}T{xJL6N5fF(A*7?Nb{stY&ALIZ4 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..c84a671c72dbea9e1689d42962c791796d8f9c3a GIT binary patch literal 1811 zcmeAS@N?(olHy`uVBq!ia0vp^i$Iuz4M-mPBqj}{7>k44ofy`glX=O&z;@Qt#WAEJ z?(JOb6)~YAZToGu2r70s@`$|*706-L);%K55x9E-i{l32kBnx^E-EleJ90*KE_xs= zs3W?@L~K#QL_ZZb4;RN8?b~Oj&i2mR^zF==ov(BDUuHQ}e{IdrYvteX6u+}f-}X?g zk%?uS=!=75Dh*0nj+{(g5lK8|3p=a=ni`a*Ni_RvEaID@u%JWrSb}iZ3T9OfjigS) z8!bw&9EP`2!(AP>8*LB7C5UfGPE!8QY{5K-!H==tf6f1b-OAlNgm3V_VP3~v#{BmG zvMr{9{!GUkr#F_nO)U%&oL%7F;C$d|uu=ZxxZ7Sg!j2t2P^^5)Vo}H2$3GYfN(4Bs z@2-@xuy_O#y3U}_xSeN%P+kppZfXsG1;dZLCEv{#b(k}*XAbW-SyB4_sq}-m2a_k> zyWgR7k8h9ZLFUOT!rwAH%X{$m1z+%qUX4ew2W|&9?04w*JyOPEduCb3WtpW)ehGQ& zI)o)I9TSTcd@g0HMmv8D@zdb+vIXC*Nb#nDx^~Ur^ z`HRzn1RodgoX`GQgdx1#&l<7 z;rT~ZCS46XVw&;xif^^m;n}bKGPcLP|J<@oJL$atH6@(vX`MMIv>X@_C-xk) zg9f@?kqV5}q6uZ$GxqE=rj$6X>$v!shm@mS4(UJ7g^wWLR$ri@4qLV`fh`Pt3hqygRs} zPa}zWtFQ%=jFihUwY!oJKD=r4bN0N!X11y$+vpwpH^#RQ-FB=0So`hmvlWvMe7w2% z^{uxn4trYc>UjHiYyV3~Mpk}Wthzo!c;ng@^@iZZUO(yu4E+VQ^`{;P12&h!SQXP>rKO=wVJbCf&{OzAso*2<|Y=x_`;R>Y~1q!+)M9Y_gG g8P!HGNDkP4WRTi)yynFVdQ&MBb@0MM}?V*mgE literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..7d1a5d1a95d92c851e63b2cb8710457639eaffb5 GIT binary patch literal 2368 zcmV-G3BUGPx-`bk7VRA@uhT5D_^R~0_{@_N0y-rZThik)B+3Ta}O7B^KDfsjy32{@*P)QZP;$sdgJF~VU#7Lv@&fK~4edm1Vocpka{?8A~8sSGj{E2S)zKh&<@Hc<13c_j# zFu+zKvh{4*^i{H0zEa5LzFYvLVv%yW+}2{TNOqg;8m>63R_k9a7R%Lt-M;-H5#@;p z%^9JZ$*hC`18(nm;)&-A#o|Cdm)p9W%TaE5nX=2v5_llOZ;622E?sfpZ@a?*Qsi(r zPFgIM{LQJUU!XZh#x#*y2$TUY5)EWTace4-f~6IJ3@Cq(JNr{TJul=7g@H^uZ3=h^cggbA2q{GT{!@3Rr{5x?tXXfEA%HfH zCpT|?Q541Z)2S3eE?O4VvvkFMjud+alJ)iV1Ts#iv+vF)pL`&DgHHezUNIto0Chas z-F-|MTMNSJRk*Z z&!$b^NG6kisIa^YOiMbC!b6COfZxA!YG&rLR!nFSuo02_a~n2970qja)v`dSfc zY-}Wt-~X+tsj0un^+NH4ngDd~?Ag3|I2;Q7L>7JN!jV|t*-5*0?IOS5uV_-zu*D)t zjX#*S***1d++SE&poA2=ICuh5x_qj;dpH)0DY{oa zEED*2XD5Al^(wjD?uvj~&5g*y0&RWnIf;Z;B0vRiX>I-X^vukkc`xt;Af1K{U0uV; zc>Gm8i}fEpN;n_IaeQcqaOz1fAP5y+U<69Vs=IqQ9*y>=)9EtF@Ddsx8KFJ<_B{&x zG(I*){YQ@I5`Y(4+uF*!zz9J5u>SExET&kWw**6MmcWf0H)v#Nh{EA;SzJ`egNv>3 z{Cr75+&y)Bzu!MGH$Sh$0wVzVG1Z>LNqQx%LJ znQ8=VHX9`~nI1ssN1-4+&qd}jUn590Cov+A#@^EM>3cmMvXpg`cgix;If zi}85P1cE-F?)(Cs`Fy^=g(8s`h$sO9lK$7Vw_g!csV!za@V_SDa=SlXip5?eq8KCK z>u77cB8uWOnjYXP?8u1|h93CQp+kxXmJ$i2%bB}(>6MpWqWcdX(AfAmeY3Bx!aI*Wt+uKXGZr+rFyS=@gZr-`G zA_AxfEE7p1Pa+C5`TZfSafpsKFnflC)INNu9Yq+-oyo_?Bc-?}CJZtv*O zB@pm>|7%DMBU&sL5_7p0gqT90B^bP%&*gf}cwi+2(C_rr6zzWbWqR=NA^rBu8C?k( z5pX!2HxjATHbwwJ?E6$}>lHDbHjIJMx8FAOz~O@jl^9?iFq?`H10bNK1|BJx5&Ed-jld4|?|K0z1@g~J0x6laC3q2sZ~b|e#t_wa%;CD90=6DLm^N(dv$ zv*Y8MLkX#Wu3zYt%#PGt7bSfozLCejZU0rl-VuCy#&zds8 zq<%|pudak->;GnUZVvK+^`&u-dR0R5LUSNc@`Amj(`rRX%P3e@ zIsfjvRrT-o`QC{{BC!4fv%Z=DexoXTo12?=EQ{j#Jh$$z=3=zoW0ZYrai7ECpoA!X zmWV>~x)64Dq(i;1h2Kc2fhIxdTh3(O$>)`}B}tV`SoVF*dpfDn$UACckWPI=!w(}% zOUV0CCLKKjxG$~FNdYYgZ;7I~S4~1o2CT!iw7dk~WuR z-pq*N9!5g1M${@PBMHgi&qX2;taL&5SS~4-gNB6oex;QBLYT% z`RCAlT|)!F56j@O9$Epung>{aAmJh+p(zmf`f@gV2A(h@samxzfw5SmT}+45xqmSl z#Y!}mG<3n6A;2;dV!{U^K|wf@Nu_=OfM$r8u{;BAx7+_=wb@QbqEYMxV5k7iYg)cq z5NmxCF@f8{YxMw6 zgn0w9!X^Q{(h%_ZzGSi4wiL2iR>3W~eEth~(QdQ-Q|_Q>t*iTcF`xfgT9%y@!XWf)sm=HLR#^`uW-XVIN3yr mJ!AjOfh#nIbH$)}5dQ&?oFc4dT-m|^0000<>2ZjNk!ssuz?4{+ zDRJl!N6XQri5%R@0%FtKXd=0NSKHK}KF?j6FV`(GzVu=?U-y#!N!wIyxBgwNwmg*c z_SCO_mwtLF?44M$R4sEW=WgYfiK?5#4AI-IjJY?7~6(zcU}q zy!vd>4ZBNb8Ef8W3tzMOu=@9nb#1|>j#A!Brzp1APXFR{>HESnx9cpg#MC~YIeEkU zNqV>HZi{=JJ$~NvhU)G0*=@Ei+blV6Z`y0jGG*5D8QmLXZ%3bA;H^2Go$deavd_*{ zm(Itu)NZX!>ffL!W^g+A--g02ZY>K5v2OI@q` zDs!yu?xZh1m&`qvtJ+Q|*(y6V;|2?Fwa&}7xBse1H81KVPCShjr@j&t0GI zO)lBLG?inv!wt{d@dDe9F(=GbRMxSQ^W3%f(X<bIa$=`E2)n?%laJ4=Z;ahzp52ylBG)*98Wxt%4lg*@s2M+!S=y z@digoG;Y{o=98Gna_G@5+DL}w+)#WVRlse*XDrFJO za>@Hal4|DFmb)zPL?>?TDU_^;Pz^RseBT%x`aq{>5367J$q?Tg>p8!z@ztAU`}V*x z$KAiGO%r+Nbh%6Vr8ep4^eVpL{2=qgXwlDf<#VPPt1LNx^UYz7<5dd!^Td+VntzYR zx$1&FKo(Pttk04kEX9J?I&B@{NS0x@Q!JER7LO& zmP2w3;f+^Y3k51JKQgyy^;LLd@gebSX+Cqg*%qHfVGe7ynvjTY-UUx5elnrAkxnrnXl`Z&Aq z+nJmhyxIGsrYS$aWKe(L&AYlO#=q{Vnu&iGYz!1BnVr&MAb;rPv8pK-om+m+xUIpp z%h$-|#wRa3k6XPz7hFu{kQR9$uReXJrM7SiPx|*hxe|RCr$PT?=p<$9Z0u00jsjK>`v$ntD)jmDusv5-CQW+D`3ScAUnFWO?Fx zGEOQxk{sD}o=x3pJguxg5<79F#FHjzY*~(FIi2xzoJdVaesr29@gsGcN){zc87pH; zqDYY=kt{h_4h-nzzQ=n<`j#$ z2B6yTt5)4msZ_oO!^6`dF9w&>45+)HSN~f817=_Y7@=VB;loFd0tm1IK!6c*%7(cF zfCkhi)#Lm6Zm3L8>xS1QhS6}h9xr5v;9lWym_%Ay$h>*;9zJsH*xxWfuvwL-jF<}m z*i2@|@TJm&larIz`tBiHM4&*DkWIC=wmx#?t+&92X;Xaggb7{(fNLSZ`mgHi zTdR~x4~~zIUk&4nI(wn*XQd24v_+$@9Dn=mKSBm<%9>n*-~|Az| zxiRZ=O?q!;fJDZlE0I(7FxN)L)EB!-c}-v6_Uy#O17l-j z`ryc{?X%KcTRva!^V#+zHpJucZyr5yf`ULZrJ6x-1AtNQ`}!Ul8y)>~NRB8Q@x=RG zc(fbIqXGKZ3fKUqn z(w=YW=}x`3(Z_RQjaMKz1wh{O&7P{&lAYw^UU@7l&|co(3lM4n03%xjTuaT@JzwCt zUc`cWgJh0xNK+Tg$k9VuOmLJPIROC2&KSS9cYA7V>;W~$=cR(IhMSmRhz&N!iAKh* zVhlqGFBkzPEL^y7!_gBbUNQ~XgxQfS0CbRrLVIY%vSlgc`RXPJlCpWY3>&1p-D$jV zP@=HAe=Hs+(P(u2(c{M{2vUVS833s6`w1bzzE!IZ4xByv`_hI-2W1(-dL}1^uz-sg zg8gW?7alGXLvX)DBJtY0XU<^6oYzLo!Xln50Fa(}AMWjaXn1(|tL%)F!NaW>!DETw zvkP)8Az)V^5Fnk47Cm}=CLW;9E{q2v0CefO^2#eeI+@A*RIlw=X}iJ{;|_A^rI(UW zC?pI}^*jKM_2%KjPp-cD>U!F==6mhgy_-Brc+ZwCIuoR_FO!re5{cI}7ECfF zY-t7n07%cg)jd5s22P*;iup`Kmce8>JTMNv{4(k3>1l)=Yrf}euf9q?x^`{NSrk~% z(b;+1Z%>|l!Hxwy2CzAQ_>%7K^O!uh+N{dWY#ey!%$W;L^F_#j@f`~mxQYeIWKzfi zD*%vo279i!V#na%puzhM1{Zif?c}-9QBi*{$o(y$P|XZLhfFM>X{jL=@BpBhPxyl? zR%}m?jeW67Rzz{Yq=)Zm08D-5&g|Kw(hC!b*H524i;RdH3(Npe`DrGEv@GxLK8FQU zyiFzs(5z@UmGacXv)L>;cJwG28X6+g)0iu_-qh@c!&FO2tyGB5=TklZ?oFF4XZB=A z+8CTAlF5xH-+2caQ56e#0H}HYs+B8u3=Rx@*<5nq1!GMpErA;LP=YYsdHcqVY^^19#*A^9F_`GNtfPkl`SPZI{x_7z`#L5NP#I)sP-}g0Qo`c8D6n$*}r8nnX6d& zQ9WA!fbUtnpzIX`P8>f@Hg4EJh6V?9u(^h33@PiWLU2SQcANc)MB>+{2M0fn6`0I~ zeiZ;ze&#`b7I$_I(ba2?V}Qw%yaM1)@4eTMo2$3sd3r6LT+2Cd6wo+=4AU6AXXe^cbf=K^$5430`-9O?%5YFfGq$`;;zz8EO?e3nHBMCNGv4*GL z^s~vyNiuxyT-CkV4@7`i$q>r`b+!vj=$9>7GHf;Yl8FK4Sm6Z&(&;o=ws^5BIjpC9 zC2w{Fefg!A$R{^$oMoO36J~wUSo(nsP2}_NAf%Ogm6QTN^*=}mX-&jpXL$`WT+*a} z25&Gi!V3U0nGES(v}nc%jHi!Tq{$vAo_>iJUwDCRT)%#nX_DG+ZbR3iMW6iLOdLQq zq&|nh0)X^0bj9VD?-&{!{E{j^GBH4K9E^3|gBSn?bT3|9H3eF407Oz_-p_)d#Q^|7 z2W2_{y8d6XeEIeaGy0YBBvBytiUCW(0F(EU!**Q>QRnhICYYG>S3+06_o4 zmn>VhJu^Q3d9&fUBVQYau%MhDAD6+=_864`ngp@If4oi-bn7QRVGP2ObI$BZZEbD8 zJ~ukLju3+CrWyxW0FeJjmM>ZIuM-m!Yj^;d(g0h7u{!Mq0EhugySl0}k#U|qIrf6$XEc>4CvxS;;eZD zENZAI26)W?76dB*3WWl>XY*!qVE=xiC`dSFHW>fuef!9D*IzH{mLUuB0st))y;uVP znUE?$bnX`bL>IKRonc$1Yd@=bRQm-nfadF?>9llbtqw#C;00kT0QUaqM+Bt{y0M_$ zc+*Yf`ThH)+r%!{nUl?o8UX;>hZ(b{o_vygd)F>Xk%Ktd&jR4o z=EuShKKQOEC`BvEy%DGrK_{^=6o)vC(y=e1?xHeakEY|?gSIJe) zh#?h?x3&F?q9}cIZkN_{=!!9^nKCA3cu_LOq+K{}iLx>klz2Vv$ZN%c7}q@o=Q7v5Yf6rOaW|9W;*sSqy!!1Y!vUv6BM z!m$F+z`V6X=2$YD$W`^aY9#H{_&B~j7W>}N$Or;3<^t48C<_3N(N{$*>FWAeCY_$G zWZB$NCI)x~z~{DZCC@%%3{RGx>u|=(O@U1YkfNe|5JMt%HVo&nvl9BeuqH##DW%eC znTv~JfL8ze%(4UXey*xdiac+S9O8Q63OFa>|s8}9|-(Uu28t$tp8>J=)3@` zqOD2DP(HsKjiuV}BnGgQ_HwkEN~Oqc>(`V1{(kjq(AYW;l|AkXIhTy6#qji;NF?(8 z(RBLnwftY#e;xpIa=v9rSJ%yHR)%cW0a-OpRI#kJQ&^sUw7;JW4h{;Jr_0>KDlq@a zop;KdE z@`Ju2&JF-7L-N6) zd22KDr{gguSQv}lR4f#1Ss;o5|MAOTlGUrF5-Qgn_UZz!zVZsW;kxTwT`m|3{Zl%d z{f1WklzK*t#s!uI?d`3tKUP`5Y))dpJ=?aCM|bXY)tP#qy!r0C)j4H1TTxLy!~|cp z{%`&+YOB>rlm#>vSh7GS2KfDcvj1m4BiDZ9BX0Urw{v$t{r~nGaG= zuJ=>9u`*{B3-bB=Zutd${O7lLH?tba8YIu|c?64nwuLtbPUQ5^)@XF|NGkO*Gw?E` zp6vDP?8#2lAR~&#qR|JYrlz)5RYx7P(5iMrFTswyxnMCPbF2MMK6lV`sY8RI(BtWB z_M2MZ#WHmI<*wB=5zb?(=9{R$c0uQhk(RbaB6}4@(Z6{^#(T{dm6=l&9b@U;xS2yn zNLg0mAiv-Ln_RK@8Af_&-e1%A1+f{C`n5F}oW)|X8;iNz=f>0ym4a|2e2)OgSqjsDqmvA9L%QP!$p>cz8XHZr4EZDo4q!7;&5=!tYT`wyD# zW5Qi1Jx&3j%U2*pSU=PPIckeWzcN)QY!)%0rWhdd_y%e{+aE3E+@%?x&UPW|fdE)a zk5d55@c;uf3c{D{KoDs=ZHP$Y+2gFVzV4nslkb09OE+PB)cR@4DKx%p3}E|9CvDVk z(8V)l8WXr6co_ribY8U21C^<|gy#9w_>diH{Hk(;-Tj@a2L%m5xf+CgezT~vUNJ(J zF{1X=vfnG?*TMi+y4-;v(Q{D-Bib)<3rB~5(IKPk)a?1S!~k<+xpEY3X;I|}YlnDq zvsOKp_2_yVU5`C5ekgQbI-C84wzR~x@!c@MiV0yYIEN$i=l@Wdp2omLYLkfn1kvWNF0v2{*#Ejq^j<&SiUn~?p%LW=Jo?h>) z#%u^pa`vQix$iQD#|W2x^_Zi8%QJK>LD=d#w0a5Ho&%4kUJuEE@udb?GHvw|02Tzw27Cbs1ptc}R45cS zdF=%<9j6wA)Nl+Bqf^7r>2C|qW#8GypXiu@#s{zhF96dV4TnEhDwTSsOQltF*&vhA z_drfE*(^LB#-`p5ji*1_$^NLbXI{@b$Xxc9Wdn^36bQ-+002<%qF~%pA><-3!)>0- zT1@kFYV_ANBg4=zH~_#q)%ZC#ycYv88K#@>16iVAVBH@DL^VG10zi2Aqv7yYOx55# zrBqVK71O2CO5V)_e*aezrixVOg8(5W?UE;MrU96j2fQ)=8I=RR%E1l zFo4H6vpfL^0HPXQd#50%KZ&lr03dzQYvB6SV0foSgcsul4abWbni`vaZua&$ks2!? z>J5Mu7%Ver@TQ=cjgSB7f&oJ&%NU;r0tJM=Q?RJP>uUIVOOPxRsaI12Q((+q&w9T; zzT+@~WdzUQ4KaGXgRsc>=KU-ySwqv$&F?G#W-zEc@!p-bYfg^;KgvcLKb9TeU;qFB M07*qoM6N<$f=;~0e*gdg literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..811d67588d7eb74598aa8d62cadc18bdbd4b8d73 GIT binary patch literal 1319 zcmeAS@N?(olHy`uVBq!ia0vp^H$a$!4M=t>=)MI~jKx9jP7LeL$-HD>V0q~2;uum9 z_xAEeUIqmo7DFYjZ}TNo%66QSe88=3p8kHf3?ozL0S=u)Q?Ccy9A}gTI9OT49?eoy zFtB$}5D|#z$ez`3;15G%fJ1`fx=bdf&&(`NjE${3mT_{N;U85z8XBW%V>G7>WKqC> Y{N|&d2d{{_0ZTpxPgg&ebxsLQ0Ps_xG5`Po literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..495e506f75e83cd6a36ef74017e188e94820d170 GIT binary patch literal 2547 zcmeH}?NifN7RN&f5VB$tF%q6i0wlIl9#RyDQ3j|MVtEo35F-4FxKR=c0wp{c!p{{2 zf~n#zXem&~0Cph|u|OISf<@4RrLqdaEQE?kDMZ2$6HG|5KmLGyy)U*e?maVi&N*}L z=bZ1ITM-)_ZijM0!C){udc>hP$jY}C(i++;2;M5lSmefqhr!x^aan@FY(?}#p~nkS zR5PRe^aaO}HDyd+sBBac%Q;#;Z`EmEfqXkgzBa_(Hl5K|Dmiv(F7A*SHgC7nfu29e zFu`ic#IT15+!?qOA9{vyH|P(q4$Yh>W-7NKIA-em-2Mk8O3punjTaV=pGe@Gyg)1s zxm7wE{RTi_Fdzki+=;>@5`DrwLVz(CybO+rFCTq|#Nho)LvF)B+^d|uaK!L7LhOej zK$*nlDh#Ap{u%PWBbJzLoy1yFf7b zDq;YOg~^v?)h5!?emX1A5H^vTX+99rqbIT4YOY%Tnnd$i!qFWv8GY?myGgD+#wF=n zt)%#Kz^0&U(&w7S=e(VJ{SVw1lIzJ+8F1%~lGTHY`qkN=9)1<|NK$NI(tFmwW%KsJ zowu(Xp|7gHWu4A6Ql}}3mcVw#Z}6>S3LP!VCV#?tAF7B+5AfllK|33*ROsf-g^{Ja z-E5`bvy=S&mt~hNmpcUYJ$G00XX>e^4V%(=jxHTaP~|2R++-=nCW2GG!^q34F4ykB zceo3jgp*DQVr&}XGr(i`u)Fvu!`%<=ypQ6KTEWtNBZ^`sM!F5-^&2m-77c%Us-w!y zo-=u&8PeoZconxlBjtEl3fDM zoHP7*Uin%4_=!^48=Sni+mIEt-i5J%*ChbHivF*N_aDv7B~UIifzN$&HlJxbZjCJ< zpgY=!9dqGX_EuheSEN>JP|+iJUrKG9u@E|^4)qt`D0v_SK{H5#mp^VJcvUtNyZ1bC5oun)OzHopp zO@Cz`wXKrHV-vq#W_Fu{^RjfohLtn)z-YW9h?Vbw7eCg{*F8KZI<;p>WZRJrq2{C8 zcpt@#yybti1E)QxV?|qxX_2AM+W!I{>VS)HI{;Ba z#6!;{B0eaEF^FU{E$1yaP-f;${n^fr)B)B$f5Bb*HpA>QXgC-zEXcWG^MwZQ}z-;`|d2Hh%xQHCHZ2jEgxV?8cOw52p>o>TNdp0--rV8qDvl=K9k0Whzsk`n_HN zsljhYapQpr<%MGGjr$!kx+39=pZG3Ij%P)#wHnlQ?$>IeaK76R?zy&)Aj5s^=OpU- zi>EPpqU*r!W4vG9RjX31e~%xyB)jPGYtr)g6Q5d5sZc>O#!eIts(Sm|%#mWAr)s^r zp+-X-|1nJ&2j^4op}@bxz$Ur;Qb=T}EG@b%i~ynfC?J4{u_uUc+P7jNY%z(ISEGB-AL#lKqJ@h(*_qs}FCC12IQmd~7;y1FR~sVj literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..ccab17a36219b3304605599f5594501bf0f72924 GIT binary patch literal 2539 zcmeHJ`(IN>77q|=fTDze_<{zwB({PeuSf#&C<;*mlyobCNNj-?2oXdRUR&T+Ez$tn zn=K+SV6DOmG~Bg9c;i)xM1hpeF3A=FHNnVJA*>{d&~Gs2X6Exb=gc|ZIp@rG z=3;bYn5Fp+a|{M!Ne>T=L08rKz`cjg7m03j=wg%|6BdFI5AB-5V9ajNLxVrfIWadz zYdm|@R=PlTvF}zviYdG$2xHPs+{7WJiAMAQ?U{mx@A@@V(?vHMQ`K6%s z@YUVG!E?Lm-tGsmyq=k;bcE!0dM%YQk+k#EyA84~4d{O+Nirk&4z95j)cXz0zvTkOt&%&l7uNfkHxiGiErSERqqqwzhIE9cU!!Tu>vFPR%@avq^#v-kr%dB{|!0Ta_I=P z;wqaFT%rA<6|4|to#`)zI;S7si}8EQBj@gyW&H5WtHJOwggig>|?G zl!l5+4d-f~|5Nmd39`9%Hf!)djeDXj}#x3Gzu2(v$ zo+|uSXLKe_>MBye11k+cy#UTBJeY(I8j92qjDCnR!{s z3ZyTN0P+m#=Y5^dEO71=7?3sjONxAUuiNIYyo|uPD0qvD;mvceny`@hA6}sMkRutUmu&@GpC>L$qlx^sCxF9BL;8TsKsn4q9NCiZWRsQo@aF46;OzEC8r)<3BM)WW8{&w@QbM)sLm z@K3c4J($l|ep0(LKWZ@s@$70Fkb$>%U5_)hzVELZf+8WWw9RPvb<9i6{()JQY5vl~ zcQ@8P;rHnqz^pMYehXm$D}4R}4Zm|GXCd$#wZo%c-KjUJBwxEKRy_@o4oOF^jbG8& zDZ?+=Ra4TLr--Ul3tujUw4f(yb3`+J6%rT2s%fOyZe-bJn0bFH@keG(seVGZlrk~( zVXxkpFuO!n_0^~JTr*1n8O+mZ1a`+$iw%%jPAZ#WWCOVaiX6|r(C<@~4j(&24Wu9u za4IJP{?LhlO3_lKY@b?ryiu}!Xvrer?M~~+ldtQtH%^e!Oc=1#*VS_ZO-ZUAl8Og) z6$UP30?H#rthd$!j9;56!?YQ)st23zBx~eV;=j$d|8F}E7wnfQ#p)|*WB843-PbpN zcyXZo^t0${)F2R%;@^48;vs*ffAeqL5Y(Fud)L35>Eo9*e-|b7o%F_8v3tSp%%obz z;vf)3%Jr4$%5+VW5Gr2-6Jor5*W!+Kn0rR!TK|3B#PU`s%sAG;mmJQZ-Vxan_$;9l z9ld}d9$?1dfwtxmhLAcW$$>j23nYa(+STb@DLUaE3M>%%6)!+{yLGp8jVK#ruNr__ zzuxfM+;ujH6OqS5;d^9#IZ#0syOB2Ym6Osz=Nf9((YR4()k!vmWJrc6xBF|N6w6ST z_95>{tz7&a4P~a_GFku62O~qpAuRBBQ7k^~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..0cfb86fc6057b82ca33d6f293caa834f2a5122cc GIT binary patch literal 9290 zcmV-QB(>X#P)PyA07*naRCr$PT?v#_#ksDYeY$(5X8{LhfS0(HVF*=Kgo;R@c3^ z>h|qBJwTr`r+d2V)~#Fh-S7YYzy7N0BS&9Hdmw`z@MUo9(L;~+067Yvqaetr2aa?A zxq1Dmj7DOJ9_(fZ=5iN^u9N>xwJ&(UhyZlhgG#m2av3CS+t}+8ea7$Lo&5}TSoH}D z2>cB1>}RNh{~z0S*a7Nr0uT=b1OtM^@IHC+^p)=hP8&uO-kE2)Bz-74;CnSgpj<` zCrvsto=nb55#me5h0LG1TFpO3(A#OEVYK?8V}GGKNnP|;8V5U*QU;N(r6IPt7xDm5>eNKn9ZcX!j# ziA5q5Ac;gmBNz=F3}ASsVF!-d9ImWhUhq8&uKfIb3MOQ$U@%DXi;I^43O6@4F0ujB zkkCs*0YD<)plLcQkxbr}OeUv;NdnM-Ndmyc5ilClh%^lX0Zu@fg?Yh$X5XW!O9Pq- z*z)qAxr6|q07UQ#1OlX>sAviC`4CKia5yc?OgYa;xeOpP;N%0_q*AGQeUZp?01bdA znMhEUVSylG4;>~V22x-e)4FZy01zRVz{CN&g+ifsd<6w>Z*FV^69+)zbyLm)DHj1G z0uJ%K7nv;qgUK)+f~mB$l$yCR&`d=| zOEz!W0zirn1t8@bfOwZ1fRlg5lqvJ0vDmF>rXqcPI@>q`h6hX|rK7ZVfB*+G2Y>=r z3I+nCu(%k21Uf0F87Wr)#Ig?6HvpU|Q>L6v;_-Q%-Q8#Obam-s7`-G_jiOp!sC6_i zj2G7Eoe94exKq65!XgMH&`R)ESXj7Z^R{gOB%YCS!mQ;2fcUsg!PKc!&q~GP^CEqH zRO9r4sRB{#26L#GD@6~?)MIndZeSx6-4&IUO9>%wHg4PYx@Oi;aGOQEJ&OPgCV=qV z$T;v`FlFMzR}naoNJOY{bS8n=3onKxy(t-uk`1rSlBopO1B?`^sG#A1U?6a>fQ|YC zS_9K3o`DBWG*|#iV;wM8zC>bPb93_<036n%QjNt7MtRrHDPSvLBG5@?<>gc#6@k#+ zw(TxWAF*uYdF*H~0K^6WK_nMUn>=|zI2`^Nn5%F&OuZ_rIE-Tk$`WIl#f4ncTpFk7 zX05D@R8>~8Y=lDFbCc#JfOwMyBKd2;Iv|p}Iy*^%bIA?7tP(jM44tE@mmKIKv`qjc zFl&{Sl}j79Z3CA-#(8U=nKZ8e#F{M1I+G_)K0DUi`$|_=7Zu6+R0BqU2Skd&raN-m zRRCq?Wtp|dDlR0!cxGD6PNShVqMlko!ICZ8x1*=#sY&w!Ks((H~@8GMsL)^EoQ?s~myv-V`E?*7w>rH$_Lmz9yqii&$R5Fs0hCTd+5*x3dU zuXhST?{su_&h6~%q#jn97sbv&nccyn?{kf@tl~w2VKf7Y%=fxUtEgDYfry`18&UvD z2hY^03p(1{=XQ2<^m|!O8ADZXXF&8k-DO zdn|Mjcxa)Dia-DLqmTZL^UzQixn|1T22dLFoIZK-!sbJVZte+(sopV-#LC?1DtD>} zjHSvz!t!o!>Z~!Qvjjq zqTnHf6rbGC&CjwgZTcIp!ErQd&A=`;Hy2F(ArF z4`l)%R`-DEDxNxN(t;XKl|+8HO~x~D5Ge#Qvl&{sC$Y|@1LT$xvjOe|1wSNw;i)c|L%lg+`6k3 z>oL#rFICWWodq)SI--473_GK4I)|tR= z4$OjK?6i~!&{FwEs&{;jGZ0=*RaF%UghJ=-+_{rAWynNIGRO&lSlt7rtK=k2_weB1 zTVfS~mS!HSyWa^jC>~=rH|2?ra=|NucET+F$dM!8{rj$6V9H>vH{A7np0yN^oC1jE z^bkUdPM$kF2dF z)22-$C!KsU^&|=k!QoSXS+R#|ZEn@YieOmxwr}rVvT5T+^5=KnA+4w$ASEdS}0k3P)q=oJ6?Kiczw;P7Yz%dq{n4RVUmbv1}E6I1R zxPqK;!U@y`J(6CKxv+WDCi3uaenZx;Ur$opCJ|C5S7Z^mF#%InU0r?t$De)*f|~Wp zq*i#y0*DV7mW-{hZ|Q=7A$VOfOk?9^@mgcXj2YyoH{C?)>+26&#<9C0VzC(c@PiM? zqC4*-Z@&c_p!H8;xjDB6b=K9@0So;nA*4?=z^DQsU>~4?qN$T6Eu;ZMHmlG^$FNkY zcbo}Bf#zAVbSe4TIp-X4%)^5Um}vcrFOs=8-e}N7{Z=iriC#Qcsozg(M~;Np5G3Za zg4&jaWB|mn5A5SsI<~(4P+LojCG(^K#>86^+31UA&LlU@olCxa?6Gz?=@Ie!&K*0* zowwgkUViB%*BJ;k6U2tTIB=j^m4##hgzQ77E1ER+v5GdcBP*+mu-wAiZzosGo=wWi z%8m$t*j*&(%#|xvP!JhzOck%phONLcsjaKK@b8~}1|FF-3)ulEoqbL`@eu2_vyoxGJm5+je75s-Mjxog@t4Q zq_fYI2@@9V*|UdgAFG!v;}|@#expvSUH0gsibtJMI9asSdaSwjly@rn1QuT0RIG2nGVK?}H5+$n(!VN8W$$J+k+UFVc6d zw^~u6;1%gita^+KEMupMfQ8yRJCD)K7-}J5=AspVP&}8woY%g6`wVklW_OTm{!f}F zV!Sc0830&xyZI(p2Q zix`)log*{!f(StTv_Dn3VStKs`M@IViFVP6VAF@wUqz*ZdaNe6a{uVI0}nctXeu54|v$>3(eWYSPx$CKmmYc{m1! zQCL-?I=gOr9y10q%M&vB9?nx+Tl?OwrY4LD3C$P}pfvBR;rQcUYHe$ql6HGa#CzCd zRHD;fF%XF7t7p$9zklVG{2DcO}wRBJGg|V!^-y@V9Q+LO$BQ-Oz3`O=NW*GcOV#(lKmPjq`uS~#4*l3o#u43#d`2UfFfSO0 z1(2B*Y3u58WzgNM1ORmRqDAEA_uXe?P8YpGtXR`Q-_*=lnhs(C#KwQneSfLFy**w3 zAl-|4ML`>xvDETatH=c&%*OK!WJpEPt}RyqbkE|&1b2#tZ4qga*Ac-iS79zd-A z35>3*+uH|GSwyyk*Og|&ZT5W@l?M~%B?G+xtqavDRAS*9fb>)U= zj7Qei&f4A71OS3$Fo*}~=^Y3lKKsyr!k521zrDTv2C2C(1#Kj(k88D;40QQrml@o6 zUQ@JpcdOhto|I+1FdiUgD^u+>kyXQMN00v1uHC!gp)N2lhC9B}^bQ_Cbi)LAD)kA+ z9d}!MYwPt^6+4{=OYw-qA6c4y;RFnC$GmmjFTrGK&ML00>r+ZrQSh{Ql*a$(F`OnpZS@ z_;7Oiv}xqLZ+#221Qn&3zL0@uSHT}V|GIGi( zr;r7=-%d`OFo6^l0MR>tSpi7zXP4Lq>MIQdHnewkp3ita3qPi=?)h*} zj}bs3L}!>E#Ctt(hdjD^wP#)!FpyOoNCrSKppeP9c+n#A#hyJhkDAvU0HjmLjUx{) zTSgkjj?IXPL;zCRl|vP}fnab$YexsHvjRZ~uDmIL^cYZGO-++ocAiWFoO)qUx2FuG ziDE6c}iDW#vEMglS%rON_%Z5B<#8ZqFIW#Epk$$pGl3_3OzE*I!Rs zo0|ui$0R5Ew9`%_zkBK_GI}(OhqIRw16kzz$evvbCXUen1g^X#fcyZUVHFjhTb)3d z>FYoviI{3A0SI)??|%DRa{aZ}rgfKy)hes1$e-SPlN@*a@v`HWR?dupoWz4<8xct) z{)rF*Gs}i8U|0syqtF1L>QLx&t9^fDPb|!Vwuu{g383$Q3FGsDnD%w_Kq`#+3jp-^ z+O_(cExT130HD|3c!L~&!U?inXbB*zK%q>&k!&M00D%TV2BMpCngOV+x}svYZdzo| zB2i8>NH{9Twi1v_ylmG-8=-E^%HOc91l8F~Km<+`078wA+Qs}3je3IO~ zcriJ6;D8WBu;=5r@#D!O%a)P)h6dN%cqg;)s$-g;pZ`HP8oh`U(P<_Om-0{%T~|}{ zY+qmBBt5<$T2-Mi2gWyAsExEj0H6ymg7#+j1;IX=6K#_ zPc@Lmy0A`Wrw)nB@T3R;Xz^Wl8ItPV1`T^5l~q*_?LTzr9=pj@urT!LJHS9=#*8_q zyS@E!Cq0sBp3q=35bN3GDu5uRl{aD80#UG{;_{Z37Fd0mw!qLV9|%0Lva0g(zl#`# z->J)$d?98oY%mzeY&JVr0fY=>mx1Vn0Qh4fiNuM75ZJl|ck0le{A`-i3IM7sEBllU zCJMc;exsXFJ9%9+7yzP|A-I-Y1rX0b*WVi_ot@v%ELFF*go-e~k<4M4y^hSjO2 z%X+|-uNgM%*=Qubl#O9$WM698{RUUd_W(4Ix2 zuc~_Z(4j-Z7?2r&aBI6Dn6ZkovK^{v;4-lus}A>yfna-=S(jWwUi$+qc}jo5bQOTXwU?-aElkw<_h}K9x9~E%b!Z6QWFdj zX@v&xMP=efs~&sIlQg*d40^605SoU~pMWM+a;H0v;HyN;N#)*>Zy^nweN#eNG}0S>v=(GK|C5 z?InO9hiC3hH<2BG`8lz-YRJRWbg#T|`E z0}F+ML1i6eYVQYZf$24P2_Tp;zkR_1^5hdw5Lnw~^%`{MfyTMW`gYeE?bkmT|1m7* zu>ufIY0xFkR7jVXKS{KBkQb3@0MJDqs5(DJh;^h#)H6&1w+B$Q-qKS^hk+2Qns-=)emq! z84Lj7>Dk9U0W%H80E+q!7B61=!yl@4tE2Ko#lUwRG@Td5U*V4WDc z^Fc6U@knHqT~N_VBgw8aqZ(-DOh*@gxE{3b>8I(I#9q8O^CfiOtxTB6jG;I7I|4yP zhc8)ubQD189qbi=wBX_8GUf|`B7y^N#%NHns;cVjcqH;D%R)}#JXZLF`c@xhptLUX z3P66pe|cM17w>%upVT7*AQ02^k(W$N=y8%ton|I1_3ty#Ny}EOAQxYH>Cwl2Yn=&m zUl6CdX3iXk+%I>SCZ4~-#C{B`PVXQ@W-%YN% z`f5^MUhecXht+Z59j;imj4Yf#KdaYOSX{iKI~@Kw6Z;Vc5A8%WtB=51v70VXEmT%o z`d25*p6yH*{XLZ;mt1-&x%IZ&$g#&Am(>m%DwV@D3q;Fd4Su#>8vFb+qkSyJvz>@$ ze>d!2Pgy7wx-k}uec#R_qj+$zpAhUN_`olJN&fX4-=JH>9my|9IeFpv=gEyf`3Y%l zZOvL&XzcTVfPK!05&U(X| z@;TRBLuSvJL+b16k2od*=GnAyBl-1%50V#Ocp+;6O#lxB4!gr)GxkA4A_TCE6+)Mu z4J^{=ba^1~TVx^G7>~+r1R(n6j2Q$T`qt3UK!yz;P6C0zVarJ1ZFO~Zk^TGj5!f3gKq~DSsr>lK07%3_7#BJ#*4yjYBkR}9{m&`4 z%D1T-HHu81KAn8!lvBttH8rHDs7QF67x^+W?Nzx+*s{?`gzVkBmu&p-LkgU1Y96GO zU?}vx*4EZHm`PL2It1-w$vy}Snd@a)2sh&FXCc4;@svqiNTy;eBa>@mRiEndD&=M7 z!({4{DWlS7nU*aqE?(Ik4#Q&)an1|ecEh?ayK~4g5X(Xs7oyw1XdqgXN~OjlTNtjzC~mvcyAF8C-A`q}C(|ys%V@%R9A~8=Z$0qT{jyFH=sYjN1UQ>px96^XvmN?uMLayLPDn zh-INPL0wT+_Txl6evM&OLI(LlhI|`^dW6hp(F@Au6`02hO=dU1{O_9A1*Ypk#&oek zLtEj@*69R5a10wZ06l}tSa#l@?8!r@;t z;9)mR(4PY)Qx`IdY*{SF3u>5Xh1gJ_G8Fo1w6D+7l)0{rY;uaz?m$TfVYQA-2idLK zkf|fvWi;Ib={S%i27dq^!^YvF2~(?fsWK1?B48mjWjI?O4Ep{5l1d~VvC~5$YRx3m zQH4QN!9g{Yq<)eumu;|^n65{=`(r)`9-M8*Y(rfx%C;{P0I{YFGZ#Tr2SS0skK^(9 z)qH%%4NYLU(Wf#CDUHJm8h}0HOIquMBrK z13g5iIzoZKbqFE@tR?Scs}6O-HhLQr&M(U*vgNV~60^FYuL_HcS82KjO&5TN4H!Z( zW$-xFKx|u)g)rp<=gO!i(m3{taWcP&DJibCtX< zHyMZpAbMr^yfI{=K%lgACCR`ubILZ37^h$CND)OYvkqQ>=5Yad05tdq%mbT5Io3Tq zgGhClMIrRcSW(R~ksm;mN+iaMgmuP@BZ_z{T#+mgh7$9@<>%$)ZSIZ5t`UF-rz(_P zc2T!xqJelIvZ5N92uvCLm4*U=Yh$t493hAXl&iwfrx%q41AC;(F)C#@VKFYtUv^w8OuZzL{R{dLI*kZq6RQ&Kikg($}T%Vq4}N`)dVwWo`*H& z0nv#92r6xv;{({Zz_*A7H5cLpGWcL323W6|hUnKs5LdpJE#wiDbgrl>&%}gQd zfXU+HJXr%zHcgnBcZLybTq2|csVorqQ7jUfV{6hRa;U8aY^cR^_-o0_%LCR~84icv zW5C1e9o$LYRd35n5iL3wA8drVGh8ObvQcqaAn=1&Br;nDNKWtUp~g5=%MHYLV3QzV z82}CIWucqSZiFBgR(INw+%~@%R3mjLf(R#I+4(cjMhK*0zu!M4-{+eYi$<@MomvoS z8=2X3sg@67Ax7%}>%6Z42N?%|1i(SP!;0msgU2fq#+x(vANOGd5aGt=03rku{S0gr z?d!YBj*aY0)*z0*<5MGWNI}8s-rimS4giG(4uS{sn89R8C&N2#71fE*7uTN;!GM!6vask;q25FYgwU z>m_BgKdkCzO&YrTsErUr$V%{D81VbQ7q`$yLs8r4rng_?G?IdXHNCyP8#KlNpdfhQ zGXh5>lsyGbE&zx%p~yxokdTd7Fu`XEq+~2MK9NkGIv94?%{z`URXlJIJS=d)Twzps z&{#*LN!;ucCw1{`#0DS1TVqWd1rY)X^i(VoxiVMo2$_pVs?Zn*G!8HhunOuLo^3?H z!DKMRmp<$eUZL?7W4KNA-2meH7DyM;y%K&2A zW@g&Z{Ri+MJK<;eAO5gRUcm2%%sd|ts7!6S$aduC<*|U-q)lW37|;yiI}0F;3dy}bYyjK#n^G6({O1rZzg!#EB`kVR7vgQ|0eGJr&84XqId zBiW!N3mDO7{0@&nGs#Z1VEufIjMW}EL5YBY|M4>dhXs)6GXjR6ddMk_W5*nW5lFOa zlilxTtRw;yvJ?*-_+JDf_>Kh-oQu8tS>PaOc<`73iDf4icv$C<0?ts-K(avM2b^US zUWoG`;~9uGlOhIUQzOvSu)tu!B>J8O3!i3@vu5gWFkz}-G6NM4E*>!WzsPA5nJ^I` zSPjGf4)yYkW_N8l{rgZfVRjwLUX$oE4-(cS^1#90M1#%)iUkMDEn+a literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..4484669b29607487e1769179476489c3c522e505 GIT binary patch literal 2951 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 F|2HoSUwHrk literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..231b4c70eb911a9b3737a4d36be59dc8fda780ef GIT binary patch literal 12432 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 heSNI*PfPdLJ`{83B>-pDD-mcB9y{6Bk5odEy< literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..b5126f5c45fc8ec231642907b8d7650c214b222d GIT binary patch literal 4235 zcmeAS@N?(olHy`uVBq!ia0y~yVB7%09Be?56MhC-K#H+A$lZxy-8q?;3=9IUo-U3d z6>)E`UgTs@;Bj{BmValzu_@YSho696>zSLs_1qg67@1g-n34}9^>%uLIPnJ>Dp{CV zI0QVnBsQevIteQ{G&C@NW(JBVOb{_hIC-l@%>k&8`58M<#6dwb;lQM=oW3BfY-jj^ zA`K2f2O3nfg=c|G=9wW66k%vw(!l6_P0a)-!XaT`57N)%$;doyjc*3XDuaYNkO<2p zCN`bO*%v@oB^>wz65&u`<%!s2wvZEO@PUS(AdyjrjfU808XL`(qs7H&0XteHjnv}rxs85!**jrJ?4-xL49;Qjs>L-35RUBJ-=22WQ%mvv4FO#sOsIE?@R literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..b851eea04d0f32341d3ec171b9b39e9d4a98548a GIT binary patch literal 7404 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..320d544ba74eee694d467133ec98c2ad8dd225cb GIT binary patch literal 7332 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 + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..31bd9ba --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,25 @@ + + MyWallet + Enter Your Email + Enter Your First Name + Enter Your Last Name + Login to My Wallet + Enter Your Password + Forgot Password? + Login + Signup + "Don’t have an account? " + Account Password + Account Name + Name on Card + Card Number + Bank Name + Expiry Date + CVV + Add Password + Add Card + https://bin-ip-checker.p.rapidapi.com/?bin= + f5204a5f14msh4f6ce93e987ac89p10f514jsn1152d1ec2f1a + Currency + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..7b6081c --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,6 @@ + + + +