diff --git a/.idea/.gitignore b/.idea/.gitignore index 26d33521af10bcc7fd8cea344038eaaeb78d0ef5..8f00030d59afb017d0955c2cfcd5c2b931225207 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -1,3 +1,5 @@ # Default ignored files /shelf/ /workspace.xml +# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 32522c1e7054e664d0b44bf5c384d6e06213b9a5..0897082f7512e48e89310db81b5455d997417505 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> + <component name="GradleMigrationSettings" migrationVersion="1" /> <component name="GradleSettings"> <option name="linkedExternalProjectsSettings"> <GradleProjectSettings> diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b1ffe673c8687ba4f20c7bbfcd4cc690f51cbca3..f7505cd6720bae64f398ffd651864da9352c2da8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("com.google.devtools.ksp") } android { @@ -9,8 +10,8 @@ android { defaultConfig { applicationId = "com.example.bandung_bondowoso" - minSdk = 30 - targetSdk = 34 + minSdk = 29 + targetSdk = 32 versionCode = 1 versionName = "1.0" @@ -48,7 +49,47 @@ dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0") implementation("androidx.navigation:navigation-fragment-ktx:2.7.7") implementation("androidx.navigation:navigation-ui-ktx:2.7.7") + implementation("androidx.legacy:legacy-support-v4:1.0.0") + implementation("org.apache.poi:poi:5.2.5") + implementation("org.apache.poi:poi-ooxml:5.2.5") + implementation("androidx.concurrent:concurrent-futures-ktx:1.1.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + + val cameraxVersion = "1.3.2" + implementation("androidx.camera:camera-core:$cameraxVersion") + implementation("androidx.camera:camera-camera2:$cameraxVersion") + implementation("androidx.camera:camera-lifecycle:$cameraxVersion") + implementation("androidx.camera:camera-view:$cameraxVersion") + implementation("androidx.camera:camera-extensions:$cameraxVersion") + + // ROOM + implementation("androidx.room:room-ktx:2.6.1") + annotationProcessor("androidx.room:room-compiler:2.6.1") + ksp("androidx.room:room-compiler:2.6.1") + + implementation("androidx.room:room-ktx:2.6.1") + + // Google Play Services + implementation("com.google.android.gms:play-services-location:21.2.0") + + // Coroutines + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") + + // Retrofit + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-moshi:2.9.0") + implementation("com.squareup.okhttp3:okhttp:4.9.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.9.0") + + // Moshi + implementation("com.squareup.moshi:moshi:1.14.0") + implementation("com.squareup.moshi:moshi-kotlin:1.14.0") + ksp("com.squareup.moshi:moshi-kotlin-codegen:1.14.0") + + implementation("com.github.bumptech.glide:glide:4.12.0") + implementation("com.github.AnyChart:AnyChart-Android:1.1.5") + implementation("com.github.PhilJay:MPAndroidChart:v3.1.0") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 62c8febabba468ceda857a8c837483b1e0f6f93f..3a9e66b67af683a17318e0721aa642ecd6dc7727 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,20 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> + <uses-feature android:name="android.hardware.camera.any" /> + <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" + android:minSdkVersion="30" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + + <application + android:name=".BandungBondowosoApp" android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" @@ -12,6 +24,11 @@ android:supportsRtl="true" android:theme="@style/Theme.BandungBondowoso" tools:targetApi="31"> + <service + android:name=".service.JwtCheckerService" + android:enabled="true" + android:exported="true" /> + <activity android:name=".MainActivity" android:exported="true" @@ -21,7 +38,27 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> + <intent-filter> + <action android:name="android.intent.action.SENDTO" /> + <data android:scheme="mailto" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> </activity> + + <meta-data + android:name="preloaded_fonts" + android:resource="@array/preloaded_fonts" /> + + <provider + android:name="androidx.core.content.FileProvider" + android:authorities="com.example.bandung_bondowoso.fileprovider" + android:exported="false" + android:grantUriPermissions="true"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/file_paths"/> + </provider> + </application> </manifest> \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a25acbab193219bb4f9aff1a35ddb2266de1ae Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/example/bandung_bondowoso/BandungBondowosoApp.kt b/app/src/main/java/com/example/bandung_bondowoso/BandungBondowosoApp.kt new file mode 100644 index 0000000000000000000000000000000000000000..49bb4de20a98106aad5bb2ff07f61c8347503af4 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/BandungBondowosoApp.kt @@ -0,0 +1,20 @@ +package com.example.bandung_bondowoso + +import android.app.Application +import com.example.bandung_bondowoso.local.AppDatabase +import com.example.bandung_bondowoso.remote.ApiClient +import com.example.bandung_bondowoso.repository.BillRepository +import com.example.bandung_bondowoso.repository.TransactionRepository +import com.example.bandung_bondowoso.repository.UserRepository +import com.example.bandung_bondowoso.util.Config + +class BandungBondowosoApp : Application() { + private val database by lazy { AppDatabase.getInstance(this) } + val transactionRepository by lazy { TransactionRepository(database.transactionDao()) } + private val sharedPreferences by lazy { getSharedPreferences(Config.SHARED_PREFERENCES_NAME, MODE_PRIVATE) } + private val authService by lazy { ApiClient.pbdApiService } + private val billService by lazy {ApiClient.pbdApiService} + + val userRepository by lazy { UserRepository(authService, sharedPreferences) } + val billRepository by lazy { BillRepository(billService) } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/MainActivity.kt b/app/src/main/java/com/example/bandung_bondowoso/MainActivity.kt index caaf15763d48060c9443598075fc2c0845713175..81b3533b54b05886f18347e2ce36cbdfbed3c823 100644 --- a/app/src/main/java/com/example/bandung_bondowoso/MainActivity.kt +++ b/app/src/main/java/com/example/bandung_bondowoso/MainActivity.kt @@ -1,35 +1,214 @@ package com.example.bandung_bondowoso +import android.app.Dialog +import android.content.Intent +import android.content.IntentFilter import android.os.Bundle -import com.google.android.material.bottomnavigation.BottomNavigationView +import android.util.Log +import android.view.View +import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.ViewModelProvider +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import androidx.navigation.NavController import androidx.navigation.findNavController -import androidx.navigation.ui.AppBarConfiguration -import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener +import com.example.bandung_bondowoso.broadcast.jwt_expired.JwtExpiredReceiver +import com.example.bandung_bondowoso.broadcast.jwt_valid.JwtValidReceiver +import com.example.bandung_bondowoso.broadcast.randomize_transaction.RandomizeTransactionReceiver import com.example.bandung_bondowoso.databinding.ActivityMainBinding +import com.example.bandung_bondowoso.service.JwtCheckerService +import com.example.bandung_bondowoso.util.ConnectionStateMonitor +import com.example.bandung_bondowoso.viewmodel.AuthViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.RandomizeTransactionViewModel +import com.google.android.material.bottomnavigation.BottomNavigationView + +class MainActivity : AppCompatActivity(), ConnectionChangeListener { + + lateinit var binding: ActivityMainBinding + + private lateinit var jwtExpiredReceiver: JwtExpiredReceiver + + private lateinit var jwtValidReceiver: JwtValidReceiver + + private lateinit var authViewModel: AuthViewModel + + private lateinit var navView : BottomNavigationView -class MainActivity : AppCompatActivity() { + private lateinit var navController : NavController - private lateinit var binding: ActivityMainBinding + private lateinit var randomizeTransactionViewModel: RandomizeTransactionViewModel override fun onCreate(savedInstanceState: Bundle?) { + Log.d("MainActivity", "onCreate") super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - val navView: BottomNavigationView = binding.navView + authViewModel = ViewModelProvider(this).get(AuthViewModel::class.java) + randomizeTransactionViewModel = ViewModelProvider(this).get(RandomizeTransactionViewModel::class.java) - val navController = findNavController(R.id.nav_host_fragment_activity_main) - // Passing each menu ID as a set of Ids because each - // menu should be considered as top level destinations. - val appBarConfiguration = AppBarConfiguration( - setOf( - R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications - ) + /* Navigation Related Configuration */ + configureNavigation() + + /* Auth Related Configuration */ + jwtExpiredReceiver = JwtExpiredReceiver(authViewModel) + LocalBroadcastManager.getInstance(this).registerReceiver( + jwtExpiredReceiver, + IntentFilter(JwtExpiredReceiver.ACTION) + ) + jwtValidReceiver = JwtValidReceiver(authViewModel) + LocalBroadcastManager.getInstance(this).registerReceiver( + jwtValidReceiver, + IntentFilter(JwtValidReceiver.ACTION) + ) + authViewModel.isLoggedIn.observe(this) { + Log.d("MainActivity", "isLoggedIn: $it") + + if (it == false) { + Log.d("MainActivity", "onExpired") + if (navController.currentDestination?.id != R.id.fragment_login) { + navController.popBackStack(R.id.mobile_navigation, true) + navController.navigate(R.id.fragment_login) + } + } else if (it != null) { + Log.d("MainActivity", "onValid") + if (navController.currentDestination?.id == R.id.fragment_login) { + navController.navigate(R.id.action_fragment_login_to_navigation_transaction) + } + } + + if (it != null) { + binding.loading.visibility = View.GONE + binding.container.visibility = View.VISIBLE + } + } + + /* Randomize Transaction Configuration */ + val randomizeTransactionReceiver = RandomizeTransactionReceiver(randomizeTransactionViewModel) + LocalBroadcastManager.getInstance(this).registerReceiver( + randomizeTransactionReceiver, + IntentFilter(RandomizeTransactionReceiver.ACTION) ) - setupActionBarWithNavController(navController, appBarConfiguration) + randomizeTransactionViewModel.isRandomized.observe(this){ + Log.d("MainActivity", "isRandomized: $it") + findNavController(R.id.nav_host_fragment_activity_main).navigate(R.id.newTransactionFragment) + } + + /* Connection State Related Configuration */ + val connectionStateMonitor = ConnectionStateMonitor(this) + connectionStateMonitor.enable(this) + } + + override fun onStart() { + super.onStart() + stopService(Intent(this, JwtCheckerService::class.java)) + startService(Intent(this, JwtCheckerService::class.java)) + Log.d("MainActivity", "onStart") + } + + override fun onResume() { + super.onResume() + Log.d("MainActivity", "onResume") + } + + override fun onPause() { + super.onPause() + Log.d("MainActivity", "onPause") + } + + override fun onStop() { + super.onStop() + Log.d("MainActivity", "onStop") + } + + override fun onRestart() { + super.onRestart() + Log.d("MainActivity", "onRestart") + } + + override fun onDestroy() { + super.onDestroy() + Log.d("MainActivity", "onDestroy") + LocalBroadcastManager.getInstance(this).unregisterReceiver(jwtExpiredReceiver) + LocalBroadcastManager.getInstance(this).unregisterReceiver(jwtValidReceiver) + } + + override fun onConnectionChanged(isConnected: Boolean) { + Log.d("MainActivity", "onNetworkChanged: $isConnected") + if (isConnected) { + Log.d("MainActivity", "onNetworkChanged: connected") + } else { + Log.d("MainActivity", "onNetworkChanged: disconnected") + val dialog = Dialog(this) + dialog.setContentView(R.layout.dialog_no_network) + dialog.window?.setLayout( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT) + dialog.window?.setBackgroundDrawableResource(R.drawable.bg_custom_dialog) + val okayButton = dialog.findViewById<View>(R.id.dialog_btn_okay) + okayButton.setOnClickListener { + dialog.dismiss() + } + dialog.show() + } + } + + private fun configureNavigation() { + navView = binding.navView + navController = findNavController(R.id.nav_host_fragment_activity_main) navView.setupWithNavController(navController) + navView.setOnItemSelectedListener { + when (it.itemId) { + R.id.navigation_transaction -> { + if (navController.currentDestination != null && navController.currentDestination?.id != R.id.navigation_transaction) { + navController.navigate(R.id.navigation_transaction) + } + } + R.id.navigation_scan -> { + if (navController.currentDestination != null && navController.currentDestination?.id != R.id.navigation_scan) { + navController.navigate(R.id.navigation_scan) + } + } + R.id.navigation_graph -> { + if (navController.currentDestination != null && navController.currentDestination?.id != R.id.navigation_graph) { + navController.navigate(R.id.navigation_graph) + } + } + R.id.navigation_twibbon -> { + if (navController.currentDestination != null && navController.currentDestination?.id != R.id.navigation_twibbon) { + navController.navigate(R.id.navigation_twibbon) + } + } + R.id.navigation_settings -> { + if (navController.currentDestination != null && navController.currentDestination?.id != R.id.navigation_settings) { + navController.navigate(R.id.navigation_settings) + } + } + } + true + } + + navController.addOnDestinationChangedListener(NavController.OnDestinationChangedListener { controller, destination, arguments -> + if (destination.id == R.id.fragment_login) { + Log.d("MainActivity", "onCreate: fragment_login") + navView.visibility = View.GONE + } else if (destination.id !in intArrayOf( + R.id.navigation_transaction, + R.id.navigation_scan, + R.id.navigation_graph, + R.id.navigation_twibbon, + R.id.navigation_settings + ) + ) { + Log.d("MainActivity", "onCreate: not navigation") + navView.visibility = View.GONE + } else { + Log.d("MainActivity", "onCreate: not fragment_login") + navView.visibility = View.VISIBLE + } + }) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/connection/ConnectionChangeListener.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/connection/ConnectionChangeListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..08acbf98edb373bb4a2637eed347854b32a74cb3 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/connection/ConnectionChangeListener.kt @@ -0,0 +1,5 @@ +package com.example.bandung_bondowoso.broadcast.connection + +interface ConnectionChangeListener { + fun onConnectionChanged(isConnected: Boolean) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/connection/ConnectionChangeReceiver.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/connection/ConnectionChangeReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..81ce959bf1b133d3c74a1337f87a0372a9ee909e --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/connection/ConnectionChangeReceiver.kt @@ -0,0 +1,22 @@ +package com.example.bandung_bondowoso.broadcast.connection + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.net.ConnectivityManager +import android.util.Log + +class ConnectionChangeReceiver(private val networkChangeListener: ConnectionChangeListener) : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == ACTION) { + Log.d("ConnectionChangeReceiver", intent.action.toString()) + val noConnection = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false) + + networkChangeListener.onConnectionChanged(!noConnection) + } + } + + companion object { + const val ACTION = "com.example.bandung_bondowoso.CONNECTION_CHANGE" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_expired/JwtExpiredListener.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_expired/JwtExpiredListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..f12573f64066401f72af30dc87859c29bb2376a8 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_expired/JwtExpiredListener.kt @@ -0,0 +1,5 @@ +package com.example.bandung_bondowoso.broadcast.jwt_expired + +interface JwtExpiredListener { + fun onExpired() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_expired/JwtExpiredReceiver.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_expired/JwtExpiredReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..b35b2538c4e142c221a1aeff957f86d4d31c6164 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_expired/JwtExpiredReceiver.kt @@ -0,0 +1,19 @@ +package com.example.bandung_bondowoso.broadcast.jwt_expired + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log + +class JwtExpiredReceiver(private val listener: JwtExpiredListener): BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action == ACTION) { + Log.d("JwtExpiredReceiver", "Received intent JWT_EXPIRED") + listener.onExpired() + } + } + + companion object { + const val ACTION = "com.example.bandung_bondowoso.JWT_EXPIRED" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_valid/JwtValidListener.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_valid/JwtValidListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..4ac6c69e57811349df590dc4dd30c053bfd12f62 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_valid/JwtValidListener.kt @@ -0,0 +1,5 @@ +package com.example.bandung_bondowoso.broadcast.jwt_valid + +interface JwtValidListener { + fun onValid() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_valid/JwtValidReceiver.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_valid/JwtValidReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..01cafba8a1efa79fdce062c791d8bfedcdfa8742 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/jwt_valid/JwtValidReceiver.kt @@ -0,0 +1,19 @@ +package com.example.bandung_bondowoso.broadcast.jwt_valid + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log + +class JwtValidReceiver(private val listener: JwtValidListener): BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action == ACTION) { + Log.d("JwtExpiredReceiver", "Received intent JWT_VALID") + listener.onValid() + } + } + + companion object { + const val ACTION = "com.example.bandung_bondowoso.JWT_VALID" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/randomize_transaction/RandomizeTransactionListener.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/randomize_transaction/RandomizeTransactionListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..64039cc468635777773b146ad55a2aa77dcde024 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/randomize_transaction/RandomizeTransactionListener.kt @@ -0,0 +1,6 @@ +package com.example.bandung_bondowoso.broadcast.randomize_transaction + +interface RandomizeTransactionListener { + fun onRandomized() + fun onReceivedRandomTransaction(transactionName: String, transactionAmount: Double) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/broadcast/randomize_transaction/RandomizeTransactionReceiver.kt b/app/src/main/java/com/example/bandung_bondowoso/broadcast/randomize_transaction/RandomizeTransactionReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..381bcfd42ea8983da069d07378004428d396dfc6 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/broadcast/randomize_transaction/RandomizeTransactionReceiver.kt @@ -0,0 +1,28 @@ +package com.example.bandung_bondowoso.broadcast.randomize_transaction + + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log +import android.widget.Toast + +class RandomizeTransactionReceiver(private val listener: RandomizeTransactionListener) : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action == ACTION) { + Log.d("RandomizeTransactionReceiver", "onReceive") + Toast.makeText(context, "Randomize Transaction", Toast.LENGTH_SHORT).show() + val transactionName = intent.getStringExtra("name") + val transactionAmount = intent.getDoubleExtra("amount", 0.00) + listener.onRandomized() + if (transactionName != null) { + Log.d("RandomizeTransactionReceiver", "onReceive: $transactionName $transactionAmount") + listener.onReceivedRandomTransaction(transactionName, transactionAmount) + } + } + } + + companion object { + const val ACTION = "com.example.bandung_bondowoso.ACTION_SEND_RANDOMIZE_TRANSACTION" + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/helper/LocationHelper.kt b/app/src/main/java/com/example/bandung_bondowoso/helper/LocationHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..a5d5e066c483f9bd13c4487fcc1d18083a6a3cc2 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/helper/LocationHelper.kt @@ -0,0 +1,34 @@ +package com.example.bandung_bondowoso.helper + +import android.content.Context +import android.location.Address +import android.location.Geocoder +import java.util.Locale + +class LocationHelper(private val context: Context) { + @Suppress("DEPRECATION") + fun setLocationByLatLong( + lat: Double, + lang: Double, + ): String? { + val geocoder = Geocoder(context, Locale.getDefault()) + return try { + val addresses: MutableList<Address>? = geocoder.getFromLocation(lat, lang, 1) + addresses?.firstOrNull()?.getAddressLine(0) + } catch (e: Exception) { + null + } + } + @Suppress("DEPRECATION") + fun setLatLongFromAddress(address:String): Pair<Double,Double>? { + val geocoder = Geocoder(context, Locale.getDefault()) + return try { + val addresses: MutableList<Address>? = geocoder.getFromLocationName(address, 1) + val lat = addresses?.firstOrNull()?.latitude + val long = addresses?.firstOrNull()?.longitude + Pair(lat?:0.0,long?:0.0) + } catch (e: Exception) { + null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/helper/TransactionHelper.kt b/app/src/main/java/com/example/bandung_bondowoso/helper/TransactionHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..9fe0c2fbc8ad2f8734c537180e4c0aa03cb45fe3 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/helper/TransactionHelper.kt @@ -0,0 +1,42 @@ +package com.example.bandung_bondowoso.helper +import android.content.Context +import android.widget.EditText +import android.widget.RadioButton +import android.widget.Toast +import androidx.core.content.ContextCompat.getString +import com.example.bandung_bondowoso.R + +class TransactionHelper(private val context: Context) { + + fun validateTransaction( + transactionName: EditText, + transactionAmount: EditText, + expenseRadioButton: RadioButton, + incomeRadioButton: RadioButton, + transactionLocation: EditText + ): Boolean { + val name = transactionName.text.toString() + val amount = transactionAmount.text.toString() + val location = transactionLocation.text.toString() + + if (name.isEmpty()) { + transactionName.error = context.getString(R.string.error_transaction_name_empty) + return false + } + if (amount.isEmpty()) { + transactionAmount.error = context.getString(R.string.error_transaction_amount_empty) + return false + } + if (!expenseRadioButton.isChecked && !incomeRadioButton.isChecked) { + Toast.makeText(context, context.getString(R.string.error_transaction_category_empty), Toast.LENGTH_SHORT).show() + return false + } + + if (location.isEmpty()) { + transactionLocation.error = context.getString(R.string.error_transaction_location_empty) + return false + } + + return true + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/interface/transactionInterface.kt b/app/src/main/java/com/example/bandung_bondowoso/interface/transactionInterface.kt new file mode 100644 index 0000000000000000000000000000000000000000..cef936fd759cb5a6e47b2c18810fabdf6d867ab4 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/interface/transactionInterface.kt @@ -0,0 +1,10 @@ +package com.example.bandung_bondowoso.`interface` + +import android.view.View +import com.example.bandung_bondowoso.model.Transaction + +interface TransactionItemClickListener { + fun onDeleteTransaction(transaction: Transaction) + fun onEditTransaction(root: View, id: Int) + fun onOpenMap(name:String, location:String) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/local/AppDatabase.kt b/app/src/main/java/com/example/bandung_bondowoso/local/AppDatabase.kt new file mode 100644 index 0000000000000000000000000000000000000000..32514e6efec6b2a384d3a5b8ff34c17a1981dae9 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/local/AppDatabase.kt @@ -0,0 +1,50 @@ +package com.example.bandung_bondowoso.local + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase +import com.example.bandung_bondowoso.local.dao.TransactionDao +import com.example.bandung_bondowoso.model.Transaction + +@Database(entities = [Transaction::class], version = 3) +@TypeConverters(Converters::class) +abstract class AppDatabase : RoomDatabase() { + abstract fun transactionDao(): TransactionDao + + companion object { + private const val DATABASE_NAME = "app_database" + + val MIGRATION_1_2 = object : Migration(1, 2) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE `transaction` ADD COLUMN email TEXT NOT NULL DEFAULT ''") + } + } + + // Singleton + @Volatile + private var INSTANCE: AppDatabase? = null + + fun getInstance(context: Context): AppDatabase { + synchronized(this) { + var instance = INSTANCE + if (instance == null) { + instance = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + DATABASE_NAME + ) + .fallbackToDestructiveMigration() + .build() + + INSTANCE = instance + } + + return instance + } + } + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/local/Converters.kt b/app/src/main/java/com/example/bandung_bondowoso/local/Converters.kt new file mode 100644 index 0000000000000000000000000000000000000000..2010d8f8db7996da5ed2f8c5d9deb71c7a7cd23b --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/local/Converters.kt @@ -0,0 +1,23 @@ +package com.example.bandung_bondowoso.local + +import androidx.room.TypeConverter +import com.example.bandung_bondowoso.model.TransactionCategory +import java.util.Date + +class Converters { + // Converters for Date + @TypeConverter + fun fromTimestamp(value: Long?): Date? { + return value?.let { Date(it) } + } + @TypeConverter + fun dateToTimestamp(date: Date?): Long? { + return date?.time?.toLong() + } + + // Converters for TransactionType + @TypeConverter + fun fromTransactionType(value: TransactionCategory) = value.ordinal + @TypeConverter + fun intToTransactionType(value: Int) = enumValues<TransactionCategory>()[value] +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/local/dao/TransactionDao.kt b/app/src/main/java/com/example/bandung_bondowoso/local/dao/TransactionDao.kt new file mode 100644 index 0000000000000000000000000000000000000000..83439101eb8a495c26c73c26879f1b408cdd6956 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/local/dao/TransactionDao.kt @@ -0,0 +1,33 @@ +package com.example.bandung_bondowoso.local.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Query +import androidx.room.Upsert +import com.example.bandung_bondowoso.model.Transaction +import kotlinx.coroutines.flow.Flow + +@Dao +interface TransactionDao { + @Query("SELECT * FROM `transaction` ORDER BY created_at DESC") + fun getAll(): Flow<List<Transaction>> + @Query("SELECT * FROM `transaction` WHERE email = :email ORDER BY created_at DESC") + fun getAllByEmail(email: String): List<Transaction> + @Query("SELECT SUM(amount) FROM `transaction` WHERE category = 0 AND email= :email") + suspend fun getIncome(email:String): Double + @Query("SELECT SUM(amount) FROM `transaction` WHERE category = 1 AND email= :email") + suspend fun getExpense(email:String): Double + @Query("SELECT * FROM `transaction` WHERE id = :id") + suspend fun getTransaction(id: Int): Transaction + @Query("SELECT COUNT(*) FROM `transaction`") + suspend fun getCount(): Int + @Upsert + suspend fun upsert(transaction: Transaction) + + @Delete + suspend fun delete(transaction: Transaction) + + // Development function + @Query("DELETE FROM `transaction`") + suspend fun deleteAll() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/model/Item.kt b/app/src/main/java/com/example/bandung_bondowoso/model/Item.kt new file mode 100644 index 0000000000000000000000000000000000000000..decee29ad2ebea99ffa115b59df0ae5adb1072d4 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/model/Item.kt @@ -0,0 +1,16 @@ +package com.example.bandung_bondowoso.model + +import com.squareup.moshi.Json + +data class Item( + @field:Json(name = "name") val name: String, + @field:Json(name = "qty") val qty: Int, + @field:Json(name = "price") val price: Float +) +data class Items( + @field:Json(name = "items") val items: List<Item> +) + +data class ItemsResponse( + @field:Json(name = "items") val items: Items +) diff --git a/app/src/main/java/com/example/bandung_bondowoso/model/NetworkResult.kt b/app/src/main/java/com/example/bandung_bondowoso/model/NetworkResult.kt new file mode 100644 index 0000000000000000000000000000000000000000..fe5f0ebac6ba006245a00aa179bebbc66dfac624 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/model/NetworkResult.kt @@ -0,0 +1,9 @@ +package com.example.bandung_bondowoso.model + +data class ErrorByPath(val path: String, val message: String) + +sealed class NetworkResult<out T : Any> { + data class Success<out T : Any>(val code: Int, val data: T) : NetworkResult<T>() + data class Error<out T : Any>(val code: Int, val errorMsg: String?, val errorByPaths: Array<ErrorByPath>? = null) : NetworkResult<T>() + data class Exception(val e: Throwable) : NetworkResult<Nothing>() +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/model/Token.kt b/app/src/main/java/com/example/bandung_bondowoso/model/Token.kt new file mode 100644 index 0000000000000000000000000000000000000000..22adc03634c9d82bfb1677581a472d7c70ac2be7 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/model/Token.kt @@ -0,0 +1,7 @@ +package com.example.bandung_bondowoso.model + +import com.squareup.moshi.Json + +data class Token( + @field:Json(name = "token") val token: String +) diff --git a/app/src/main/java/com/example/bandung_bondowoso/model/TokenDetail.kt b/app/src/main/java/com/example/bandung_bondowoso/model/TokenDetail.kt new file mode 100644 index 0000000000000000000000000000000000000000..4702cedf01830bc0bb444a9d1be0d4563dfb53a9 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/model/TokenDetail.kt @@ -0,0 +1,9 @@ +package com.example.bandung_bondowoso.model + +import com.squareup.moshi.Json + +data class TokenDetail( + @field:Json(name = "nim") val nim: String, + @field:Json(name = "iat") val iat: Long, + @field:Json(name = "exp") val exp: Long +) diff --git a/app/src/main/java/com/example/bandung_bondowoso/model/Transaction.kt b/app/src/main/java/com/example/bandung_bondowoso/model/Transaction.kt new file mode 100644 index 0000000000000000000000000000000000000000..89529be7e38b6bada91a6696f259e8c598c99f0c --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/model/Transaction.kt @@ -0,0 +1,19 @@ +package com.example.bandung_bondowoso.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import java.util.Date + +@Entity(tableName = "transaction") +data class Transaction ( + @PrimaryKey(autoGenerate = true) val id: Int = 0, + @ColumnInfo(name = "email") val email:String, + @ColumnInfo(name = "name") val name: String, + @ColumnInfo(name = "amount") val amount: Double, + @ColumnInfo(name = "category") val type: TransactionCategory, + @ColumnInfo(name ="location_lat") val locationLat: Double, + @ColumnInfo(name ="location_long") val locationLong: Double, + @ColumnInfo(name = "location_name") val locationName: String, + @ColumnInfo(name = "created_at") val createdAt: Date, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/model/TransactionCategory.kt b/app/src/main/java/com/example/bandung_bondowoso/model/TransactionCategory.kt new file mode 100644 index 0000000000000000000000000000000000000000..48b216575db4e8b5ebc62588cc896bb9585932df --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/model/TransactionCategory.kt @@ -0,0 +1,6 @@ +package com.example.bandung_bondowoso.model + +enum class TransactionCategory(val value: Int) { + INCOME(0), + EXPENSE(1) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/model/request/LoginRequest.kt b/app/src/main/java/com/example/bandung_bondowoso/model/request/LoginRequest.kt new file mode 100644 index 0000000000000000000000000000000000000000..2c25bd717adf44ea7f024c924e77650d508f3019 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/model/request/LoginRequest.kt @@ -0,0 +1,6 @@ +package com.example.bandung_bondowoso.model.request + +data class LoginRequest( + val email: String, + val password: String +) diff --git a/app/src/main/java/com/example/bandung_bondowoso/remote/ApiClient.kt b/app/src/main/java/com/example/bandung_bondowoso/remote/ApiClient.kt new file mode 100644 index 0000000000000000000000000000000000000000..78cf201c866ab3771bee311667dae90726c35d82 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/remote/ApiClient.kt @@ -0,0 +1,26 @@ +package com.example.bandung_bondowoso.remote + +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory + + +class RetrofitClient(private val baseUrl: String) { + private val moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + + val retrofit: Retrofit = Retrofit.Builder() + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .baseUrl(baseUrl) + .build() +} + +object ApiClient { + val pbdApiService: PBDApiService by lazy { + RetrofitClient( + "https://pbd-backend-2024.vercel.app/" + ).retrofit.create(PBDApiService::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/remote/ApiHandler.kt b/app/src/main/java/com/example/bandung_bondowoso/remote/ApiHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..893eceb0b137e50880623dd71af255f964e24741 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/remote/ApiHandler.kt @@ -0,0 +1,67 @@ +package com.example.bandung_bondowoso.remote + +import android.util.Log +import com.example.bandung_bondowoso.model.ErrorByPath +import com.example.bandung_bondowoso.model.NetworkResult +import org.json.JSONObject +import retrofit2.HttpException +import retrofit2.Response + + +interface ApiHandler { + suspend fun <T : Any> safeApiCall(call: suspend () -> Response<T>): NetworkResult<T> { + return try { + val response = call() + + Log.d("ApiHandler", "safeApiCall: ${response.body()}") + + if (response.isSuccessful) { + NetworkResult.Success( + code = response.code(), + data = response.body()!! + ) + } else { + var errorMessage = response.errorBody()?.string() + return try { + // JSON error response + val jObjError = JSONObject(errorMessage!!) + val name = jObjError.getString("name") + + val issues = jObjError.getJSONArray("issues") + + // Map issues to ErrorByPath + val errorByPaths = Array(issues.length()) { i -> + val issue = issues.getJSONObject(i) + ErrorByPath( + issue.getJSONArray("path").getString(0), + issue.getString("message") + ) + } + + errorMessage = errorByPaths[0].message + + Log.d("ApiHandler", "safeApiCall: $name: $errorMessage") + NetworkResult.Error( + response.code(), + errorMessage, + errorByPaths + ) + } catch (e: Exception) { + Log.d("ApiHandler", "safeApiCall: ${e.message}") + NetworkResult.Error( + response.code(), + errorMessage + ) + } + } + } catch (e: HttpException) { + NetworkResult.Error( + e.code(), + e.message() + ) + } + catch (e: Throwable) { + NetworkResult.Exception(e) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/remote/AuthService.kt b/app/src/main/java/com/example/bandung_bondowoso/remote/AuthService.kt new file mode 100644 index 0000000000000000000000000000000000000000..7ff423a30e221bba805f27ef2de3f58868c0da22 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/remote/AuthService.kt @@ -0,0 +1,11 @@ +package com.example.bandung_bondowoso.remote + +import com.example.bandung_bondowoso.model.Token +import com.example.bandung_bondowoso.model.TokenDetail +import com.example.bandung_bondowoso.model.request.LoginRequest +import retrofit2.Response + +interface AuthService { + suspend fun login(loginRequest: LoginRequest): Response<Token> + suspend fun token(token: String): Response<TokenDetail> +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/remote/BillService.kt b/app/src/main/java/com/example/bandung_bondowoso/remote/BillService.kt new file mode 100644 index 0000000000000000000000000000000000000000..eeddb336db7309680c852dfcaf67744b37e13a75 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/remote/BillService.kt @@ -0,0 +1,9 @@ +package com.example.bandung_bondowoso.remote +import com.example.bandung_bondowoso.model.ItemsResponse +import okhttp3.MultipartBody +import retrofit2.Response + +interface BillService { + suspend fun upload(token: String, file: MultipartBody.Part) : Response<ItemsResponse> + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/remote/PBDApiService.kt b/app/src/main/java/com/example/bandung_bondowoso/remote/PBDApiService.kt new file mode 100644 index 0000000000000000000000000000000000000000..cdd8abb3efcbfc246673acb6c4817e3c0a3342a7 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/remote/PBDApiService.kt @@ -0,0 +1,26 @@ +package com.example.bandung_bondowoso.remote + +import com.example.bandung_bondowoso.model.ItemsResponse +import com.example.bandung_bondowoso.model.Token +import com.example.bandung_bondowoso.model.TokenDetail +import com.example.bandung_bondowoso.model.request.LoginRequest +import okhttp3.MultipartBody +import retrofit2.Response +import retrofit2.http.Body +import retrofit2.http.Header +import retrofit2.http.Multipart +import retrofit2.http.POST +import retrofit2.http.Part + +interface PBDApiService : AuthService, BillService { + @POST("api/auth/login") + override suspend fun login(@Body loginRequest: LoginRequest): Response<Token> + + @POST("api/auth/token") + override suspend fun token(@Header("Authorization") token: String): Response<TokenDetail> + + @Multipart + @POST("api/bill/upload") + override suspend fun upload(@Header("Authorization") token: String, @Part file: MultipartBody.Part): Response<ItemsResponse> + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/repository/BillRepository.kt b/app/src/main/java/com/example/bandung_bondowoso/repository/BillRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..6248f6ff8e94095c2463bb7d76b2ba8f00918014 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/repository/BillRepository.kt @@ -0,0 +1,49 @@ +package com.example.bandung_bondowoso.repository + +import android.util.Log +import com.example.bandung_bondowoso.model.ItemsResponse +import com.example.bandung_bondowoso.model.NetworkResult +import com.example.bandung_bondowoso.remote.ApiHandler +import com.example.bandung_bondowoso.remote.BillService +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody.Companion.asRequestBody +import java.io.File + +class BillRepository( + private val billService: BillService, + private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default +) : ApiHandler { + private var currentResponse: ItemsResponse? = null + suspend fun upload(token: String, file: File) = withContext(defaultDispatcher) { + val fileRequest = file.asRequestBody("image/*".toMediaTypeOrNull()) + val request = MultipartBody.Part.createFormData("file", "file.jpg", fileRequest) + val response = safeApiCall { + billService.upload("Bearer $token", request) + } + when(response){ + is NetworkResult.Success -> { + val result = response.data + saveResponse(result) + Log.d("BillRepository", "getting bills: $result") + } + else -> { + Log.d("BillRepository", "Getting Bills: $response") + } + } + } + private fun saveResponse(response: ItemsResponse?) { + currentResponse = response + } + + fun getCurrentResponse(): ItemsResponse? { + return currentResponse + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/repository/TransactionRepository.kt b/app/src/main/java/com/example/bandung_bondowoso/repository/TransactionRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..f8ed7a38ab0243de2d6351b95d998cb813d3032f --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/repository/TransactionRepository.kt @@ -0,0 +1,59 @@ +package com.example.bandung_bondowoso.repository + +import android.util.Log +import com.example.bandung_bondowoso.local.dao.TransactionDao +import com.example.bandung_bondowoso.model.Transaction +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.withContext + +class TransactionRepository(private val transactionDao: TransactionDao, + ) { + private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default + private val TAG:String = "TransactionRepository" + suspend fun getIncome(email:String) = withContext(defaultDispatcher){ + Log.d(TAG, "getIncome") + transactionDao.getIncome(email) + } + + suspend fun getExpense(email:String) = withContext(defaultDispatcher){ + Log.d(TAG, "getExpense") + transactionDao.getExpense(email) + } + + suspend fun getTransaction(id:Int) = withContext(defaultDispatcher){ + transactionDao.getTransaction(id) + } + suspend fun getCount() = withContext(defaultDispatcher) { + Log.d(TAG, "getCount") + transactionDao.getCount() + } + suspend fun upsert(transaction: Transaction) = withContext(defaultDispatcher) { + Log.d(TAG, "upsert: $transaction") + transactionDao.upsert(transaction) + } + + val getAll = flow { + transactionDao.getAll().collect { + emit(it) + } + } + .flowOn(defaultDispatcher) + + suspend fun getAllByEmail(email:String) = withContext(defaultDispatcher){ + Log.d(TAG, "getAllbyEmail") + transactionDao.getAllByEmail(email) + } + suspend fun delete(transaction: Transaction) = withContext(defaultDispatcher) { + Log.d(TAG, "delete: $transaction") + transactionDao.delete(transaction) + } + + // Development function + suspend fun deleteAll() = withContext(defaultDispatcher) { + Log.d(TAG, "deleteAll") + transactionDao.deleteAll() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/repository/UserRepository.kt b/app/src/main/java/com/example/bandung_bondowoso/repository/UserRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..60cccdcb56ca260742d9b27fd74034a5f0396b43 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/repository/UserRepository.kt @@ -0,0 +1,95 @@ +package com.example.bandung_bondowoso.repository + +import android.content.Context +import android.content.SharedPreferences +import android.util.Log +import com.example.bandung_bondowoso.model.NetworkResult +import com.example.bandung_bondowoso.model.request.LoginRequest +import com.example.bandung_bondowoso.remote.ApiHandler +import com.example.bandung_bondowoso.remote.AuthService +import com.example.bandung_bondowoso.util.Config +import com.example.bandung_bondowoso.util.CryptoManager +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class UserRepository( + private val authService: AuthService, + private val sharedPreferences: SharedPreferences, + private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default +) : ApiHandler { + suspend fun login(email: String, password: String) = withContext(defaultDispatcher) { + val response = safeApiCall { + authService.login(LoginRequest(email, password)) + } + + when (response) { + is NetworkResult.Success -> { + Log.d("UserRepository", "login: ${response.data}") + val token = response.data.token + + // Encrypt token + val bytes = token.encodeToByteArray() + val encryptedToken = CryptoManager().encryptToBase64(bytes) + + // Save token to shared preferences + sharedPreferences.edit().putString(Config.TOKEN_KEY, encryptedToken).apply() + + // Save email to shared preferences + sharedPreferences.edit().putString(Config.EMAIL_KEY, email).apply() + } + else -> { + Log.d("UserRepository", "login: $response") + } + } + + response + } + + suspend fun logout() = withContext(defaultDispatcher) { + // delete token from shared preferences + sharedPreferences.edit().remove(Config.TOKEN_KEY).apply() + + // delete email from shared preferences + sharedPreferences.edit().remove(Config.EMAIL_KEY).apply() + + // Log token + val token = getToken() + Log.d("UserRepository", "logout: $token") + } + + suspend fun checkToken() = withContext(defaultDispatcher) { + val token = getToken() ?: return@withContext NetworkResult.Error(401, "Unauthorized") + + val response = safeApiCall { + authService.token("Bearer $token") + } + + when (response) { + is NetworkResult.Success -> { + Log.d("UserRepository", "isLoggedIn: ${response.data}") + } + else -> {} + } + + Log.d("UserRepository", "checkToken: $response") + + response + } + + suspend fun getEmail() = withContext(defaultDispatcher) { + val email = sharedPreferences.getString(Config.EMAIL_KEY, null) + email + } + + suspend fun getToken() = withContext(defaultDispatcher) { + val encryptedToken = sharedPreferences.getString(Config.TOKEN_KEY, null) + if (encryptedToken != null) { + val bytes = CryptoManager().decryptFromBase64(encryptedToken) + val token = String(bytes) + token + } else { + null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/service/JwtCheckerService.kt b/app/src/main/java/com/example/bandung_bondowoso/service/JwtCheckerService.kt new file mode 100644 index 0000000000000000000000000000000000000000..cc3f4abe9ebb0cea1d1ff6e4f2a079969d1fb16d --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/service/JwtCheckerService.kt @@ -0,0 +1,111 @@ +package com.example.bandung_bondowoso.service + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.util.Log +import android.widget.Toast +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener +import com.example.bandung_bondowoso.broadcast.jwt_expired.JwtExpiredListener +import com.example.bandung_bondowoso.model.NetworkResult +import com.example.bandung_bondowoso.remote.ApiClient +import com.example.bandung_bondowoso.repository.UserRepository +import com.example.bandung_bondowoso.util.Config +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class JwtCheckerService : Service(), ConnectionChangeListener, JwtExpiredListener { + private val job = SupervisorJob() + private val scope = CoroutineScope(Dispatchers.IO + job) + private lateinit var userRepository: UserRepository + + override fun onCreate() { + super.onCreate() + Log.d("JwtCheckerService", "JwtCheckerService is created") + + userRepository = UserRepository(ApiClient.pbdApiService, this.getSharedPreferences(Config.SHARED_PREFERENCES_NAME, MODE_PRIVATE)) + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + super.onStartCommand(intent, flags, startId) + + Log.d("JwtCheckerService", "JwtCheckerService is starting") + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show() + + + // Coroutine to fetch periodically the token + scope.launch { + while (true) { + Log.d("JwtCheckerService", "JwtCheckerService is running") + val result = userRepository.checkToken() + + Log.d("JwtCheckerService", "JwtCheckerService is running: $result") + + when (result) { + is NetworkResult.Success -> { + Log.d("JwtCheckerService", "JwtCheckerService is running: ${result.data}") + val tokenDetail = result.data + val remainingTime = tokenDetail.exp - System.currentTimeMillis() / 1000 + Log.d("JwtCheckerService", "JwtCheckerService is running: $remainingTime") + LocalBroadcastManager.getInstance(this@JwtCheckerService) + .sendBroadcast(Intent("com.example.bandung_bondowoso.JWT_VALID")) + delay(remainingTime * 1000) + } + is NetworkResult.Error ->{ + Log.d("JwtCheckerService", "JwtCheckerService is running: ${result.errorMsg}") + + if (result.code == 401) { + Log.d( + "JwtCheckerService", + "JwtCheckerService is stopping" + ) + LocalBroadcastManager.getInstance(this@JwtCheckerService) + .sendBroadcast(Intent("com.example.bandung_bondowoso.JWT_EXPIRED")) + stopSelf() + break + } + } + else -> { + Log.d("JwtCheckerService", "JwtCheckerService is running: $result") + } + } + + delay(10000) + } + } + + Log.d("JwtCheckerService", "OUTSIDE") + + return START_STICKY + } + + override fun onBind(intent: Intent): IBinder? { + Log.d("JwtCheckerService", "JwtCheckerService is bound") + return null + } + + override fun onDestroy() { + Log.d("JwtCheckerService", "JwtCheckerService is destroyed") + super.onDestroy() + job.cancel() + Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show() + } + + override fun onConnectionChanged(isConnected: Boolean) { + if (isConnected) { + Log.d("Network", "Connected") + onStartCommand(Intent(), 0, 0) + } else { + stopSelf() + } + } + + override fun onExpired() { + Log.d("JwtCheckerService", "onExpired") + stopSelf() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/ui/dashboard/DashboardFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/ui/dashboard/DashboardFragment.kt deleted file mode 100644 index 7297c534423902ca0117ec746651f224afb51a16..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/bandung_bondowoso/ui/dashboard/DashboardFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.example.bandung_bondowoso.ui.dashboard - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import com.example.bandung_bondowoso.databinding.FragmentDashboardBinding - -class DashboardFragment : Fragment() { - - private var _binding: FragmentDashboardBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val dashboardViewModel = - ViewModelProvider(this).get(DashboardViewModel::class.java) - - _binding = FragmentDashboardBinding.inflate(inflater, container, false) - val root: View = binding.root - - val textView: TextView = binding.textDashboard - dashboardViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/ui/home/HomeFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/ui/home/HomeFragment.kt deleted file mode 100644 index 5c0a333f694abef941f4031c0438ccf1a87f3f5a..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/bandung_bondowoso/ui/home/HomeFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.example.bandung_bondowoso.ui.home - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import com.example.bandung_bondowoso.databinding.FragmentHomeBinding - -class HomeFragment : Fragment() { - - private var _binding: FragmentHomeBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val homeViewModel = - ViewModelProvider(this).get(HomeViewModel::class.java) - - _binding = FragmentHomeBinding.inflate(inflater, container, false) - val root: View = binding.root - - val textView: TextView = binding.textHome - homeViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/ui/home/HomeViewModel.kt deleted file mode 100644 index ac867c1c262fa43587eced4558ea810f0c802e6b..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/bandung_bondowoso/ui/home/HomeViewModel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.bandung_bondowoso.ui.home - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class HomeViewModel : ViewModel() { - - private val _text = MutableLiveData<String>().apply { - value = "This is home Fragment" - } - val text: LiveData<String> = _text -} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/ui/notifications/NotificationsFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/ui/notifications/NotificationsFragment.kt deleted file mode 100644 index 0cfe3b0571c720d5a33cd9e83d60d5e683bb1e92..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/bandung_bondowoso/ui/notifications/NotificationsFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.example.bandung_bondowoso.ui.notifications - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import com.example.bandung_bondowoso.databinding.FragmentNotificationsBinding - -class NotificationsFragment : Fragment() { - - private var _binding: FragmentNotificationsBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val notificationsViewModel = - ViewModelProvider(this).get(NotificationsViewModel::class.java) - - _binding = FragmentNotificationsBinding.inflate(inflater, container, false) - val root: View = binding.root - - val textView: TextView = binding.textNotifications - notificationsViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/ui/notifications/NotificationsViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/ui/notifications/NotificationsViewModel.kt deleted file mode 100644 index d95f5e08470c9a879f1acd4c756f627ef97469ee..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/bandung_bondowoso/ui/notifications/NotificationsViewModel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.bandung_bondowoso.ui.notifications - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class NotificationsViewModel : ViewModel() { - - private val _text = MutableLiveData<String>().apply { - value = "This is notifications Fragment" - } - val text: LiveData<String> = _text -} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/util/Config.kt b/app/src/main/java/com/example/bandung_bondowoso/util/Config.kt new file mode 100644 index 0000000000000000000000000000000000000000..6c9179950edd8438b08fb4af64d1073e9f596e1d --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/util/Config.kt @@ -0,0 +1,10 @@ +package com.example.bandung_bondowoso.util + +class Config { + companion object { + const val BASE_URL = "https://pbd-backend-2024.vercel.app" + const val SHARED_PREFERENCES_NAME = "com.example.bandung_bondowoso.util.SharedPreferences" + const val TOKEN_KEY = "token" + const val EMAIL_KEY = "email" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/util/ConnectionStateMonitor.kt b/app/src/main/java/com/example/bandung_bondowoso/util/ConnectionStateMonitor.kt new file mode 100644 index 0000000000000000000000000000000000000000..e982ddf5943b652c23b171972869594266e77c71 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/util/ConnectionStateMonitor.kt @@ -0,0 +1,53 @@ +package com.example.bandung_bondowoso.util + +import android.content.Context +import android.net.ConnectivityManager +import android.net.ConnectivityManager.NetworkCallback +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkRequest +import android.util.Log +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener + + +class ConnectionStateMonitor(private val connectionChangeListener: ConnectionChangeListener) : NetworkCallback() { + private final val networkRequest: NetworkRequest = NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build() + + fun enable(context: Context) { + val connectivityMangaer = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + + connectivityMangaer.registerNetworkCallback(networkRequest, this) + val network = connectivityMangaer.activeNetwork + + if (network != null) { + connectionChangeListener.onConnectionChanged(true) + } else { + connectionChangeListener.onConnectionChanged(false) + } + } + + fun disable(context: Context) { + val connectivityMangaer = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + + connectivityMangaer.unregisterNetworkCallback(this) + } + + final override fun onAvailable(network: Network) { + super.onAvailable(network) + + // Handle network availability + Log.d("ConnectionStateMonitor", "onAvailable") + connectionChangeListener.onConnectionChanged(true) + } + + final override fun onLost(network: Network) { + super.onLost(network) + + // Handle network lost + Log.d("ConnectionStateMonitor", "onLost") + connectionChangeListener.onConnectionChanged(false) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/util/CryptoManager.kt b/app/src/main/java/com/example/bandung_bondowoso/util/CryptoManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..1a0f9d998faf0b2f2c0f4edb8579e172c085aa68 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/util/CryptoManager.kt @@ -0,0 +1,113 @@ +package com.example.bandung_bondowoso.util + +import android.security.keystore.KeyGenParameterSpec +import android.security.keystore.KeyProperties +import android.util.Base64 +import android.util.Log +import java.io.InputStream +import java.security.KeyStore +import javax.crypto.Cipher +import javax.crypto.KeyGenerator +import javax.crypto.SecretKey +import javax.crypto.spec.IvParameterSpec + +class CryptoManager { + private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { + load(null) + } + + private fun encryptCipher(): Cipher { + return Cipher.getInstance(TRANSFORMATION).apply { + init(Cipher.ENCRYPT_MODE, getOrCreateKey()) + } + } + + private fun decryptCipher(iv: ByteArray): Cipher { + return Cipher.getInstance(TRANSFORMATION).apply { + init(Cipher.DECRYPT_MODE, getOrCreateKey(), IvParameterSpec(iv)) + } + } + + private fun getOrCreateKey(): SecretKey { + return if (keyStore.containsAlias(KEY_ALIAS)) { + keyStore.getKey(KEY_ALIAS, null) as SecretKey + } else { + createKey() + } + } + + private fun createKey(): SecretKey { + val keyGenerator = KeyGenerator.getInstance(ALGORITHM, "AndroidKeyStore") + val keyGenParameterSpec = KeyGenParameterSpec.Builder( + KEY_ALIAS, + KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT + ).apply { + setBlockModes(BLOCK_MODE) + setEncryptionPaddings(PADDING) + setUserAuthenticationRequired(false) + setRandomizedEncryptionRequired(true) // randomized to produce different ciphertexts for the same plaintext every time + }.build() + + keyGenerator.init(keyGenParameterSpec) + return keyGenerator.generateKey() + } + + fun encrypt(bytes: ByteArray): ByteArray { + return encryptCipher().doFinal(bytes) + } + + fun encryptToBase64(bytes: ByteArray): String { + val encryptCipher = encryptCipher() + val encryptedBytes = encryptCipher.doFinal(bytes) + + // iv size + iv + encrypted bytes size + encrypted bytes + val iv = encryptCipher.iv + Log.d("CryptoManager", "ivBase64: ${Base64.encodeToString(iv, Base64.DEFAULT)}") + val ivSize = iv.size + + val paddedBytes = ByteArray(1 + ivSize + 2 + encryptedBytes.size) + paddedBytes[0] = ivSize.toByte() + System.arraycopy(iv, 0, paddedBytes, 1, ivSize) + // assign 2 byte for encryptedBytesSize + System.arraycopy( + byteArrayOf( + (encryptedBytes.size shr 8 and 0xFF).toByte(), + (encryptedBytes.size and 0xFF).toByte() + ), + 0, + paddedBytes, + 1 + ivSize, + 2 + ) + System.arraycopy(encryptedBytes, 0, paddedBytes, 1 + ivSize + 2, encryptedBytes.size) + + return Base64.encodeToString(paddedBytes, Base64.DEFAULT) + } + + fun decrypt(bytes: ByteArray, iv: ByteArray): ByteArray { + return decryptCipher(iv).doFinal(bytes) + } + + fun decryptFromBase64(base64: String): ByteArray { + // decode base64 + val bytes = Base64.decode(base64, Base64.DEFAULT) + + Log.d("CryptoManager", "decryptFromBase64: $bytes") + + // iv size + iv + encrypted bytes size + encrypted bytes + val ivSize = bytes[0].toInt() + val iv = bytes.copyOfRange(1, ivSize + 1) + val encryptedBytesSize = (bytes[ivSize + 1].toInt() shl 8 and 0xFF00) or (bytes[ivSize + 2].toInt() and 0xFF) + val encryptedBytes = bytes.copyOfRange(1 + ivSize + 2, 1 + ivSize + 2 + encryptedBytesSize) + + return decrypt(encryptedBytes, iv) + } + + companion object { + private const val ALGORITHM = KeyProperties.KEY_ALGORITHM_AES + private const val BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC + private const val PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7 + private const val TRANSFORMATION = "$ALGORITHM/$BLOCK_MODE/$PADDING" + private const val KEY_ALIAS = "com.example.bandung_bondowoso.util.CryptoManager" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/util/StringFormat.kt b/app/src/main/java/com/example/bandung_bondowoso/util/StringFormat.kt new file mode 100644 index 0000000000000000000000000000000000000000..f3b60799b5a099b27f7fecd90566ba76bcee41bf --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/util/StringFormat.kt @@ -0,0 +1,14 @@ +package com.example.bandung_bondowoso.util + +import android.icu.text.NumberFormat +import java.util.Locale + +class StringFormat { + companion object { + fun formatAmount(amount: Double): String { + val format = NumberFormat.getCurrencyInstance(Locale("id", "ID")) + + return format.format(amount) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/dashboard/DashboardFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/dashboard/DashboardFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..aa4c00b7b46e03246809c319325c03680e88c093 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/dashboard/DashboardFragment.kt @@ -0,0 +1,76 @@ +package com.example.bandung_bondowoso.view.dashboard + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModelProvider +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener +import com.example.bandung_bondowoso.databinding.FragmentDashboardBinding +import com.example.bandung_bondowoso.util.ConnectionStateMonitor +import com.example.bandung_bondowoso.view.network.NoNetworkFragment +import com.example.bandung_bondowoso.viewmodel.AuthViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModelFactory + +class DashboardFragment : Fragment(), ConnectionChangeListener { + + private var _binding: FragmentDashboardBinding? = null + private val transactionViewModel: TransactionViewModel by viewModels { + TransactionViewModelFactory((activity?.application as BandungBondowosoApp).transactionRepository) + } + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + private val connectionStateMonitor = ConnectionStateMonitor(this) + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val dashboardViewModel = + ViewModelProvider(this).get(DashboardViewModel::class.java) + + _binding = FragmentDashboardBinding.inflate(inflater, container, false) + val root: View = binding.root + + connectionStateMonitor.enable(requireContext()) + + return root + } + + override fun onDestroyView() { + super.onDestroyView() + Log.d("DashboardFragment", "onDestroyView") + _binding = null + connectionStateMonitor.disable(requireContext()) + } + + override fun onConnectionChanged(isConnected: Boolean) { + if (!isConnected) { + + // change fragment to no network fragment + Log.d("DashboardFragment", binding.dashboardChildFragment.toString()) + childFragmentManager.beginTransaction() + .replace(binding.dashboardChildFragment.id, NoNetworkFragment()) + .commit() + } else { + // remove no network fragment + Log.d("DashboardFragment", "Connected") + val fragment = childFragmentManager.findFragmentById(binding.dashboardChildFragment.id) + if (fragment is NoNetworkFragment) { + childFragmentManager.beginTransaction().remove(fragment).commit() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/ui/dashboard/DashboardViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/view/dashboard/DashboardViewModel.kt similarity index 85% rename from app/src/main/java/com/example/bandung_bondowoso/ui/dashboard/DashboardViewModel.kt rename to app/src/main/java/com/example/bandung_bondowoso/view/dashboard/DashboardViewModel.kt index 3ef1e8ddab48e17790258195df890294d63ed7af..c0a1acb9763d6b659f93f369ac4820dccdc1d933 100644 --- a/app/src/main/java/com/example/bandung_bondowoso/ui/dashboard/DashboardViewModel.kt +++ b/app/src/main/java/com/example/bandung_bondowoso/view/dashboard/DashboardViewModel.kt @@ -1,4 +1,4 @@ -package com.example.bandung_bondowoso.ui.dashboard +package com.example.bandung_bondowoso.view.dashboard import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/graph/GraphFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/graph/GraphFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..a98744b7675c36b816dabbdf65ad2fe9ee0b8491 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/graph/GraphFragment.kt @@ -0,0 +1,129 @@ +package com.example.bandung_bondowoso.view.graph + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.databinding.FragmentGraphBinding +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModelFactory +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModelFactory +import com.github.mikephil.charting.animation.Easing +import com.github.mikephil.charting.charts.PieChart +import com.github.mikephil.charting.data.PieEntry +import com.github.mikephil.charting.formatter.PercentFormatter +import kotlinx.coroutines.launch + +class GraphFragment : Fragment() { + private var _binding: FragmentGraphBinding? = null + private val binding get() = _binding!! + private val tag = "graphFragment" + private val transactionViewModel: TransactionViewModel by viewModels { + TransactionViewModelFactory((activity?.application as BandungBondowosoApp).transactionRepository) + } + private val loginViewModel: LoginViewModel by viewModels { + LoginViewModelFactory((activity?.application as BandungBondowosoApp).userRepository) + } + private lateinit var chart:PieChart + private lateinit var emailUser:String + private var income:Double = 0.00 + private var expense:Double = 0.00 + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Log.d(tag, "onCreateView") + if (_binding == null) { + _binding = FragmentGraphBinding.inflate(inflater, container, false) + } + return binding.root + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Log.d(tag, "onViewCreated") + super.onViewCreated(view, savedInstanceState) + + if (_binding != null) { + chart = binding.chart1 + chart.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.md_theme_surface)) + chart.animateY(1400, Easing.EaseInOutQuad) + chart.setUsePercentValues(true) + chart.isDrawHoleEnabled = false + chart.isDrawHoleEnabled = false + + val l: com.github.mikephil.charting.components.Legend? = chart.legend + l?.verticalAlignment = com.github.mikephil.charting.components.Legend.LegendVerticalAlignment.TOP + l?.horizontalAlignment = com.github.mikephil.charting.components.Legend.LegendHorizontalAlignment.RIGHT + l?.orientation = com.github.mikephil.charting.components.Legend.LegendOrientation.VERTICAL + l?.setDrawInside(false) + l?.xEntrySpace = 7f + l?.yEntrySpace = 0f + l?.yOffset = 0f + chart.setEntryLabelColor(ContextCompat.getColor(requireContext(), R.color.md_theme_surface)) + chart.setEntryLabelTextSize(16f) + chart.setNoDataText("") + } + val values = ArrayList<PieEntry>() + loginViewModel.getEmail().observe(viewLifecycleOwner) { email -> + Log.d(tag, "User Email: $email") + this.emailUser = email.toString() + lifecycleScope.launch { + income = transactionViewModel.getIncome(emailUser) + expense = transactionViewModel.getExpense(emailUser) + + values.clear() + values.add(PieEntry(income.toFloat(), "Pemasukan")) + values.add(PieEntry(expense.toFloat(), "Pengeluaran")) + val dataSet = com.github.mikephil.charting.data.PieDataSet(values, "") + dataSet.setColors( + ContextCompat.getColor(requireContext(), R.color.md_theme_primary), + ContextCompat.getColor(requireContext(), R.color.md_theme_peach) + ) + val data = com.github.mikephil.charting.data.PieData(dataSet) + chart.data = data + data.setValueFormatter(PercentFormatter(chart)) + data.setValueTextSize(16f) + data.setValueTextColor(ContextCompat.getColor(requireContext(), R.color.md_theme_surface)) + if (values.isEmpty()) { + chart.visibility = View.GONE + binding.clEmptyRv?.visibility = View.VISIBLE + } else { + chart.visibility = View.VISIBLE + binding.clEmptyRv?.visibility = View.GONE + } + chart.invalidate() + } + } + } + +// override fun onSaveInstanceState(outState: Bundle) { +// super.onSaveInstanceState(outState) +// val incomeState = income +// val expenseState = expense +// val chart = chart +// outState.putInt("income", incomeState) +// outState.putInt("expense", expenseState) +// } +// +// override fun onViewStateRestored(savedInstanceState: Bundle?) { +// super.onViewStateRestored(savedInstanceState) +// if(savedInstanceState != null){ +// income = savedInstanceState.getInt("income") +// expense = savedInstanceState.getInt("expense") +// } +// } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/login/LoginFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/login/LoginFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..550ec82883dc75cf68d6fee11068ef684af89e60 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/login/LoginFragment.kt @@ -0,0 +1,146 @@ +package com.example.bandung_bondowoso.view.login + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener +import com.example.bandung_bondowoso.databinding.FragmentLoginBinding +import com.example.bandung_bondowoso.service.JwtCheckerService +import com.example.bandung_bondowoso.util.ConnectionStateMonitor +import com.example.bandung_bondowoso.view.network.NoNetworkFragment +import com.example.bandung_bondowoso.viewmodel.login.LoginResult +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModelFactory + +class LoginFragment : Fragment(), ConnectionChangeListener { + + private var _binding: FragmentLoginBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + private val loginViewModel: LoginViewModel by activityViewModels { + LoginViewModelFactory((activity?.application as BandungBondowosoApp).userRepository) + } + + private val connectionStateMonitor = ConnectionStateMonitor(this) + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Log.d("LoginFragment", "onCreateView") + + _binding = FragmentLoginBinding.inflate(inflater, container, false) + val root: View = binding.root + + binding.buttonLoginText.setOnClickListener { + Log.d("LoginFragment", "Button Login Clicked") + + val email = binding.etEmail.text.toString() + val password = binding.etPassword.text.toString() + + loginViewModel.login(email, password) + } + + loginViewModel.loginResult.observe(viewLifecycleOwner) { + Log.d("LoginFragment", "loginResult: $it") + + when (it) { + LoginResult.SUCCESS -> handleSuccess() + LoginResult.ERROR -> handleError() + LoginResult.LOADING -> handleLoading() + else -> { + Log.d("LoginFragment", "loginResult: $it") + } + } + } + + loginViewModel.loginFormState.observe(viewLifecycleOwner, + Observer { loginFormState -> + if (loginFormState == null) { + return@Observer + } + loginFormState.emailError?.let { + binding.emailTextInput.error = it + } + + loginFormState.passwordError?.let { + binding.passwordTextInput.error = it + } + + loginFormState.error?.let { + Toast.makeText(this.requireContext(), it, Toast.LENGTH_SHORT).show() + } + }) + + connectionStateMonitor.enable(requireContext()) + + return root + } + + override fun onDestroyView() { + super.onDestroyView() + Log.d("LoginFragment", "onDestroyView") + _binding = null + connectionStateMonitor.disable(requireContext()) + } + + private fun handleSuccess() { + Log.d("LoginFragment", "Login Success") + + this.requireActivity().startService(Intent(this.requireActivity(), JwtCheckerService::class.java)) + } + + private fun handleError() { + Log.d("LoginFragment", "Login Error") + binding.buttonLoginText.isEnabled = true + binding.buttonLoginProgress.visibility = View.GONE + + binding.etEmail.isEnabled = true + binding.etPassword.isEnabled = true + } + + private fun handleLoading() { + Log.d("LoginFragment", "Login Loading") + binding.buttonLoginText.isEnabled = false + binding.buttonLoginProgress.visibility = View.VISIBLE + + binding.etEmail.isEnabled = false + binding.etPassword.isEnabled = false + } + + override fun onConnectionChanged(isConnected: Boolean) { + activity?.runOnUiThread(Runnable { + if (!isConnected) { + // change fragment to no network fragment + Log.d("DashboardFragment", binding.loginChildFragment.toString()) + childFragmentManager.beginTransaction() + .replace(binding.loginChildFragment.id, NoNetworkFragment()) + .commit() + binding.loginFragment.visibility = View.GONE + binding.loginChildFragment.visibility = View.VISIBLE + } else { + // remove no network fragment + Log.d("DashboardFragment", "Connected") + val fragment = childFragmentManager.findFragmentById(binding.loginChildFragment.id) + if (fragment is NoNetworkFragment) { + childFragmentManager.beginTransaction().remove(fragment).commit() + } + binding.loginFragment.visibility = View.VISIBLE + binding.loginChildFragment.visibility = View.GONE + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/network/NoNetworkFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/network/NoNetworkFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..681aabe093744d380d8e3aa3163cbfd733550b12 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/network/NoNetworkFragment.kt @@ -0,0 +1,35 @@ +package com.example.bandung_bondowoso.view.network + +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.navigation.fragment.findNavController +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener +import com.example.bandung_bondowoso.databinding.FragmentNoNetworkBinding +import com.example.bandung_bondowoso.util.ConnectionStateMonitor + +class NoNetworkFragment : Fragment(){ + private var _binding: FragmentNoNetworkBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreate(savedInstanceState: Bundle?) { + Log.d("NoNetworkFragment", "onCreate") + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Log.d("NoNetworkFragment", "onCreateView") + _binding = FragmentNoNetworkBinding.inflate(inflater, container, false) + + return binding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..ee86cd55af1493bb6ba089c482d19fb389506766 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanFragment.kt @@ -0,0 +1,138 @@ +package com.example.bandung_bondowoso.view.scan +import android.content.Context +import android.content.pm.PackageManager +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageCapture +import androidx.camera.core.ImageCaptureException +import androidx.camera.view.LifecycleCameraController +import androidx.camera.view.PreviewView +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.Navigation +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.databinding.FragmentScanBinding +import com.example.bandung_bondowoso.viewmodel.scan.ScanViewModel +import com.example.bandung_bondowoso.viewmodel.scan.ScanViewModelFactory +import java.io.File + + +class ScanFragment : Fragment(){ + private var _binding : FragmentScanBinding ? = null + private lateinit var cameraController: LifecycleCameraController + private val binding get() = _binding!! + private var imageFile: File? = null + private val scanViewModel: ScanViewModel by activityViewModels { + ScanViewModelFactory((activity?.application as BandungBondowosoApp).billRepository) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + Log.d("ScanFragment", "OnCreateView") + _binding = FragmentScanBinding.inflate(inflater, container, false) + val root: View = binding.root + binding.shutter.setOnClickListener { + takePhoto() ; +// Navigation.findNavController(root).navigate(R.id.action_navigation_camera_to_result) + } + return root; + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + if (!hasPermission(requireContext())) { + activityResultLauncher.launch(REQUIRED_PERMISSIONS) + } else { + startCamera() + } + } + + private fun startCamera(){ + val previewView: PreviewView = _binding!!.viewFinder + cameraController = LifecycleCameraController(requireContext()) + cameraController.bindToLifecycle(this) + cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + previewView.controller = cameraController + + } + + private fun takePhoto(){ + val name = "file" + val outputDirectory = File(requireContext().cacheDir, "camera").apply{ + mkdirs() + } + val imageFile = File(outputDirectory, name) + +// val contentValues = ContentValues().apply{ +// put(MediaStore.MediaColumns.DISPLAY_NAME, name) +// put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") +// if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P){ +// put(MediaStore.Images.Media.RELATIVE_PATH, "DCIM/Camera") +// +// } +// } +// val outputOptions = ImageCapture.OutputFileOptions +// .Builder(this.requireActivity().getContentResolver(), +// MediaStore.Images.Media.EXTERNAL_CONTENT_URI, +// contentValues) +// .build() + val outputOptions = ImageCapture.OutputFileOptions.Builder(imageFile).build() + cameraController.takePicture( + outputOptions, + ContextCompat.getMainExecutor(this.requireContext()), + object: ImageCapture.OnImageSavedCallback{ + override fun onError(exc: ImageCaptureException){ + Log.e("PhotoCapture", "Photo captured failed: ${exc.message}", exc) + } + + override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { + Log.d("PhotoCapture", "Photo captured success!") + this@ScanFragment.imageFile = imageFile + Log.d("ImageFile", "ImageFile : ${this@ScanFragment.imageFile.toString()}") + scanViewModel.setUploadFile(this@ScanFragment.imageFile!!) + Log.d("ImageFile scanFragment", "Update image file uploaded") + view?.let { Navigation.findNavController(it).navigate(R.id.action_navigation_camera_to_result)} + } + } + ) + + } + + private val activityResultLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){ + permissions -> + var permissionGranted = true + permissions.entries.forEach{ + if(it.key in REQUIRED_PERMISSIONS && it.value == false){ + permissionGranted = false + } + } + if(!permissionGranted) { + Toast.makeText(requireContext(), "Permission request denied", Toast.LENGTH_LONG).show() + }else{ + startCamera() + } + } + + companion object { + private const val TAG = "CameraXApp" + private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" + private val REQUIRED_PERMISSIONS = + mutableListOf( + android.Manifest.permission.CAMERA + ).toTypedArray() + + fun hasPermission(context: Context) = REQUIRED_PERMISSIONS.all{ + ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED; + } + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanHomeFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanHomeFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..24563dd0aa04c687b18977404ac5ab56c6022d00 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanHomeFragment.kt @@ -0,0 +1,118 @@ +package com.example.bandung_bondowoso.view.scan + +import android.content.ContentResolver +import android.content.Context +import android.net.Uri +import android.os.Bundle +import android.provider.MediaStore +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.Navigation +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener +import com.example.bandung_bondowoso.databinding.FragmentScanHomeBinding +import com.example.bandung_bondowoso.util.ConnectionStateMonitor +import com.example.bandung_bondowoso.view.network.NoNetworkFragment +import com.example.bandung_bondowoso.viewmodel.scan.ScanViewModel +import com.example.bandung_bondowoso.viewmodel.scan.ScanViewModelFactory +import java.io.File +import java.io.FileOutputStream +import java.io.InputStream +import java.io.OutputStream + +class ScanHomeFragment: Fragment(), ConnectionChangeListener { + private var _binding :FragmentScanHomeBinding ? = null; + private val binding get() = _binding!! + private val scanViewModel: ScanViewModel by activityViewModels { + ScanViewModelFactory((activity?.application as BandungBondowosoApp).billRepository) + } + private var imageFile : File? = null + private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> + if (uri != null) { + Log.d("PhotoPicker", "Selected URI: $uri") + imageFile = uriToFile(uri, this.requireContext()) + scanViewModel.setUploadFile(imageFile!!) + Navigation.findNavController(binding.root).navigate(R.id.action_navigation_scan_to_result) + } else { + Log.d("PhotoPicker", "No photo selected") + } + } + private val connectionStateMonitor = ConnectionStateMonitor(this) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + Log.d("ScanHomeFragment", "OnCreateView") + _binding = FragmentScanHomeBinding.inflate(inflater, container, false) + val root: View = binding.root + binding.toScanButton.setOnClickListener { + Navigation.findNavController(root).navigate(R.id.action_navigation_scan_to_camera_scan) + } + binding.toGaleriButton.setOnClickListener{ + pickImageGallery() + } + connectionStateMonitor.enable(requireContext()) + return root; + } + + private fun pickImageGallery(){ + pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) + } + override fun onConnectionChanged(isConnected: Boolean) { + activity?.runOnUiThread(Runnable { + if (!isConnected) { + // change fragment to no network fragment + Log.d("DashboardFragment", binding.scanChildFragment.toString()) + childFragmentManager.beginTransaction() + .replace(binding.scanChildFragment.id, NoNetworkFragment()) + .commit() + binding.scanFragment.visibility = View.GONE + binding.scanChildFragment.visibility = View.VISIBLE + } else { + // remove no network fragment + Log.d("DashboardFragment", "Connected") + val fragment = childFragmentManager.findFragmentById(binding.scanChildFragment.id) + if (fragment is NoNetworkFragment) { + childFragmentManager.beginTransaction().remove(fragment).commit() + } + binding.scanFragment.visibility = View.VISIBLE + binding.scanChildFragment.visibility = View.GONE + } + }) + } + + private fun uriToFile(imageUri: Uri, context: Context) : File{ + val contentResolver = context.contentResolver + val file = File(context.cacheDir, contentResolver.getFileName(imageUri)) + val input: InputStream? = contentResolver.openInputStream(imageUri) + val output: OutputStream = FileOutputStream(file) + input?.copyTo(output) + + return file; + } + fun ContentResolver.getFileName(uri: Uri): String{ + var name = "" + val returnCursor = this.query(uri, null, null, null, null) + if (returnCursor != null) { + val nameIndex = returnCursor.getColumnIndex(MediaStore.Images.ImageColumns.DISPLAY_NAME) + returnCursor.moveToFirst() + name = returnCursor.getString(nameIndex) + returnCursor.close() + } + return name + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanResultFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanResultFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..8166750b5276a128d25a5b380df37f867a311996 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/scan/ScanResultFragment.kt @@ -0,0 +1,112 @@ +package com.example.bandung_bondowoso.view.scan + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModelProvider +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import androidx.navigation.Navigation +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.broadcast.randomize_transaction.RandomizeTransactionReceiver +import com.example.bandung_bondowoso.databinding.FragmentScanResultBinding +import com.example.bandung_bondowoso.model.TransactionCategory +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModelFactory +import com.example.bandung_bondowoso.viewmodel.scan.ScanViewModel +import com.example.bandung_bondowoso.viewmodel.scan.ScanViewModelFactory +import com.example.bandung_bondowoso.viewmodel.transaction.RandomizeTransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModelFactory +import java.io.File + +class ScanResultFragment: Fragment() { + private var _binding: FragmentScanResultBinding ? = null + private val binding get() = _binding!! + private lateinit var randomizeTransactionViewModel: RandomizeTransactionViewModel + + + + private val scanViewModel: ScanViewModel by activityViewModels { + ScanViewModelFactory((activity?.application as BandungBondowosoApp).billRepository) + } + private val loginViewModel: LoginViewModel by activityViewModels { + LoginViewModelFactory((activity?.application as BandungBondowosoApp).userRepository) + } + private val transactionViewModel: TransactionViewModel by viewModels { + TransactionViewModelFactory((activity?.application as BandungBondowosoApp).transactionRepository) + } + + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + Log.d("ScanResultFragment", "OnCreateView") + _binding = FragmentScanResultBinding.inflate(inflater, container, false) + val root: View = binding.root + randomizeTransactionViewModel = ViewModelProvider(this).get(RandomizeTransactionViewModel::class.java) + binding.buttonUlang.setOnClickListener { + Navigation.findNavController(root).navigate(R.id.action_navigation_result_to_scan) + } + binding.testAja.text = "Waiting for result..." + binding.buttonTidakUlang.setOnClickListener{ + var tempName= "" + var tempAmount = 0.00 + var tempType = TransactionCategory.INCOME + scanViewModel.uploadResult.observe(viewLifecycleOwner) { uploadResult -> + uploadResult?.items?.items?.forEach { item -> + tempName += (item.name + " ") + tempAmount += (item.price * item.qty) + + } + Log.d("tempAmount", tempAmount.toString()) + randomizeTransactionViewModel.onRandomized() + val intent = Intent(RandomizeTransactionReceiver.ACTION) + intent.putExtra("name", tempName) + intent.putExtra("amount", tempAmount) + intent.putExtra("type", tempType) + LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent) + } + } + return root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + var token: String? + var file: File? + + scanViewModel.uploadResult.observe(viewLifecycleOwner) { uploadResult -> + var temp = "" + uploadResult?.items?.items?.forEach { item -> + temp += "Item : ${item.name} \n" + temp += "Quantity : ${item.qty} \n" + temp += "Price : ${item.price} \n \n" + } + binding.testAja.text = temp.trim() + } + file = scanViewModel.getUploadFile() + loginViewModel.getToken().observe(viewLifecycleOwner) { userToken -> + token = userToken + Log.d("Token", "Token value: $token") + if(token != null && file != null){ + scanViewModel.upload(token!!, file) + Log.d("ScanResultFragment", "Upload file") + } + } + + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/setting/SettingFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/setting/SettingFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..5f53d7ad6d5d8250d7b727427473b43925c3d3f1 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/setting/SettingFragment.kt @@ -0,0 +1,218 @@ +package com.example.bandung_bondowoso.view.setting + + +import android.content.ContentValues +import android.content.Intent +import android.os.Bundle +import android.os.Environment +import android.provider.MediaStore +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import android.widget.Toast +import androidx.core.content.FileProvider +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModelProvider +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.broadcast.connection.ConnectionChangeListener +import com.example.bandung_bondowoso.broadcast.jwt_expired.JwtExpiredReceiver +import com.example.bandung_bondowoso.broadcast.randomize_transaction.RandomizeTransactionReceiver +import com.example.bandung_bondowoso.databinding.FragmentSettingsBinding +import com.example.bandung_bondowoso.model.Transaction +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModelFactory +import com.example.bandung_bondowoso.util.ConnectionStateMonitor +import com.example.bandung_bondowoso.viewmodel.transaction.RandomizeTransactionViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModelFactory +import com.example.bandung_bondowoso.viewmodel.setting.SettingViewModel +import com.example.bandung_bondowoso.viewmodel.setting.SettingViewModelFactory +import org.apache.poi.xssf.usermodel.XSSFWorkbook +import java.io.File +import java.io.FileOutputStream + +class SettingFragment : Fragment(), ConnectionChangeListener { + private var _binding: FragmentSettingsBinding? = null + private val binding get() = _binding!! + private lateinit var userEmail: TextView + private var transactionList = listOf<Transaction>() + + private lateinit var settingViewModel: SettingViewModel + private lateinit var randomizeTransactionViewModel: RandomizeTransactionViewModel + + + fun createFile(): XSSFWorkbook { + val workbook = XSSFWorkbook() + val sheet = workbook.createSheet("Sheet1") + val dataList = mutableListOf<Array<String>>() + dataList.add(arrayOf("Date", "Category", "Amount", "Transaction Name", "Location")) + transactionList.forEach { transaction -> + val transactionArray = arrayOf( + transaction.createdAt.toString(), + transaction.type.name.toString(), + transaction.amount.toString(), + transaction.name.toString(), + transaction.locationName.toString() + + ) + dataList.add(transactionArray) + } + val data = dataList.toTypedArray() + + var rowIndex = 0 + for (rowData in data) { + val row = sheet.createRow(rowIndex++) + var cellIndex = 0 + for (cellData in rowData) { + row.createCell(cellIndex++).setCellValue(cellData) + } + } + return workbook; + } + fun writingEmail(workbook: XSSFWorkbook, filename: String, email: String){ + val outputDir = this.requireActivity().cacheDir + val excelFile = File.createTempFile("excel_file", ".xls", outputDir) + FileOutputStream(excelFile).use{outputStream -> workbook.write(outputStream)} + val androidUri = FileProvider.getUriForFile(requireContext(), "com.example.bandung_bondowoso.fileprovider", excelFile) + Log.d("fileuri", androidUri.toString()) + val emailIntent = Intent(Intent.ACTION_SEND).apply { + type = "application/vnd.ms-excel" + putExtra(Intent.EXTRA_EMAIL, arrayOf(email)) + putExtra(Intent.EXTRA_SUBJECT, "Sending All Transactions") + putExtra(Intent.EXTRA_TEXT, "We have attatched excel file below that has all of your transactions") + putExtra(Intent.EXTRA_STREAM, androidUri) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + } + + emailIntent.setPackage("com.google.android.gm") + startActivity(emailIntent) + Log.d("email", "startintentemail") + + } + + fun saveFile(workbook:XSSFWorkbook, fileName: String) { + + // Content values for MediaStore insertion + val contentValues = ContentValues().apply { + put(MediaStore.MediaColumns.DISPLAY_NAME, "$fileName") + put(MediaStore.MediaColumns.MIME_TYPE, "application/vnd.ms-excel") + put( + MediaStore.MediaColumns.RELATIVE_PATH, + Environment.DIRECTORY_DOWNLOADS + File.separator + "BondoMan" + ) + } + + // Inserting the file into MediaStore and getting the URI + val uri = context?.contentResolver?.insert( + MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY), + contentValues + ) + + if (uri != null) { + val outputStream = context?.contentResolver?.openOutputStream(uri) + if (outputStream != null) { + workbook.write(outputStream) + outputStream.close() + Toast.makeText(requireContext(), "File Created Successfully", Toast.LENGTH_LONG).show() + } else { + // todo + } + } else { + // todo + } + } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Log.d("SettingsFragment", "onCreateView") + + _binding = FragmentSettingsBinding.inflate(inflater, container, false) + val root: View = binding.root + + settingViewModel = SettingViewModelFactory( + ((this.activity?.application as BandungBondowosoApp) as BandungBondowosoApp).userRepository, + ).create(SettingViewModel::class.java) + + randomizeTransactionViewModel = ViewModelProvider(this).get(RandomizeTransactionViewModel::class.java) + + userEmail = binding.userEmail + binding.buttonSendEmail.setOnClickListener { + writingEmail(createFile(), "test", userEmail.text.toString()) + + } + binding.buttonSaveExcel.setOnClickListener { + saveFile(createFile(), "test") + } + + binding.buttonLogOut.setOnClickListener { + settingViewModel.logout() + LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(Intent(JwtExpiredReceiver.ACTION)) + } + + binding.buttonRandom.setOnClickListener { + randomizeTransactionViewModel.onRandomized() + val intent = Intent(RandomizeTransactionReceiver.ACTION) + val randomNumber = (0..100000).random() + val randomAmount = (1 .. 9999999).random() + intent.putExtra("name", "Random Transaction $randomNumber") + intent.putExtra("amount", randomAmount) + LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent) + + } + + val connectionStateMonitor = ConnectionStateMonitor(this) + connectionStateMonitor.enable(requireContext()) + + + return root + } + private val loginViewModel: LoginViewModel by viewModels { + LoginViewModelFactory((activity?.application as BandungBondowosoApp).userRepository) + } + private val transactionViewModel: TransactionViewModel by viewModels { + TransactionViewModelFactory((activity?.application as BandungBondowosoApp).transactionRepository) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + loginViewModel.getEmail().observe(viewLifecycleOwner) { email -> + Log.d(tag, "User Email: $email") + userEmail.text = email.toString() + } + transactionViewModel.transactions.observe(viewLifecycleOwner){ + Log.d(tag, "Transactions: $it") + + transactionList = it + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onConnectionChanged(isConnected: Boolean) { + activity?.runOnUiThread(Runnable { + if (_binding == null) { + _binding = FragmentSettingsBinding.inflate(layoutInflater) + } + if (isConnected) { + Log.d("SettingsFragment", "Connected") + binding.noNetworkEmailAlert.visibility = View.GONE + binding.buttonSendEmail.visibility = View.VISIBLE + } else { + Log.d("SettingsFragment", "Disconnected") + binding.noNetworkEmailAlert.visibility = View.VISIBLE + binding.buttonSendEmail.visibility = View.GONE + } + }) + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/transaction/CreateTransactionFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/CreateTransactionFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..e9b86058f7d1395b921b1cf6ba654c109cba980d --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/CreateTransactionFragment.kt @@ -0,0 +1,276 @@ +package com.example.bandung_bondowoso.view.transaction + +import android.Manifest +import android.app.Dialog +import android.content.Intent +import android.content.pm.PackageManager +import android.location.Location +import android.os.Bundle +import android.provider.Settings +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.RadioButton +import android.widget.RadioGroup +import android.widget.TextView +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.app.ActivityCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.Navigation +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.MainActivity +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.databinding.FragmentTransactionCreateBinding +import com.example.bandung_bondowoso.helper.LocationHelper +import com.example.bandung_bondowoso.helper.TransactionHelper +import com.example.bandung_bondowoso.model.Transaction +import com.example.bandung_bondowoso.model.TransactionCategory +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModelFactory +import com.example.bandung_bondowoso.viewmodel.transaction.RandomizeTransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModelFactory +import com.google.android.gms.location.FusedLocationProviderClient +import com.google.android.gms.location.LocationServices +import java.util.Date + +class CreateTransactionFragment : Fragment() { + private val tag = "createTransactionFragment" + private var _binding: FragmentTransactionCreateBinding? = null + + private lateinit var transactionName: EditText + private lateinit var transactionAmount: EditText + private lateinit var transactionLocation: EditText + private lateinit var radioGroup: RadioGroup + private lateinit var incomeRadioButton: RadioButton + private lateinit var expenseRadioButton: RadioButton + private lateinit var submitButton: Button + private lateinit var cancelButton: Button + private lateinit var dialog: Dialog + private lateinit var btnDialogCancel: Button + private lateinit var btnDialogSubmit: Button + private lateinit var tvDialogTitle:TextView + private lateinit var tvDialogMsg:TextView + private lateinit var fusedLocationClient: FusedLocationProviderClient + + private val _locationName = MutableLiveData<String?>() + private val locationName: LiveData<String?> = _locationName + + private val _locationLat = MutableLiveData<Double>() + private val locationLat: LiveData<Double> = _locationLat + + private val _locationLong = MutableLiveData<Double>() + private val locationLong: LiveData<Double> = _locationLong + private val binding get() = _binding!! + + private lateinit var transactionHelper: TransactionHelper + private lateinit var locationHelper: LocationHelper + + private lateinit var emailUser:String + + /** Initialize Transaction View Model */ + private val transactionViewModel: TransactionViewModel by viewModels { + TransactionViewModelFactory((activity?.application as BandungBondowosoApp).transactionRepository) + } + + private val loginViewModel: LoginViewModel by viewModels { + LoginViewModelFactory((activity?.application as BandungBondowosoApp).userRepository) + } + + private lateinit var randomizeTransactionViewModel: RandomizeTransactionViewModel + + override fun onCreate(savedInstanceState: Bundle?) { + Log.d(tag, "onCreate") + super.onCreate(savedInstanceState) + } + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Log.d(tag, "onCreateView") + _binding = FragmentTransactionCreateBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Log.d(tag, "onViewCreated") + super.onViewCreated(view, savedInstanceState) + randomizeTransactionViewModel = ViewModelProvider(requireActivity()).get( + RandomizeTransactionViewModel::class.java) + transactionHelper = TransactionHelper(requireContext()) + locationHelper = LocationHelper(requireContext()) + transactionName = binding.etTransactionName + transactionAmount = binding.etTransactionPrice + transactionLocation = binding.etTransactionLocation + radioGroup = binding.rgCategory + incomeRadioButton = binding.rbPemasukan + expenseRadioButton = binding.rbPembelian + dialog = Dialog(requireContext()) + dialog.setContentView(R.layout.dialog_custom) + dialog.window?.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + dialog.window?.setBackgroundDrawableResource(R.drawable.bg_custom_dialog) + dialog.setCancelable(false) + tvDialogTitle = dialog.findViewById(R.id.dialog_tv_title) + tvDialogMsg = dialog.findViewById(R.id.dialog_tv_message) + btnDialogCancel= dialog.findViewById(R.id.dialog_btn_cancel) + btnDialogSubmit= dialog.findViewById(R.id.dialog_btn_submit) + btnDialogSubmit.text = getString(R.string.button_ok) + tvDialogTitle.text= getString(R.string.dialog_title_new_transaction) + tvDialogMsg.text = getString(R.string.dialog_message_new_transaction) + submitButton = binding.btnSubmit + submitButton.setOnClickListener { + if(createNewTransaction()){ + clearField() + Navigation.findNavController(view).navigate(R.id.action_newTransactionFragment_to_navigation_transaction) + (activity as MainActivity).binding.navView.selectedItemId = R.id.navigation_transaction + Toast.makeText(requireContext(), "Create ETransaction Success", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(requireContext(), "Create ETransaction Failed", Toast.LENGTH_SHORT).show() + } + } + cancelButton = binding.btnCancel + cancelButton.setOnClickListener { + dialog.show() + btnDialogSubmit.setOnClickListener { + clearField() + Navigation.findNavController(view).navigate(R.id.action_newTransactionFragment_to_navigation_transaction) + (activity as MainActivity).binding.navView.selectedItemId = R.id.navigation_transaction + dialog.dismiss() + } + btnDialogCancel.setOnClickListener { + dialog.dismiss() + } + } + + askLocation() + + loginViewModel.getEmail().observe(viewLifecycleOwner) { email -> + emailUser = email.toString() + } + + locationName.observe(viewLifecycleOwner) { location -> + if(location != null){ + transactionLocation.setText(location) + } + } + + randomizeTransactionViewModel.transactionName.observe(viewLifecycleOwner) { name -> + transactionName.setText(name) + } + randomizeTransactionViewModel.transactionAmount.observe(viewLifecycleOwner) { amount -> + transactionAmount.setText(amount.toString()) + } + + if (ActivityCompat.checkSelfPermission( + requireContext(), + Manifest.permission.ACCESS_COARSE_LOCATION + ) != PackageManager.PERMISSION_GRANTED + ) { + locationHelper.setLatLongFromAddress(transactionLocation.text.toString()) + } + } + + private fun createNewTransaction(): Boolean{ + Log.d(tag, "createNewTransaction") + if (!transactionHelper.validateTransaction( + transactionName, + transactionAmount, + expenseRadioButton, + incomeRadioButton, + transactionLocation + )) return false + + val name = transactionName.text.toString() + val amount = transactionAmount.text.toString().toDouble() + val location = transactionLocation.text.toString() + val category = when { + incomeRadioButton.isChecked -> TransactionCategory.INCOME + expenseRadioButton.isChecked -> TransactionCategory.EXPENSE + else -> throw IllegalStateException("No category selected") + } + + val coordinates = locationHelper.setLatLongFromAddress(location) + + val newTransaction = Transaction( + name = name, + email = emailUser, + amount = amount, + type = category, + locationLat = coordinates!!.first, + locationLong = coordinates.second, + locationName = location, + createdAt = Date() + ) + Log.d(tag, "Transaction: $name, $amount, $category, ${coordinates.first}, " + + "${coordinates.second}, $location") + transactionViewModel.upsert(newTransaction) + return true + } + private fun clearField(){ + Log.d(tag, "clearField") + transactionName.text.clear() + transactionAmount.text.clear() + transactionLocation.text.clear() + incomeRadioButton.isChecked = false + expenseRadioButton.isChecked = false + } + + private fun getLastLocation() { + Log.d(tag, "getLastLocation") + fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity()) + if (ActivityCompat.checkSelfPermission( + requireContext(), + Manifest.permission.ACCESS_COARSE_LOCATION + ) != PackageManager.PERMISSION_GRANTED + ) { + return + } + + fusedLocationClient.lastLocation + .addOnSuccessListener { location: Location? -> + if (location != null) { + Log.d(tag, "Location: ${location.latitude}, ${location.longitude}") + _locationLat.value = location.latitude + _locationLong.value = location.longitude + _locationName.value = locationHelper.setLocationByLatLong(location.latitude, location.longitude) + } + } + } + + private fun askLocation() { + val locationPermissionRequest = registerForActivityResult( + ActivityResultContracts.RequestMultiplePermissions() + ) { permissions -> + when { + permissions.getOrDefault(android.Manifest.permission.ACCESS_COARSE_LOCATION, false) -> { + Log.d("HomeFragment", "Approximate location access granted") + getLastLocation() + } else -> { + Log.d("HomeFragment", "No location access granted") + Toast.makeText(context, "Please enable location", Toast.LENGTH_SHORT).show() + val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) + startActivity(intent) + } + } + } + + locationPermissionRequest.launch(arrayOf( + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION) + ) + } + + override fun onDestroyView() { + Log.d(tag, "onDestroy") + super.onDestroyView() + (activity as MainActivity).binding.navView.visibility = View.VISIBLE + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/transaction/EditTransactionFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/EditTransactionFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..64994d0fd1cb39af93be20887a513c1ab5371dc2 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/EditTransactionFragment.kt @@ -0,0 +1,190 @@ +package com.example.bandung_bondowoso.view.transaction + +import android.app.Dialog +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.RadioButton +import android.widget.RadioGroup +import android.widget.TextView +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import androidx.navigation.Navigation +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.databinding.FragmentTransactionCreateBinding +import com.example.bandung_bondowoso.helper.LocationHelper +import com.example.bandung_bondowoso.helper.TransactionHelper +import com.example.bandung_bondowoso.model.Transaction +import com.example.bandung_bondowoso.model.TransactionCategory +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModelFactory +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModelFactory +import kotlinx.coroutines.launch +import java.util.Date +import kotlin.properties.Delegates + +class EditTransactionFragment : Fragment() { + private val tag ="EditTransactionFragment" + private var _binding: FragmentTransactionCreateBinding? = null + private val transactionId: Int by lazy { + arguments?.getInt("transactionId") ?: throw IllegalArgumentException("Transaction ID not provided") + } + private val binding get() = _binding!! + private lateinit var transactionHelper: TransactionHelper + private lateinit var locationHelper: LocationHelper + /** Initialize Transaction View Model */ + private val transactionViewModel: TransactionViewModel by viewModels { + TransactionViewModelFactory((activity?.application as BandungBondowosoApp).transactionRepository) + } + private val loginViewModel: LoginViewModel by viewModels { + LoginViewModelFactory((activity?.application as BandungBondowosoApp).userRepository) + } + private lateinit var transactionName: EditText + private lateinit var transactionAmount: EditText + private lateinit var transactionLocation: EditText + private lateinit var radioGroup: RadioGroup + private lateinit var incomeRadioButton: RadioButton + private lateinit var expenseRadioButton: RadioButton + private lateinit var submitButton: Button + private lateinit var cancelButton: Button + private lateinit var transaction: Transaction + private lateinit var title: TextView + private lateinit var dialog: Dialog + private lateinit var btnDialogCancel: Button + private lateinit var btnDialogSubmit: Button + private lateinit var tvDialogTitle:TextView + private lateinit var tvDialogMsg:TextView + private lateinit var transactionDate:Date + private var locationLat by Delegates.notNull<Double>() + private var locationLong by Delegates.notNull<Double>() + private lateinit var emailUser:String + + override fun onCreate(savedInstanceState: Bundle?) { + Log.d(tag, "onCreate") + super.onCreate(savedInstanceState) + } + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + // Inflate the layout for this fragment + _binding = FragmentTransactionCreateBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Log.d(tag, "onViewCreated") + super.onViewCreated(view, savedInstanceState) + title = binding.tvTransactionNew + transactionHelper = TransactionHelper(requireContext()) + locationHelper = LocationHelper(requireContext()) + transactionName = binding.etTransactionName + transactionAmount = binding.etTransactionPrice + transactionLocation = binding.etTransactionLocation + radioGroup = binding.rgCategory + incomeRadioButton = binding.rbPemasukan + expenseRadioButton = binding.rbPembelian + submitButton = binding.btnSubmit + cancelButton = binding.btnCancel + dialog = Dialog(requireContext()) + dialog.setContentView(R.layout.dialog_custom) + dialog.window?.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + dialog.window?.setBackgroundDrawableResource(R.drawable.bg_custom_dialog) + dialog.setCancelable(false) + tvDialogTitle = dialog.findViewById(R.id.dialog_tv_title) + tvDialogMsg = dialog.findViewById(R.id.dialog_tv_message) + btnDialogCancel= dialog.findViewById(R.id.dialog_btn_cancel) + btnDialogSubmit= dialog.findViewById(R.id.dialog_btn_submit) + btnDialogSubmit.text = getString(R.string.button_ok) + submitButton = binding.btnSubmit + + loginViewModel.getEmail().observe(viewLifecycleOwner) { email -> + emailUser = email.toString() + } + + lifecycleScope.launch{ + transaction = transactionViewModel.getTransaction(transactionId) + title.text = transaction.name + transactionName.setText(transaction.name) + transactionAmount.setText(transaction.amount.toString()) + transactionLocation.setText(transaction.locationName) + if(transaction.type == TransactionCategory.INCOME ) { + incomeRadioButton.isChecked = true + } else { + expenseRadioButton.isChecked = true + } + tvDialogTitle.text = getString(R.string.dialog_title_edit_transaction, transaction.name) + tvDialogMsg.text = getString(R.string.dialog_message_edit_transaction, transaction.name) + transactionDate = transaction.createdAt + locationLat = transaction.locationLat + locationLong = transaction.locationLong + } + + submitButton.setOnClickListener { + if(editTransaction()){ + Navigation.findNavController(view).navigate(R.id.action_editTransactionFragment_to_navigation_transaction) + Toast.makeText(requireContext(), "Edit Transaction Success", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(requireContext(), "Edit Transaction Failed", Toast.LENGTH_SHORT).show() + } + } + cancelButton.setOnClickListener { + dialog.show() + btnDialogSubmit.setOnClickListener { + Navigation.findNavController(view).navigate(R.id.action_editTransactionFragment_to_navigation_transaction) + dialog.dismiss() + } + btnDialogCancel.setOnClickListener { + dialog.dismiss() + } + } + } + + private fun editTransaction(): Boolean{ + Log.d(tag, "editTransaction") + if (!transactionHelper.validateTransaction( + transactionName, + transactionAmount, + expenseRadioButton, + incomeRadioButton, + transactionLocation + )) return false + + val name = transactionName.text.toString() + val amount = transactionAmount.text.toString() + val location = transactionLocation.text.toString() + val category = when { + incomeRadioButton.isChecked -> TransactionCategory.INCOME + expenseRadioButton.isChecked -> TransactionCategory.EXPENSE + else -> throw IllegalStateException("No category selected") + } + + val coordinates = locationHelper.setLatLongFromAddress(location) + + val newTransaction = transaction.copy( + name = name, + amount = amount.toDouble(), + type = category, + locationLat = coordinates!!.first, + locationLong = coordinates.second, + locationName = location + ) + + Log.d(tag, "Transaction: $name, $amount, $category, ${coordinates.first}, " + + "${coordinates.second}, $location") + transactionViewModel.upsert(newTransaction) + return true + } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/transaction/TransactionAdapter.kt b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/TransactionAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..696ed15c0c0149b8b537a8b34bb47af7d352d24d --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/TransactionAdapter.kt @@ -0,0 +1,165 @@ +package com.example.bandung_bondowoso.view.transaction + +import android.app.Dialog +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ImageView +import android.widget.PopupMenu +import android.widget.TextView +import android.widget.Toast +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.model.Transaction +import com.example.bandung_bondowoso.model.TransactionCategory +import com.example.bandung_bondowoso.util.StringFormat +import java.text.SimpleDateFormat +import java.util.Locale + +class TransactionAdapter( + var transactionList: List<Transaction>, + private val itemClickListener: TransactionFragment +): + RecyclerView.Adapter<TransactionAdapter.TransactionViewHolder>(){ + inner class TransactionViewHolder(view: View): RecyclerView.ViewHolder(view){ + val tvTransactionName:TextView = view.findViewById(R.id.tv_transaction_name) + val tvTransactionAmount:TextView = view.findViewById(R.id.tv_transaction_amount) + val tvTransactionCategory:TextView = view.findViewById(R.id.tv_transaction_category) + val tvTransactionLocation:TextView = view.findViewById(R.id.tv_transaction_location) +// val tvTransactionCurrency:TextView = view.findViewById(R.id.tv_currency) + val tvTransactionDate:TextView = view.findViewById(R.id.tv_transaction_date) +// val tvValueIcon:ImageView = view.findViewById(R.id.img_icon_value) + val tvImageIcon:View = view.findViewById(R.id.img_icon_category) + val locationLayout:View = view.findViewById(R.id.locationLayout) + private val mMenus:ImageView = view.findViewById(R.id.img_more_action) + private val dialog: Dialog = Dialog(itemView.context) + private var btnDialogCancel: Button + private var btnDialogSubmit: Button + + init { + mMenus.setOnClickListener { + popupMenus() + } + dialog.setContentView(R.layout.dialog_custom) + dialog.window?.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT) + dialog.window?.setBackgroundDrawableResource(R.drawable.bg_custom_dialog) + dialog.setCancelable(false) + btnDialogCancel= dialog.findViewById(R.id.dialog_btn_cancel) + btnDialogSubmit= dialog.findViewById(R.id.dialog_btn_submit) + btnDialogSubmit.text = "HAPUS" + } + + private fun popupMenus(){ + val popupMenu = PopupMenu(itemView.context, mMenus) + popupMenu.inflate(R.menu.transaction_menu) + popupMenu.setOnMenuItemClickListener { + when (it.itemId) { + R.id.edit_transaction -> { + itemClickListener.onEditTransaction(itemView, + transactionList[adapterPosition].id) + true + } + R.id.delete_transaction -> { + dialog.show() + btnDialogSubmit.setOnClickListener { + Toast.makeText(itemView.context, + "Transaction Deleted", Toast.LENGTH_SHORT).show() + itemClickListener.onDeleteTransaction(transactionList[adapterPosition]) + dialog.dismiss() + } + btnDialogCancel.setOnClickListener { + Toast.makeText(itemView.context, "Canceled", Toast.LENGTH_SHORT) + .show() + dialog.dismiss() + } + true + } + else -> false + } + } + try{ + val fieldMPopup = PopupMenu::class.java.getDeclaredField("mPopup") + fieldMPopup.isAccessible = true + val mPopup = fieldMPopup.get(popupMenu) + mPopup.javaClass.getDeclaredMethod("setForceShowIcon", Boolean::class.java) + .invoke(mPopup, true) + } catch (e: Exception){ + e.printStackTrace() + } + popupMenu.show() + } + + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder { + val view = LayoutInflater.from(parent.context). + inflate(R.layout.item_transaction, parent, false) + return TransactionViewHolder(view) + } + + override fun getItemCount(): Int { + return transactionList.size + } + + override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) { + val transaction = transactionList[position] + val imageResource = when (transaction.type) { + TransactionCategory.INCOME -> R.drawable.ic_money_bill_wave + TransactionCategory.EXPENSE -> R.drawable.ic_shopping_cart + } + + val valueResource = when (transaction.type) { + TransactionCategory.INCOME -> R.drawable.ic_add + TransactionCategory.EXPENSE -> R.drawable.ic_remove + } + + Glide.with(holder.itemView.context) + .load(imageResource) + .into(holder.tvImageIcon as ImageView) + +// Glide.with(holder.itemView.context) +// .load(valueResource) +// .into(holder.tvValueIcon) + + holder.tvTransactionName.text = transaction.name + holder.tvTransactionAmount.text = when (transaction.type) { + TransactionCategory.INCOME -> "+${StringFormat.formatAmount(transaction.amount.toDouble())}" + TransactionCategory.EXPENSE -> "-${StringFormat.formatAmount(transaction.amount.toDouble())}" + } + + val category = transaction.type.name + if (category == "INCOME") { + holder.tvTransactionAmount.setTextColor( + ContextCompat.getColor(holder.itemView.context, R.color.md_theme_green) + ) +// holder.tvTransactionCurrency.setTextColor( +// ContextCompat.getColor(holder.itemView.context, R.color.md_theme_green) +// ) +// holder.tvValueIcon.setColorFilter( +// ContextCompat.getColor(holder.itemView.context, R.color.md_theme_green) +// ) + } else { + holder.tvTransactionAmount.setTextColor( + ContextCompat.getColor(holder.itemView.context, R.color.md_theme_red) + ) +// holder.tvTransactionCurrency.setTextColor( +// ContextCompat.getColor(holder.itemView.context, R.color.md_theme_red) +// ) +// holder.tvValueIcon.setColorFilter( +// ContextCompat.getColor(holder.itemView.context, R.color.md_theme_red) +// ) + } + + val dateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.getDefault()) + holder.tvTransactionCategory.text = transaction.type.name + holder.tvTransactionLocation.text = transaction.locationName + holder.tvTransactionDate.text = dateFormat.format((transaction.createdAt)) + holder.locationLayout.setOnClickListener { + itemClickListener.onOpenMap(transaction.name, transaction.locationName) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/transaction/TransactionFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/TransactionFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..8f0af422152bd7d2b94655530941ca72bbab33f0 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/transaction/TransactionFragment.kt @@ -0,0 +1,150 @@ +package com.example.bandung_bondowoso.view.transaction + +import android.annotation.SuppressLint +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.TextView +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.navigation.Navigation +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.bandung_bondowoso.BandungBondowosoApp +import com.example.bandung_bondowoso.R +import com.example.bandung_bondowoso.databinding.FragmentTransactionBinding +import com.example.bandung_bondowoso.helper.LocationHelper +import com.example.bandung_bondowoso.`interface`.TransactionItemClickListener +import com.example.bandung_bondowoso.model.Transaction +import com.example.bandung_bondowoso.util.StringFormat +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModel +import com.example.bandung_bondowoso.viewmodel.transaction.TransactionViewModelFactory +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModel +import com.example.bandung_bondowoso.viewmodel.login.LoginViewModelFactory +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.floatingactionbutton.FloatingActionButton + +class TransactionFragment : Fragment(), TransactionItemClickListener { + private var _binding: FragmentTransactionBinding? = null + private val tag = "transactionFragment" + private lateinit var userEmailValue:String + private val binding get() = _binding!! + private var transactionList = listOf<Transaction>() + private lateinit var adapter: TransactionAdapter + private lateinit var userEmail: TextView + private lateinit var balance: TextView + private lateinit var locationHelper: LocationHelper + private lateinit var bottomSheetDialog: BottomSheetDialog + private lateinit var email:String + + private val transactionViewModel: TransactionViewModel by viewModels { + TransactionViewModelFactory((activity?.application as BandungBondowosoApp).transactionRepository) + } + + private val loginViewModel: LoginViewModel by viewModels { + LoginViewModelFactory((activity?.application as BandungBondowosoApp).userRepository) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + Log.d(tag, "onCreateView") + _binding = FragmentTransactionBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + Log.d(tag, "onViewCreated") + super.onViewCreated(view, savedInstanceState) + locationHelper = LocationHelper(requireContext()) + bottomSheetDialog = BottomSheetDialog(requireContext()) + + adapter = TransactionAdapter(transactionList, itemClickListener = this) + binding.rvTransaction.adapter = adapter + binding.rvTransaction.layoutManager = LinearLayoutManager(context) + userEmail = binding.tvEmail + balance = binding.tvBalanceNominal + + + + loginViewModel.getEmail().observe(viewLifecycleOwner) { email -> + Log.d(tag, "User Email: $email") + userEmail.text = email.toString() + userEmailValue = email.toString() + this.email = userEmailValue + transactionViewModel.fetchTransactionsByEmail(email.toString()) + transactionViewModel.updateBalance(email.toString()) + } + + transactionViewModel.balance.observe(viewLifecycleOwner) { balanceValue -> + balance.text = StringFormat.formatAmount(balanceValue) + } + + transactionViewModel.transactions.observe(viewLifecycleOwner) { transactions -> + transactionList = transactions + if(transactionList.isEmpty()){ + binding.clEmptyRv.visibility = View.VISIBLE + binding.rvTransaction.visibility = View.GONE + } else { + adapter = TransactionAdapter(transactionList, itemClickListener = this) + binding.rvTransaction.adapter = adapter + } + } + + val createTransactionButton:FloatingActionButton = binding.fabCreateTransaction + createTransactionButton.setOnClickListener { + Navigation.findNavController(view).navigate(R.id.action_navigation_transaction_to_newTransactionFragment) + } + } + + @SuppressLint("NotifyDataSetChanged") + override fun onDeleteTransaction(transaction: Transaction) { + val position = transactionList.indexOf(transaction) + transactionViewModel.delete(transaction, email) + adapter.notifyItemRemoved(position) + adapter.notifyDataSetChanged() + } + + override fun onEditTransaction(root:View, id:Int) { + val bundle = bundleOf("transactionId" to id) + Navigation.findNavController(root).navigate(R.id.action_navigation_transaction_to_editTransactionFragment, bundle) + } + + override fun onOpenMap(name:String, location:String) { + val bottomSheetView = layoutInflater.inflate(R.layout.bottom_dialog_map, null) + val nameTextView = bottomSheetView.findViewById<TextView>(R.id.tv_btm_dialog_name) + val addressTextView = bottomSheetView.findViewById<TextView>(R.id.tv_address) + val buttonOpenMap = bottomSheetView.findViewById<Button>(R.id.btn_open_map) + + addressTextView.text = location + nameTextView.text = name + + bottomSheetDialog.setContentView(bottomSheetView) + bottomSheetDialog.show() + + buttonOpenMap.setOnClickListener { + bottomSheetDialog.dismiss() + val gmmIntentUri = "geo:0,0?q=$location" + val mapIntent = Intent(Intent.ACTION_VIEW, Uri.parse(gmmIntentUri)) + mapIntent.setPackage("com.google.android.apps.maps") + startActivity(mapIntent) + } + } + private fun dismissBottomSheetDialog() { + if (bottomSheetDialog.isShowing) { + bottomSheetDialog.dismiss() + } + } + + override fun onDestroyView() { + dismissBottomSheetDialog() + super.onDestroyView() + } +} + diff --git a/app/src/main/java/com/example/bandung_bondowoso/view/twibbon/TwibbonFragment.kt b/app/src/main/java/com/example/bandung_bondowoso/view/twibbon/TwibbonFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..4702f006af1edfdd925deeb85476c48a7d2b233d --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/view/twibbon/TwibbonFragment.kt @@ -0,0 +1,143 @@ +package com.example.bandung_bondowoso.view.twibbon + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.camera.core.CameraSelector +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.LifecycleCameraController +import androidx.camera.view.PreviewView +import androidx.core.content.ContextCompat +import com.example.bandung_bondowoso.databinding.FragmentTwibbonBinding + +class TwibbonFragment : Fragment() { + private var _binding : FragmentTwibbonBinding? = null + private lateinit var cameraController: LifecycleCameraController + private val binding get() = _binding!! + private var freeze = false + private lateinit var imageCapture: ImageCapture + private var selectedImage: View? = null + + companion object { + private val REQUIRED_PERMISSIONS = + mutableListOf( + android.Manifest.permission.CAMERA + ).toTypedArray() + fun hasPermission(context: Context) = TwibbonFragment.REQUIRED_PERMISSIONS.all{ + ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED; + } + } + + private lateinit var preview:Preview + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentTwibbonBinding.inflate(inflater, container, false) + return binding.root; + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + if (!hasPermission(requireContext())) { + requestCameraPermission() + } else { + startCamera() + } + selectedImage = binding.twibbon1 + imageCapture = ImageCapture.Builder().build() + _binding!!.shutter.setOnClickListener { + freeze = !freeze + takePhoto() } + _binding!!.buttonRetake.setOnClickListener { + freeze = false + binding.imageButtonSoobin.visibility = View.VISIBLE + binding.imageButtonFaker.visibility = View.VISIBLE + _binding!!.shutter.visibility = View.VISIBLE + _binding!!.buttonRetake.visibility = View.GONE + startCamera() + } + binding.imageButtonSoobin.setOnClickListener { + binding.twibbon1.visibility = View.VISIBLE + binding.twibbon2.visibility = View.GONE + selectedImage = binding.twibbon1 + } + + binding.imageButtonFaker.setOnClickListener{ + binding.twibbon2.visibility = View.VISIBLE + binding.twibbon1.visibility = View.GONE + selectedImage = binding.twibbon2 + } + } + private fun startCamera(){ + freeze = false + val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext()) + + cameraProviderFuture.addListener({ + val cameraProvider = cameraProviderFuture.get() + + preview = Preview.Builder().build().also { + it.setSurfaceProvider(binding.viewFinder.surfaceProvider) + } + + val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA + binding.viewFinder.implementationMode = PreviewView.ImplementationMode.COMPATIBLE + binding.viewFinder.overlay.add(selectedImage!!) + preview.setSurfaceProvider(binding.viewFinder.surfaceProvider) + imageCapture = ImageCapture.Builder().build() + + try { + cameraProvider.unbindAll() + cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture) + } catch (e: Exception) { + Toast.makeText(requireContext(), "Error starting camera", Toast.LENGTH_SHORT).show() + } + }, ContextCompat.getMainExecutor(requireContext())) + } + + private fun takePhoto() { + if (freeze) { + preview.setSurfaceProvider(null) + _binding!!.shutter.visibility = View.GONE + _binding!!.buttonRetake.visibility = View.VISIBLE + binding.imageButtonSoobin.visibility = View.GONE + binding.imageButtonFaker.visibility = View.GONE + } else { + preview.setSurfaceProvider(binding.viewFinder.surfaceProvider) + _binding!!.shutter.visibility = View.VISIBLE + _binding!!.buttonRetake.visibility = View.GONE + binding.imageButtonSoobin.visibility = View.VISIBLE + binding.imageButtonFaker.visibility = View.VISIBLE + } + } + + private val activityResultLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){ + permissions -> + var permissionGranted = true + permissions.entries.forEach{ + entry -> + if (entry.key in REQUIRED_PERMISSIONS && !entry.value) { + permissionGranted = false + } + } + if(!permissionGranted) { + Toast.makeText(requireContext(), "Permission request denied", Toast.LENGTH_LONG).show() + }else{ + startCamera() + } + } + + private fun requestCameraPermission() { + activityResultLauncher.launch(REQUIRED_PERMISSIONS) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/AuthViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/AuthViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..0bc871b6045d1c7be1c4232ac1fc7b9be7ef23b3 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/AuthViewModel.kt @@ -0,0 +1,36 @@ +package com.example.bandung_bondowoso.viewmodel + +import android.content.Intent +import android.content.IntentFilter +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.example.bandung_bondowoso.broadcast.jwt_expired.JwtExpiredListener +import com.example.bandung_bondowoso.broadcast.jwt_expired.JwtExpiredReceiver +import com.example.bandung_bondowoso.broadcast.jwt_valid.JwtValidListener +import com.example.bandung_bondowoso.broadcast.jwt_valid.JwtValidReceiver +import com.example.bandung_bondowoso.repository.UserRepository +import kotlinx.coroutines.launch + +class AuthViewModel: ViewModel(), JwtExpiredListener, JwtValidListener { + private val _isLoggedIn = MutableLiveData<Boolean?>() + val isLoggedIn: LiveData<Boolean?> = _isLoggedIn + + override fun onExpired() { + Log.d("AuthViewModel", "onExpired") + _isLoggedIn.value = false + } + + override fun onValid() { + Log.d("AuthViewModel", "onValid") + _isLoggedIn.value = true + } + + override fun onCleared() { + Log.d("AuthViewModel", "onCleared") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginFormState.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginFormState.kt new file mode 100644 index 0000000000000000000000000000000000000000..5c412b4f8c90a283fafb197c4e22f279ff392da2 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginFormState.kt @@ -0,0 +1,7 @@ +package com.example.bandung_bondowoso.viewmodel.login + +data class LoginFormState( + val emailError: String? = null, + val passwordError: String? = null, + val error : String? = null +) diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginResult.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginResult.kt new file mode 100644 index 0000000000000000000000000000000000000000..de1b0dc21208fd0d212926639810ac4ea818ace6 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginResult.kt @@ -0,0 +1,7 @@ +package com.example.bandung_bondowoso.viewmodel.login + +enum class LoginResult { + SUCCESS, + ERROR, + LOADING +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..238e5e1cb3ae12785968bac53e48ef4a638ea5bc --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginViewModel.kt @@ -0,0 +1,68 @@ +package com.example.bandung_bondowoso.viewmodel.login + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.bandung_bondowoso.model.NetworkResult +import com.example.bandung_bondowoso.repository.UserRepository +import kotlinx.coroutines.launch + +class LoginViewModel(private val userRepository: UserRepository) : ViewModel() { + private val _loginResult = MutableLiveData<LoginResult>() + val loginResult: LiveData<LoginResult> = _loginResult + + private val _loginFormState = MutableLiveData<LoginFormState>() + val loginFormState: LiveData<LoginFormState> = _loginFormState + + fun login(email: String, password: String) = viewModelScope.launch { + _loginResult.value = LoginResult.LOADING + when (val response = userRepository.login(email, password)) { + is NetworkResult.Success -> { + _loginResult.value = LoginResult.SUCCESS + } + is NetworkResult.Error -> { + Log.d("LoginViewModel", "login: ${response.errorMsg}") + if (!response.errorByPaths.isNullOrEmpty()) { + Log.d("LoginViewModel", "login: ${response.errorByPaths}") + + val emailErrorMsg = response.errorByPaths.find { + it.path == "email" + }?.message + + val passwordErrorMsg = response.errorByPaths.find { + it.path == "password" + }?.message + + _loginFormState.value = LoginFormState(emailErrorMsg, passwordErrorMsg) + } else { + _loginFormState.value = LoginFormState(error = response.errorMsg) + } + + _loginResult.value = LoginResult.ERROR + } + is NetworkResult.Exception -> { + Log.d("LoginViewModel", "login: ${response.e.message}") + _loginResult.value = LoginResult.ERROR + _loginFormState.value = LoginFormState(error = response.e.message) + } + } + } + fun getEmail(): LiveData<String?> { + val email = MutableLiveData<String?>() + viewModelScope.launch { + email.value = userRepository.getEmail() + } + return email + } + fun getToken(): LiveData<String?>{ + val token = MutableLiveData<String?>() + viewModelScope.launch{ + token.value = userRepository.getToken() + } + return token + } + +} + diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginViewModelFactory.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginViewModelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..0bf7881234932c6267ed007b9c91d2c94db54168 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/login/LoginViewModelFactory.kt @@ -0,0 +1,15 @@ +package com.example.bandung_bondowoso.viewmodel.login + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.bandung_bondowoso.repository.UserRepository + +class LoginViewModelFactory(private val userRepository: UserRepository) : ViewModelProvider.Factory { + override fun <T : ViewModel> create(modelClass: Class<T>): T { + if (modelClass.isAssignableFrom(LoginViewModel::class.java)) { + @Suppress("UNCHECKED_CAST") + return LoginViewModel(userRepository) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/scan/ScanViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/scan/ScanViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..a367bdf5ff47bedf1f30860ee4539fd5621956f2 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/scan/ScanViewModel.kt @@ -0,0 +1,53 @@ +package com.example.bandung_bondowoso.viewmodel.scan + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.bandung_bondowoso.model.ItemsResponse +import com.example.bandung_bondowoso.repository.BillRepository +import kotlinx.coroutines.launch +import java.io.File + +class ScanViewModel(private val billRepository: BillRepository) : ViewModel() { + private val _uploadResult = MutableLiveData<ItemsResponse?>() + val uploadResult: LiveData<ItemsResponse?> = _uploadResult + + private val _uploadFile = MutableLiveData<File?>() + val uploadFile: LiveData<File?> = _uploadFile + + private val _error = MutableLiveData<String?>() + val error: LiveData<String?> = _error + + fun upload(token: String, file: File) { + viewModelScope.launch { + try { + billRepository.upload(token, file) + _uploadResult.value = billRepository.getCurrentResponse() + Log.d("ViewModel", "Uploading..") + } catch (e: Exception) { + Log.d("ViewModel", "Error uploading") + _error.postValue(e.message) + } + } + } + fun getCurrentResponse():ItemsResponse? { + viewModelScope.launch { + val currentResponse = billRepository.getCurrentResponse() + _uploadResult.postValue(currentResponse) + } + return _uploadResult.value; + } + fun getUploadFile() : File?{ + return _uploadFile.value; + } + fun get_UploadResult(): ItemsResponse?{ + return _uploadResult.value; + } + fun setUploadFile(file: File){ + _uploadFile.value = file + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/scan/ScanViewModelFactory.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/scan/ScanViewModelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..9b05449d09a9db16e6e063615d6cbf44052f23af --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/scan/ScanViewModelFactory.kt @@ -0,0 +1,15 @@ +package com.example.bandung_bondowoso.viewmodel.scan + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.bandung_bondowoso.repository.BillRepository + +class ScanViewModelFactory(private val billRepository: BillRepository) : ViewModelProvider.Factory { + override fun <T : ViewModel> create(modelClass: Class<T>): T { + if (modelClass.isAssignableFrom(ScanViewModel::class.java)) { + @Suppress("UNCHECKED_CAST") + return ScanViewModel(billRepository) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/setting/SettingViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/setting/SettingViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..c40b0afe8c51dccfeec1f33c86550a0873db5e3e --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/setting/SettingViewModel.kt @@ -0,0 +1,31 @@ +package com.example.bandung_bondowoso.viewmodel.setting + +import android.content.Intent +import android.util.Log +import androidx.core.content.ContentProviderCompat.requireContext +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.example.bandung_bondowoso.broadcast.randomize_transaction.RandomizeTransactionListener +import com.example.bandung_bondowoso.model.TransactionCategory +import com.example.bandung_bondowoso.repository.UserRepository +import kotlinx.coroutines.launch + +class SettingViewModel(private val userRepository: UserRepository): ViewModel(){ + fun logout() { + viewModelScope.launch { + userRepository.logout() + } + } +} + +class SettingViewModelFactory(private val userRepository: UserRepository) : ViewModelProvider.Factory { + override fun <T : ViewModel> create(modelClass: Class<T>): T { + if (modelClass.isAssignableFrom(SettingViewModel::class.java)) { + @Suppress("UNCHECKED_CAST") + return SettingViewModel(userRepository) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/transaction/RandomizeTransactionViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/transaction/RandomizeTransactionViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..0f3dc5a6cd87b2dde5865dc2854e131ad94ea7ec --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/transaction/RandomizeTransactionViewModel.kt @@ -0,0 +1,39 @@ +package com.example.bandung_bondowoso.viewmodel.transaction + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.example.bandung_bondowoso.broadcast.randomize_transaction.RandomizeTransactionListener + +class RandomizeTransactionViewModel: ViewModel(), RandomizeTransactionListener { + private val _isRandomized = MutableLiveData<Boolean>() + val isRandomized = _isRandomized + + private val _transactionName = MutableLiveData<String>() + val transactionName: LiveData<String> = _transactionName + + private val _transactionAmount = MutableLiveData<Double>() + val transactionAmount:LiveData<Double> = _transactionAmount + + override fun onRandomized() { + Log.d("RandomizeTransactionViewModel", "onRandomized") + _isRandomized.value = true + } + + override fun onReceivedRandomTransaction( + transactionName: String, + transactionAmount: Double, + ) { + Log.d("RandomizeTransactionViewModel", "onReceivedRandomTransaction") + _transactionName.value = transactionName + _transactionAmount.value = transactionAmount + } + + fun getTransactionName(): String? { + return _transactionName.value + } + + + +} diff --git a/app/src/main/java/com/example/bandung_bondowoso/viewmodel/transaction/TransactionViewModel.kt b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/transaction/TransactionViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..11102d8143d32da204190297d0b19b765c83dd04 --- /dev/null +++ b/app/src/main/java/com/example/bandung_bondowoso/viewmodel/transaction/TransactionViewModel.kt @@ -0,0 +1,131 @@ +package com.example.bandung_bondowoso.viewmodel.transaction + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import com.example.bandung_bondowoso.model.Transaction +import com.example.bandung_bondowoso.model.TransactionCategory +import com.example.bandung_bondowoso.repository.TransactionRepository +import kotlinx.coroutines.launch + +class TransactionViewModel(private val repository:TransactionRepository) : ViewModel(){ + + private val _transactions = MutableLiveData<List<Transaction>>() + val transactions:LiveData<List<Transaction>> = _transactions + private val _balance = MutableLiveData<Double>() + val balance: LiveData<Double> = _balance + private val tag = "TransactionViewModel" + + + suspend fun fetchTransactions(email: String): List<Transaction> { + return repository.getAllByEmail(email) + } + fun fetchTransactionsByEmail(email: String) { + viewModelScope.launch { + val transactions = repository.getAllByEmail(email) + _transactions.value = transactions + } + } + suspend fun getTransaction(id: Int): Transaction { + return repository.getTransaction(id) + } + + fun getTransactionCount(){ + viewModelScope.launch { + repository.getCount() + } + } + fun upsert(transaction: Transaction) { + viewModelScope.launch { + repository.upsert(transaction) + updateBalance(transaction.email) + } + } + fun updateBalance(email: String) { + viewModelScope.launch { + val newBalance = (getIncome(email) - getExpense(email)) + _balance.postValue(newBalance) + } + } + suspend fun getIncome(email:String): Double { + return repository.getIncome(email) + } + + suspend fun getExpense(email:String): Double { + return repository.getExpense(email) + } + + fun delete(transaction: Transaction, email:String) { + viewModelScope.launch { + repository.delete(transaction) + updateBalance(transaction.email) + fetchTransactionsByEmail(email) + } + } + // Development function + fun deleteAll() { + viewModelScope.launch { + repository.deleteAll() + } + } + fun randomizeTransaction():Transaction{ + val random = (0..1).random() + val randomName = (1..1000).random() + val randomAmount = (0..1000000).random().toDouble() + val randomLocation = (0..1).random() + val randomType = if(random == 0) TransactionCategory.INCOME else TransactionCategory.EXPENSE + val randomLat = (-90..90).random().toDouble() + val randomLong = (-180..180).random().toDouble() + val randomLocationName = if(randomLocation == 0) "Bandung" else "Bondowoso" + return Transaction( name = "Random Transaction $randomName", email = "13521132@std.stei.itb.ac.id", + amount = randomAmount, + type = randomType, locationLat = randomLat, + locationLong = randomLong, locationName = randomLocationName, + createdAt = java.util.Date()) } + fun seedData(){ + val transactionList = mutableListOf<Transaction>( + Transaction( email = "13521132@std.stei.itb.ac.id", name = "Test 1", amount = 100.00, + type = TransactionCategory.INCOME, locationLat = 6.1944, + locationLong = 106.8229, locationName = "Jakarta", + createdAt = java.util.Date()), + Transaction( email = "13521132@std.stei.itb.ac.id", name = "Test 2", amount = 100.00, + type = TransactionCategory.INCOME, locationLat = 6.1944, + locationLong = 106.8229, locationName = "Jakarta", + createdAt = java.util.Date()), + Transaction( email = "13521132@std.stei.itb.ac.id", name = "Test 3", amount = 100.00, + type = TransactionCategory.INCOME, locationLat = 6.1944, + locationLong = 106.8229, locationName = "Jakarta", + createdAt = java.util.Date()), + Transaction(email = "13521132@std.stei.itb.ac.id", name = "Test 4 ", amount = 100.00, + type = TransactionCategory.INCOME, locationLat = 6.1944, + locationLong = 106.8229, locationName = "Jakarta", + createdAt = java.util.Date()), + Transaction(email = "13521132@std.stei.itb.ac.id", name = "Test 5", amount = 100.00, + type = TransactionCategory.INCOME, locationLat = 6.1944, + locationLong = 106.8229, locationName = "Jakarta", + createdAt = java.util.Date()), + Transaction(email = "13521132@std.stei.itb.ac.id", name = "Test 6", amount = 100.00, + type = TransactionCategory.INCOME, locationLat = 6.1944, + locationLong = 106.8229, locationName = "Jakarta", + createdAt = java.util.Date()) + ) + + transactionList.forEach { + upsert(it) + } + } + +} + +/** Provides repository to transaction view model */ +class TransactionViewModelFactory(private val repository: TransactionRepository) : ViewModelProvider.Factory { + override fun <T : ViewModel> create(modelClass: Class<T>): T { + if (modelClass.isAssignableFrom(TransactionViewModel::class.java)) { + @Suppress("UNCHECKED_CAST") + return TransactionViewModel(repository) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/app/src/main/res/color/btm_nav_bg_color.xml b/app/src/main/res/color/btm_nav_bg_color.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f1c1ea5370633f6f799395e3b1c17a22ed17a42 --- /dev/null +++ b/app/src/main/res/color/btm_nav_bg_color.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_checked="true" android:color="@color/md_theme_secondary"/> + <item android:color="@color/md_theme_surface"/> +</selector> \ No newline at end of file diff --git a/app/src/main/res/color/btm_nav_color.xml b/app/src/main/res/color/btm_nav_color.xml new file mode 100644 index 0000000000000000000000000000000000000000..693c00e23c597932a3cbad8e38f848a6b0b189f6 --- /dev/null +++ b/app/src/main/res/color/btm_nav_color.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_checked="true" android:color="@color/md_theme_primary" /> + <item android:color="@color/md_theme_onSurfaceVariant" /> +</selector> \ No newline at end of file diff --git a/app/src/main/res/drawable-night/img_logo.png b/app/src/main/res/drawable-night/img_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2d19987d6f4ab6e04d2b8336419560da16b881b3 Binary files /dev/null and b/app/src/main/res/drawable-night/img_logo.png differ diff --git a/app/src/main/res/drawable/avatar.png b/app/src/main/res/drawable/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..a822f770c2a14eab589bda898af7b5a7f1ed1b28 Binary files /dev/null and b/app/src/main/res/drawable/avatar.png differ diff --git a/app/src/main/res/drawable/bg_button_danger.xml b/app/src/main/res/drawable/bg_button_danger.xml new file mode 100644 index 0000000000000000000000000000000000000000..df25fce0ee745c6384b2fd5af3cc6de6e708e012 --- /dev/null +++ b/app/src/main/res/drawable/bg_button_danger.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="12dp" /> + <solid android:color="@color/md_theme_red" /> +</shape> diff --git a/app/src/main/res/drawable/bg_button_primary.xml b/app/src/main/res/drawable/bg_button_primary.xml new file mode 100644 index 0000000000000000000000000000000000000000..1d535f58fe07a4ec6e3cdcf3f5a076ea77538b01 --- /dev/null +++ b/app/src/main/res/drawable/bg_button_primary.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="12dp" /> + <solid android:color="@color/md_theme_primary" /> +</shape> diff --git a/app/src/main/res/drawable/bg_button_secondary.xml b/app/src/main/res/drawable/bg_button_secondary.xml new file mode 100644 index 0000000000000000000000000000000000000000..bf7cfeff6f297aaee06a8035c75493508d82d795 --- /dev/null +++ b/app/src/main/res/drawable/bg_button_secondary.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="12dp" /> + <solid android:color="@color/md_theme_secondary" /> +</shape> diff --git a/app/src/main/res/drawable/bg_custom_dialog.xml b/app/src/main/res/drawable/bg_custom_dialog.xml new file mode 100644 index 0000000000000000000000000000000000000000..67a18ff4d5b6ca1aa2b33226000937ff085c2b22 --- /dev/null +++ b/app/src/main/res/drawable/bg_custom_dialog.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/md_theme_surfaceContainer"/> + <corners android:radius="20dp"/> + <size android:width="330dp"/> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_gradient_nav.xml b/app/src/main/res/drawable/bg_gradient_nav.xml new file mode 100644 index 0000000000000000000000000000000000000000..97964227a526df69571198bd703ebd0cf3ba3ad2 --- /dev/null +++ b/app/src/main/res/drawable/bg_gradient_nav.xml @@ -0,0 +1,12 @@ +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <gradient + + android:startColor="@color/md_theme_primary_0" + android:endColor="@color/md_theme_primary" + android:type="linear" + android:angle="90" + android:centerColor="@color/md_theme_primary_0" + /> +</shape> + diff --git a/app/src/main/res/drawable/bg_settings_alert_card_email.xml b/app/src/main/res/drawable/bg_settings_alert_card_email.xml new file mode 100644 index 0000000000000000000000000000000000000000..51370ceca7ff2b5bf3a2072f2ce04ddfb0f68714 --- /dev/null +++ b/app/src/main/res/drawable/bg_settings_alert_card_email.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="8dp" /> + <solid android:color="@color/md_theme_errorContainer" /> + <stroke android:width="2dp" android:color="@color/md_theme_error"/> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_settings_card_user.xml b/app/src/main/res/drawable/bg_settings_card_user.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8370c0dbd0fce4751b42db5edb58401baeaa725 --- /dev/null +++ b/app/src/main/res/drawable/bg_settings_card_user.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/md_theme_primaryContainer" /> + <corners android:radius="10dp" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_transaction_balance.xml b/app/src/main/res/drawable/bg_transaction_balance.xml new file mode 100644 index 0000000000000000000000000000000000000000..0277b649e9fc7c12a4863b684b376e13a73176b8 --- /dev/null +++ b/app/src/main/res/drawable/bg_transaction_balance.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/md_theme_primary"/> + <corners android:radius="15dp"/> + <padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_transaction_card.xml b/app/src/main/res/drawable/bg_transaction_card.xml new file mode 100644 index 0000000000000000000000000000000000000000..1daed3c4dd4b38038046a4fc2b9674030eb8204a --- /dev/null +++ b/app/src/main/res/drawable/bg_transaction_card.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/md_theme_primaryContainer" /> + <stroke android:width="2dp" android:color="@color/md_theme_primary" /> + <corners android:radius="10dp" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_transaction_card_view.xml b/app/src/main/res/drawable/bg_transaction_card_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..609817e9f209f1f5ceee73cf9bd5debf5bdbf494 --- /dev/null +++ b/app/src/main/res/drawable/bg_transaction_card_view.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <stroke android:width="2dp" android:color="@color/md_theme_primary" /> + <corners android:radius="10dp" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_transaction_icon.xml b/app/src/main/res/drawable/bg_transaction_icon.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d9b954a4ad51b64162d575fcc5f441ea87f89f2 --- /dev/null +++ b/app/src/main/res/drawable/bg_transaction_icon.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/md_theme_primaryContainer"/> + <corners android:radius="5dp"/> + <padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/email_icon.png b/app/src/main/res/drawable/email_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bcefbac5f8b9b71b37540ae78e483ebc9bedb395 Binary files /dev/null and b/app/src/main/res/drawable/email_icon.png differ diff --git a/app/src/main/res/drawable/excel_icon.png b/app/src/main/res/drawable/excel_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..05e5c6b995d61023e1203c8c72570d8d1af5de00 Binary files /dev/null and b/app/src/main/res/drawable/excel_icon.png differ diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 0000000000000000000000000000000000000000..70046c48feedc6c8c3ef30839e8366792c5c1af2 --- /dev/null +++ b/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#FFFFFF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000000000000000000000000000000000000..b48d354e65ce274b2b645256c3bda2078d1e342a --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#000E8E" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_edit.xml b/app/src/main/res/drawable/ic_edit.xml new file mode 100644 index 0000000000000000000000000000000000000000..db53a40a8bec9e3780accfa97cc808342e40a9fd --- /dev/null +++ b/app/src/main/res/drawable/ic_edit.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#000E8E" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_graph.xml b/app/src/main/res/drawable/ic_graph.xml new file mode 100644 index 0000000000000000000000000000000000000000..c055bd544fc3632260f1a546a68429535d108cd5 --- /dev/null +++ b/app/src/main/res/drawable/ic_graph.xml @@ -0,0 +1,19 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="25dp" + android:height="24dp" + android:viewportWidth="25" + android:viewportHeight="24"> + <path + android:pathData="M12.404,3.78C12.651,3.759 12.9,3.749 13.152,3.749C18.12,3.749 22.152,7.78 22.152,12.749C22.152,17.718 18.12,21.749 13.152,21.749C11.245,21.749 9.388,21.144 7.847,20.02C6.306,18.897 5.162,17.314 4.579,15.498" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M12.399,2.249C7.014,2.249 2.649,6.614 2.649,11.999C2.647,13.372 2.936,14.73 3.497,15.983L12.399,11.999V2.249Z" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_graph_black.xml b/app/src/main/res/drawable/ic_graph_black.xml new file mode 100644 index 0000000000000000000000000000000000000000..90f8b21bfbd65751dd2d562d50c6d452bb35b91f --- /dev/null +++ b/app/src/main/res/drawable/ic_graph_black.xml @@ -0,0 +1,19 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="32dp" + android:viewportWidth="64" + android:viewportHeight="32"> + <path + android:pathData="M32.004,7.78C32.251,7.759 32.5,7.749 32.752,7.749C37.721,7.749 41.752,11.78 41.752,16.749C41.752,21.718 37.721,25.749 32.752,25.749C30.845,25.749 28.988,25.144 27.447,24.02C25.906,22.897 24.762,21.314 24.179,19.498" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M31.999,6.249C26.614,6.249 22.249,10.614 22.249,15.999C22.247,17.372 22.536,18.73 23.097,19.983L31.999,15.999V6.249Z" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 07d5da9cbf141911847041df5d7b87f0dd5ef9d4..71255239aefc1f4d596c7921ff615b7c94ece0f6 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,170 +1,14 @@ -<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="108dp" android:height="108dp" - android:viewportWidth="108" - android:viewportHeight="108"> - <path - android:fillColor="#3DDC84" - android:pathData="M0,0h108v108h-108z" /> - <path - android:fillColor="#00000000" - android:pathData="M9,0L9,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M19,0L19,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M29,0L29,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M39,0L39,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M49,0L49,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M59,0L59,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M69,0L69,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M79,0L79,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M89,0L89,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M99,0L99,108" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,9L108,9" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,19L108,19" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,29L108,29" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,39L108,39" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,49L108,49" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,59L108,59" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,69L108,69" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,79L108,79" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,89L108,89" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M0,99L108,99" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M19,29L89,29" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M19,39L89,39" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M19,49L89,49" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M19,59L89,59" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M19,69L89,69" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M19,79L89,79" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M29,19L29,89" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M39,19L39,89" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M49,19L49,89" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M59,19L59,89" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M69,19L69,89" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> - <path - android:fillColor="#00000000" - android:pathData="M79,19L79,89" - android:strokeWidth="0.8" - android:strokeColor="#33FFFFFF" /> + android:viewportWidth="50" + android:viewportHeight="50"> + <group android:scaleX="1.18" + android:scaleY="1.18" + android:translateX="-4.5" + android:translateY="-4.5"> + <path + android:pathData="M5,0L45,0A5,5 0,0 1,50 5L50,45A5,5 0,0 1,45 50L5,50A5,5 0,0 1,0 45L0,5A5,5 0,0 1,5 0z" + android:fillColor="#ffffff"/> + </group> </vector> diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 2b068d11462a4b96669193de13a711a3a36220a0..9b5eeb4e30c61e3cd65d84020ccbff520d146535 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,30 +1,14 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:aapt="http://schemas.android.com/aapt" android:width="108dp" android:height="108dp" - android:viewportWidth="108" - android:viewportHeight="108"> - <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z"> - <aapt:attr name="android:fillColor"> - <gradient - android:endX="85.84757" - android:endY="92.4963" - android:startX="42.9492" - android:startY="49.59793" - android:type="linear"> - <item - android:color="#44000000" - android:offset="0.0" /> - <item - android:color="#00000000" - android:offset="1.0" /> - </gradient> - </aapt:attr> - </path> + android:viewportWidth="325" + android:viewportHeight="524"> + <group android:scaleX="0.32872137" + android:scaleY="0.53" + android:translateX="109.08278" + android:translateY="123.14"> <path - android:fillColor="#FFFFFF" - android:fillType="nonZero" - android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" - android:strokeWidth="1" - android:strokeColor="#00000000" /> -</vector> \ No newline at end of file + android:pathData="M161.52,1.24C161,2.03 157.66,7.11 154.13,12.52C109.43,80.66 68.39,150.31 30.39,222.6C16.48,249.03 11.09,259.71 8.3,266.15C-2.77,292.01 -2.77,310.82 8.33,332.93C13.99,344.23 20.17,352.7 36.74,371.78C52.4,389.86 58.85,398.67 64.13,409.21C68.53,417.98 70.58,425.27 71.32,434.74C72.03,443.94 72.47,448.14 72.99,450.66C75.78,464.39 84.96,471.57 101.94,473.23C110.23,474.05 138.99,474.05 152.25,473.23C154.74,473.1 157.22,472.96 157.77,472.96H158.78L158.86,497.31C158.95,523.85 158.86,522.46 160.53,523.47C162.42,524.64 165.15,523.77 165.84,521.83C166.08,521.12 166.16,514.73 166.16,496.9L166.19,472.96H167.23C167.78,472.96 170.26,473.1 172.75,473.23C185.93,474.05 215.1,474.05 223.06,473.23C233.5,472.17 240.45,469.36 245.31,464.2C250.7,458.52 252.26,453.52 253.41,438.42C254.04,430.07 254.45,427.15 255.59,422.86C258.03,413.72 262.65,404.63 270.17,394.06C274.54,387.92 278.89,382.59 288.27,371.81C304.4,353.3 311.01,344.23 316.73,332.88C325.99,314.37 327.39,298.09 321.35,278.57C318.64,269.78 314.76,261.15 306.04,244.45C304.2,240.92 301.01,234.78 298.93,230.79C259.58,155.31 217.02,82.79 169.2,9.92C165.73,4.6 162.77,0.12 162.66,0.01C162.55,-0.1 162.04,0.45 161.52,1.24ZM158.81,48.86C158.81,65.51 158.81,79.49 158.81,79.9C158.81,80.61 158.73,80.55 156.9,78.75C154.08,75.91 150.31,73.56 147.33,72.69C144.24,71.82 141.31,67.15 141.28,63.05C141.26,58.33 144.29,54.62 148.17,54.62C152.25,54.62 154.65,58.44 152.41,61.39C151.48,62.62 150.93,62.89 149.18,63C147.52,63.14 146.78,63.79 146.78,65.24C146.78,66.49 147.49,66.82 149.76,66.66C152.66,66.44 155.01,64.88 156.4,62.26C157.28,60.62 157.28,57.24 156.4,55.6C155.56,53.99 154.02,52.57 152.25,51.72C150.12,50.71 146.73,50.58 144.54,51.42C142.3,52.27 140.19,54.26 138.99,56.69C136.91,60.92 136.99,65.24 139.26,69.69L140.22,71.6L138.9,71.76C132.65,72.64 127.48,75.86 124.22,80.91C121.96,84.43 121,87.63 121,91.83C120.97,96.28 122.34,100.35 125.02,103.95C126.03,105.29 126.19,105.67 126.08,106.52C125.64,110.18 123.38,112.71 120.07,113.26C117.33,113.7 113.94,112.17 112.9,110.01C112.14,108.46 112.14,105.94 112.88,104.74C113.53,103.65 114.38,103.4 116.13,103.87C117.31,104.17 117.58,104.14 118.18,103.76C118.92,103.27 119.33,102.23 119.08,101.55C118.78,100.76 117.5,100.21 115.67,100.07C111.15,99.77 108.01,103 108.28,107.72C108.39,110.23 109.19,111.92 111.1,113.83C112.82,115.56 114.25,116.32 116.79,116.84C119.77,117.47 122.72,116.86 125.26,115.12C126.68,114.14 128.57,111.6 129.15,109.85C129.39,109.08 129.66,108.48 129.72,108.48C129.8,108.48 130.46,108.78 131.2,109.17C136.61,111.92 142.98,111.05 147.16,107.01C150.52,103.73 151.95,98.96 150.74,94.91C150.03,92.51 147.9,91.34 145.74,92.16C144.43,92.65 143.39,94.12 143.61,95.24C144.24,98.41 144.04,99.88 142.73,101.58C142.38,102.07 141.42,102.78 140.6,103.19C139.32,103.82 138.88,103.9 137.46,103.76C135.21,103.57 133.22,102.53 131.41,100.62C129.69,98.82 128.93,97.45 128.32,95.19C126.22,87.08 132.67,78.7 141.01,78.72C145.14,78.75 148.28,80.2 151.87,83.78C153.91,85.82 154.54,86.67 155.72,88.96C156.49,90.46 157.47,92.73 157.88,94.01L158.67,96.33L158.81,150.47C158.89,180.23 158.86,204.59 158.78,204.59C158.7,204.59 157.96,203.71 157.17,202.65C153.67,197.95 149.92,193.86 140.9,184.82C136.17,180.1 134.97,178.35 134.07,174.94C132.18,167.7 137.05,160.71 143.63,161.23C148.42,161.64 151.78,166.61 150.61,171.52C149.95,174.28 148.12,175.92 145.69,175.92C144.29,175.92 143.34,175.43 142.21,174.17C141.64,173.52 141.12,173.19 140.63,173.19C139.84,173.19 138.58,174.28 138.58,174.96C138.58,176.38 140.85,178.65 143.03,179.36C144.95,179.99 147.57,179.77 149.43,178.81C152.25,177.42 153.91,174.96 154.52,171.39C155.39,166.34 152.44,160.57 147.9,158.39C144.43,156.73 139.84,157.08 136.36,159.29C132.37,161.83 129.86,166.66 129.83,171.8L129.8,173.32L129.12,172.51C119.28,160.96 114.79,151.68 114.71,142.75C114.68,136.71 116.73,132.81 121.11,130.57C122.67,129.78 123.1,129.67 125.04,129.67C126.74,129.67 127.56,129.81 128.65,130.3C131.22,131.42 132.86,133.98 132.45,136.2C131.99,138.65 129.55,140.7 127.12,140.7C124.93,140.7 123.68,141.98 123.76,144.14C123.87,146.87 126.03,148.18 129.42,147.55C133.16,146.84 136.23,144.52 137.98,141C138.58,139.83 139.1,138.73 139.15,138.57C139.23,138.35 139.64,138.38 140.63,138.68C142.62,139.31 145.69,139.09 147.68,138.16C149.62,137.29 151.67,135.21 152.71,133.14C153.42,131.69 153.48,131.31 153.48,128.41C153.48,125.49 153.42,125.17 152.68,123.66C151.04,120.33 148.34,118.48 145.14,118.48C143.03,118.48 141.69,119.02 140.16,120.55C138.93,121.78 138.82,122.68 139.84,123.47C140.87,124.29 141.69,124.18 142.87,123.12C143.44,122.63 144.18,122.13 144.48,122.03C145.33,121.78 146.48,122.3 147.68,123.44C149.24,124.95 149.87,126.34 149.9,128.3C149.9,131.23 148.26,133.71 145.55,134.86C144.32,135.35 141.86,135.35 140.55,134.83C139.59,134.45 139.48,134.28 139.01,132.51C137.84,127.92 133.52,123.96 128.54,122.95C126.33,122.49 122.12,122.74 120.18,123.44C115.12,125.27 110.53,130.27 108.67,135.98C108.39,136.77 108.15,137.42 108.09,137.42C108.01,137.42 107.22,136.93 106.29,136.33C104.4,135.13 102.41,134.31 99.78,133.68C97.02,133.05 91.77,133.33 89.12,134.26C88,134.64 87.04,134.91 86.99,134.86C86.71,134.58 110.85,94.12 123.18,74.22C136.83,52.16 158.48,18.25 158.75,18.5C158.78,18.55 158.81,32.2 158.81,48.86ZM172.48,27.81C194.35,61.63 213.68,93 233.42,126.75C236.02,131.14 238.07,134.8 238.01,134.86C237.99,134.91 237,134.64 235.88,134.23C234.24,133.66 233.2,133.49 230.44,133.41C225.63,133.22 222.18,134.09 218.68,136.36C217.76,136.96 216.93,137.42 216.91,137.37C216.85,137.31 216.52,136.47 216.17,135.49C213.95,129.42 209.01,124.51 203.65,123.09C201.68,122.57 197.91,122.57 195.85,123.09C191.04,124.35 187.11,128.09 185.99,132.51C185.52,134.28 185.41,134.42 184.45,134.83C183.03,135.38 180.52,135.35 179.18,134.72C175.92,133.25 174.2,129.07 175.57,125.9C176.2,124.43 178.11,122.46 179.23,122.16C180.38,121.83 180.82,121.97 182.13,123.14C183.31,124.18 184.13,124.29 185.16,123.47C186.18,122.68 186.07,121.78 184.84,120.55C183.31,119.02 181.97,118.48 179.86,118.48C176.66,118.48 173.96,120.33 172.32,123.66C171.58,125.17 171.52,125.49 171.52,128.41C171.52,131.31 171.58,131.69 172.29,133.14C173.33,135.21 175.38,137.29 177.32,138.16C179.31,139.06 182.38,139.31 184.35,138.68C185.77,138.24 186.15,138.3 186.15,138.95C186.15,139.85 187.95,142.83 189.4,144.25C191.15,146 193.23,147.12 195.55,147.55C198.62,148.1 200.53,147.2 201.16,144.93C201.82,142.53 200.42,140.7 197.93,140.7C194.52,140.7 191.86,137.34 192.71,134.15C193.12,132.65 194.6,131.06 196.35,130.3C198.51,129.32 201.57,129.4 203.78,130.46C206.85,131.96 209.12,134.88 209.96,138.41C210.43,140.26 210.35,145.37 209.83,147.8C209.14,150.96 207.83,154.65 206.35,157.54C204.19,161.8 200.01,167.78 196.02,172.37L195.2,173.32L195.17,171.69C195.09,163.39 188.83,156.94 181.31,157.41C178.36,157.6 176.39,158.42 174.39,160.27C168.54,165.68 169.17,175.59 175.57,178.84C177.24,179.66 179.94,179.96 181.69,179.49C183.74,178.95 186.42,176.41 186.42,175.04C186.42,174.31 185.19,173.19 184.37,173.19C183.88,173.19 183.31,173.6 182.46,174.47L181.26,175.78H179.37C177.76,175.78 177.37,175.67 176.53,175.04C174.42,173.43 173.65,170.18 174.61,166.99C175.65,163.63 178.14,161.5 181.37,161.23C187.98,160.71 192.82,167.67 190.93,174.94C189.95,178.68 189.07,179.85 180.82,188.2C174.28,194.84 171.3,198.2 166.96,203.77L166.22,204.72L166.19,151.32V97.92L166.88,95.21C169.34,85.52 176.39,78.72 183.96,78.72C192.38,78.72 198.81,87.05 196.68,95.19C196.07,97.45 195.31,98.82 193.59,100.62C191.73,102.59 189.76,103.6 187.46,103.76C185.96,103.87 185.55,103.79 184.24,103.11C183.14,102.53 182.51,101.96 181.91,100.98C181.06,99.61 181.01,99.06 181.26,95.19C181.34,93.99 181.26,93.69 180.71,93.09C179.21,91.5 176.5,91.56 175.13,93.19C173.87,94.67 173.52,98.05 174.26,100.98C174.86,103.27 175.92,105.04 177.81,106.9C182.02,111.08 188.23,111.95 193.86,109.14C194.57,108.78 195.2,108.48 195.25,108.48C195.31,108.48 195.58,109.06 195.85,109.77C196.13,110.5 196.79,111.73 197.3,112.55C201.02,118.18 209.66,118.67 214.31,113.48C218.36,108.92 217.35,102.37 212.29,100.43C210.65,99.8 207.75,99.99 206.68,100.76C205.7,101.52 205.62,102.56 206.52,103.46C207.09,104.03 207.39,104.14 208.1,104.01C210.89,103.49 210.89,103.49 211.71,104.2C212.42,104.8 212.53,105.07 212.62,106.79C212.75,109.3 212.1,110.83 210.29,112C207.34,113.97 203.46,113.67 201.08,111.32C199.33,109.58 198.32,105.56 199.41,104.66C200.2,104.01 202.23,100.43 202.94,98.46C205.81,90.38 203.18,81.48 196.32,75.99C193.5,73.76 189.98,72.31 186.07,71.76L184.76,71.6L185.41,70.45C187.95,66.06 188.17,60.79 185.96,56.39C184.97,54.43 182.49,52.16 180.54,51.45C178.47,50.66 175.51,50.69 173.38,51.48C168.87,53.14 166.57,58.3 168.6,62.21C169.94,64.86 172.92,66.71 175.79,66.71C177.73,66.71 178.22,66.38 178.22,65.1C178.22,63.71 177.54,63.14 175.76,63C174.07,62.89 172.94,62.15 172.21,60.71C171.52,59.34 171.52,58.44 172.23,57.18C174.07,53.91 178.77,53.69 181.45,56.75C184.81,60.54 184.54,65.89 180.76,70.56C179.64,71.93 179.23,72.23 177.98,72.61C174.61,73.56 170.81,75.99 167.83,79.03L166.19,80.72V49.51C166.19,32.07 166.3,18.39 166.44,18.52C166.55,18.69 169.28,22.84 172.48,27.81ZM98.96,140.59C101.29,141.3 102.98,142.26 104.48,143.81C107,146.35 107.85,147.58 108.07,148.89C108.34,150.72 109.76,155.17 110.88,157.71C113.32,163.25 117.69,169.86 123.1,176.16L125.32,178.73L124.22,178.57C115.86,177.15 108.34,178.13 101.53,181.6C95.46,184.65 90.9,189.19 87.83,195.17L86.44,197.9L84.42,198.93C74.16,204.12 61.59,199.13 58.17,188.48L57.6,186.7L64.81,173.74C68.81,166.61 72.91,159.26 73.95,157.41L75.83,154.08L76.05,155.22C76.9,159.51 78.46,162.84 80.97,165.68C82.64,167.59 83.19,169.64 83.02,173.6C82.89,176.76 82.42,177.94 80.62,179.58C77.96,181.95 74.96,182.01 72.77,179.71C71.79,178.68 71.05,176.85 71.05,175.54C71.07,174.34 71.98,172.51 72.82,171.93C74.25,171 76.52,171.6 76.52,172.92C76.52,173.84 77.58,174.83 78.57,174.83C80.32,174.83 80.83,173.32 79.82,171.14C78.89,169.09 76.43,167.46 74.27,167.46C71.84,167.46 69.11,169.39 68.04,171.88C67.25,173.68 67.16,177.01 67.88,178.92C68.94,181.84 71.38,184.27 73.89,184.96C75.69,185.45 78.59,185.12 80.48,184.25C84.58,182.31 86.9,178.13 86.9,172.72C86.9,171.33 86.96,170.18 87.04,170.18C87.1,170.18 87.78,170.43 88.52,170.73C93.27,172.59 100.79,172.45 102.93,170.43C104.21,169.23 104.05,166.61 102.6,165.24C101.97,164.67 101.69,164.59 100.22,164.7C99.29,164.75 97.16,164.81 95.49,164.83C92.51,164.86 92.45,164.83 90.35,163.82C87.59,162.46 85.65,160.49 84.28,157.76C83.38,155.93 83.24,155.36 83.13,153.29C82.94,149.44 83.95,146.65 86.52,143.98C88.95,141.41 91.83,140.21 95.54,140.18C96.61,140.15 98.14,140.35 98.96,140.59ZM233.15,140.67C235.42,141.38 236.89,142.31 238.56,144.03C241.05,146.68 242.06,149.46 241.87,153.26C241.79,155.28 241.62,155.91 240.75,157.74C239.46,160.47 237.49,162.4 234.62,163.82C232.55,164.83 232.49,164.86 229.51,164.83C227.84,164.81 225.71,164.75 224.78,164.7C223.3,164.59 223.03,164.67 222.4,165.24C220.95,166.61 220.79,169.23 222.07,170.43C224.18,172.4 231.43,172.62 236.15,170.84C237.11,170.49 237.93,170.18 237.99,170.18C238.04,170.18 238.1,171.28 238.1,172.59C238.1,178.1 240.42,182.31 244.57,184.27C246.41,185.12 249.33,185.45 251.11,184.96C253.63,184.27 256.03,181.87 257.13,178.92C257.83,177.01 257.78,173.68 256.99,171.88C255.92,169.48 253.16,167.46 250.97,167.46C248.68,167.46 246.11,169.09 245.18,171.11C244.16,173.32 244.68,174.83 246.41,174.83C247.42,174.83 248.13,174.2 248.46,173.02C248.76,171.9 249.85,171.17 250.92,171.41C253.76,172.04 254.83,175.95 252.97,178.84C250.81,182.14 246.68,182.23 243.87,179.03C242.42,177.39 241.92,175.81 241.92,172.94C241.92,169.34 242.5,167.43 244.03,165.68C246.54,162.84 248.13,159.46 248.95,155.22L249.17,154.02L251.6,158.36C252.94,160.74 257.04,168.08 260.73,174.69L267.4,186.7L266.94,188.2C263.52,199.07 251.16,204.15 240.61,198.96C238.64,198.01 238.62,197.98 237.52,195.77C234.32,189.41 229.68,184.74 223.47,181.6C216.63,178.13 209.23,177.15 200.8,178.57L199.74,178.73L202.61,175.35C210.48,165.98 215.87,156.1 216.93,148.97C217.13,147.58 218.11,146.21 220.65,143.65C223.71,140.59 228.88,139.33 233.15,140.67ZM123.27,185.47C128,186.43 132.84,188.42 136.94,191.04C138.71,192.19 143.69,197.24 147.87,202.1C152.03,206.93 155.66,212.31 157.77,216.76L158.81,219V238.06V257.14L158.24,256.19C155.5,251.71 150.06,246.85 145.55,244.85C142.38,243.46 139.84,242.97 136.12,242.97C131.41,242.97 127.94,244.01 124.11,246.49C122.8,247.34 120.12,247.83 117.94,247.64C113.89,247.26 110.69,244.28 110.69,240.92C110.69,239.23 111.76,237.07 113.01,236.12C114.19,235.22 116.49,234.89 117.8,235.44C119.14,235.98 120.26,237.46 120.26,238.68C120.26,239.56 120.07,239.89 119.03,240.84C117.61,242.15 117.44,243.03 118.48,244.04C119.3,244.85 119.79,244.88 120.97,244.15C122.61,243.13 124.09,240.43 124.09,238.41C124.09,234.65 120.37,231.07 116.46,231.07C113.04,231.07 109.51,233.39 107.76,236.8C107.08,238.14 107,238.58 107,240.9C107,243.33 107.05,243.6 107.93,245.21C109.65,248.35 112.96,250.62 116.84,251.3C117.91,251.46 118.78,251.65 118.84,251.68C118.89,251.74 118.56,252.5 118.1,253.37C116.92,255.72 116.38,258.12 116.35,260.96C116.32,264.1 116.73,265.82 118.26,268.99C119.28,271.09 119.88,271.94 121.6,273.63C124.8,276.8 127.64,278.24 131.91,278.87C133.85,279.17 134.01,279.26 134.61,280.18C135.51,281.55 136.23,284.39 136.04,286C135.43,290.94 130.73,294.33 125.84,293.32C123.7,292.88 122.42,292.2 121.08,290.8C119.63,289.3 119.06,287.75 119.22,285.81C119.36,284.11 119.93,283.16 121.35,282.2C122.97,281.08 125.29,281.58 126.14,283.21C126.93,284.74 128.57,285.32 129.61,284.39C130.32,283.76 130.21,282.7 129.28,281.22C126.14,276.25 118.95,276.88 116.13,282.39C115.23,284.23 115.09,287.47 115.86,289.55C117.88,294.85 124.09,298.2 129.72,297.03C133.3,296.29 136.04,294.43 138.03,291.35C140.11,288.18 140.55,283.6 139.1,280.08L138.41,278.41L139.89,277.78C144.07,275.92 146.7,271.15 145.96,266.72C145.52,264.08 144.43,262.96 142.27,262.96C140.93,262.96 139.92,263.48 139.29,264.46C138.77,265.25 138.71,265.82 138.96,267.71C139.32,270.14 138.36,271.23 135.51,271.75C131.03,272.59 126.6,270.19 124.44,265.8C123.46,263.86 123.4,263.56 123.4,261.26C123.43,257.85 124.14,256.08 126.38,253.84C129.25,251 132.75,249.74 137.21,249.99C140.44,250.15 142.6,250.89 145.25,252.66C149.13,255.26 152.52,259.54 154.71,264.62C157.91,271.99 158.81,280.1 158.81,301.32V313L156.62,310.84C151.59,305.85 144.62,302.24 135.57,299.98C132.07,299.08 129.36,298.56 118.35,296.59C109.49,295.01 104.18,293.48 99.04,290.99C92.1,287.64 86.9,282.29 84.77,276.33C83.84,273.69 83.6,268.44 84.28,265.74C85.92,259.24 90.84,255.09 96.88,255.09C100.93,255.09 104.32,256.98 105.99,260.12C106.67,261.37 106.73,261.78 106.73,264.51C106.73,267.92 106.37,268.91 104.54,270.66C103.25,271.88 102.76,272.84 102.76,274.07C102.76,275.95 104.26,277.75 105.85,277.75C106.97,277.75 108.23,276.91 109.9,275.08C114.27,270.16 115.09,262.77 111.87,256.65C109.93,252.94 106.94,250.45 102.76,248.98C100.71,248.27 100.08,248.16 97.16,248.16C94.45,248.13 93.52,248.24 91.83,248.76C89.42,249.52 87.53,250.45 85.73,251.74C84.99,252.25 84.36,252.64 84.33,252.58C84.31,252.53 83.95,251.27 83.57,249.77C81.63,242.26 77.12,235.6 71.4,231.8C69.16,230.33 68.64,229.38 68.39,226.4C68.12,223.15 69.52,220.53 72.22,219.16C75.83,217.34 79.96,218.43 81.9,221.73C82.53,222.8 82.67,223.34 82.67,224.93C82.67,227.19 82.01,228.69 80.62,229.65C78.67,230.96 77.25,230.74 76.35,229.02C75.69,227.74 74.68,227.27 73.64,227.74C72.41,228.31 72.25,229.16 73.04,230.88C74.3,233.63 77.09,234.86 80.07,233.99C84.47,232.71 86.9,229.05 86.55,224.32C85.84,215.07 74.57,211.14 67.88,217.83C65.5,220.18 64.43,222.88 64.43,226.35C64.46,227.44 64.38,228.34 64.29,228.34C64.18,228.34 63.06,228.15 61.78,227.9C58.06,227.19 53.06,227.46 49.69,228.58C42.83,230.82 37.64,236.47 35.78,243.74C35.12,246.36 35.07,250.18 35.64,252.5C36.19,254.68 37.69,257.66 39.14,259.57C40.18,260.88 40.37,261.35 40.54,262.79C40.75,265.06 40.29,267.63 39.31,269.15C37.99,271.2 34.79,272.84 32.06,272.84C28.81,272.84 25.17,270.14 24.19,267C22.82,262.68 25.01,258.86 28.61,259.27C30.36,259.46 31.02,260.2 30.94,261.95C30.88,263.09 30.99,263.45 31.54,263.99C32.39,264.84 33.67,264.87 34.25,264.05C34.79,263.28 34.82,260.61 34.3,259.35C33.7,257.93 32.33,256.57 30.8,255.91C29.63,255.42 29.03,255.31 27.44,255.42C25.22,255.56 24.16,256.05 22.6,257.61C18.64,261.56 19.16,268.58 23.78,273.17C30.39,279.8 41.63,276.44 44.12,267.08C44.34,266.26 44.53,265.28 44.53,264.84C44.53,264.43 44.55,264.1 44.61,264.1C44.64,264.1 45.43,264.35 46.3,264.68C48.41,265.41 51.66,265.66 53.58,265.2C55.35,264.79 57.4,263.78 58.83,262.68C60.06,261.7 60.99,261.78 62.9,262.98C66.4,265.2 67.19,269.97 64.57,272.87C62.19,275.52 58.74,275.79 56.12,273.58C55.11,272.73 53.82,272.62 53.22,273.3C51.88,274.89 52.7,276.31 56.01,278.05C57.08,278.63 57.62,278.71 59.97,278.71C62.57,278.71 62.79,278.65 64.43,277.78C66.48,276.66 68.12,274.97 69.08,272.89C69.71,271.56 69.82,270.98 69.82,268.74C69.82,266.4 69.73,265.99 68.94,264.32C67.9,262.11 66.13,260.31 63.99,259.3C63.15,258.89 62.41,258.53 62.38,258.51C62.33,258.48 62.57,257.82 62.87,257.01C64.27,253.32 63.53,247.7 61.42,246.25C60.22,245.4 58.47,245.84 57.1,247.31C56.37,248.08 56.28,249.28 56.69,252.5C56.83,253.73 56.78,254.03 55.96,255.37C54.07,258.48 51.12,259.27 47.7,257.58C41.82,254.71 40.4,247.12 44.55,240.9C46.5,238 48.93,236.2 52.46,235C54.75,234.24 59.35,234.29 62.02,235.11C69.43,237.43 74.49,242.94 76.65,251.05C77.66,254.82 77.88,257.91 77.39,261.1C77.14,262.66 76.98,265.85 76.95,269.15C76.93,274.4 76.95,274.7 77.69,277.07C78.65,280.16 80.18,283.19 82.15,286C82.99,287.2 83.62,288.21 83.57,288.24C83.51,288.29 82.72,288.59 81.76,288.95C76.57,290.83 72.3,295.75 71.18,301.1C70.39,304.92 70.86,308.71 72.58,312.35C73.64,314.56 73.73,315.79 73.1,318.3C71.84,323.02 68.29,326.46 63.56,327.44C57.87,328.62 52.1,324.08 52.07,318.43C52.05,314.5 55.19,311.01 58.74,311.01C60.25,311.01 61.29,311.47 62.54,312.81C63.67,313.96 64.95,314.15 65.85,313.25C66.81,312.29 66.54,311.53 64.76,309.86C61.75,307.08 57.9,306.53 54.21,308.33C45.84,312.43 46.44,324.55 55.24,329.85L56.23,330.45L53.99,332.71C52.21,334.46 51.47,335.47 50.57,337.27C47.26,343.96 48.52,351.66 53.8,356.96C58.39,361.57 64.87,362.36 69.9,358.92C76,354.74 75.97,345.73 69.84,342.51C68.61,341.86 68.15,341.78 65.85,341.78C63.67,341.78 63.06,341.89 62.02,342.43C60.3,343.33 58.47,345.14 58.47,345.98C58.47,347.84 60.63,348.25 62.33,346.72C66.29,343.11 71.81,346.86 70.42,352.18C69.13,357.15 62.71,358.76 57.73,355.4C53.8,352.72 51.85,347.86 52.84,343.09C53.44,340 54.86,337.41 57.08,335.28C59.1,333.31 60.58,332.49 63.94,331.4C67.6,330.23 68.89,329.65 70.69,328.37C73.43,326.43 75.28,323.84 76.43,320.37L77.14,318.21L78.43,319.14C81.76,321.52 87.12,322.8 90.57,322.01C93.33,321.36 94.61,317.83 92.76,315.84C92.18,315.21 91.93,315.16 89.72,315.16C85.81,315.16 82.97,314.12 80.73,311.91C77.55,308.8 76.87,304.1 79.03,300.06C81.14,296.13 85.78,294 90.19,294.93C90.98,295.09 93.25,296.05 95.22,297C101.29,300.01 107.46,301.75 118.62,303.69C125.4,304.86 125.04,304.73 123.18,305.36C119.25,306.69 116.62,308.22 113.75,310.93C109.24,315.1 106.83,320.43 106.81,326.21C106.81,331.18 108.48,335.31 111.92,338.75C115.2,342.02 118.37,343.52 122.58,343.74C126.99,343.99 130.92,342.43 134.18,339.18C139.84,333.53 140.08,325.23 134.78,320.23C130.65,316.39 124.33,316.11 120.37,319.61C117.83,321.82 117.11,323.87 118.51,324.96C119.49,325.72 120.18,325.67 120.89,324.82C122.83,322.5 123.4,321.98 124.69,321.44C125.81,320.95 126.44,320.86 127.67,320.97C132.81,321.44 135.9,326.49 134.31,331.84C133.08,335.99 129.58,339.07 125.29,339.81C120.15,340.68 114.49,337.52 111.97,332.36C107,322.23 115.26,310.11 128.54,308.03C130.92,307.65 136.09,307.87 138.63,308.44C140.71,308.9 145.08,310.98 147.98,312.92C150.69,314.69 154.38,318.43 155.75,320.75C156.35,321.79 157.2,323.62 157.58,324.8L158.29,326.92L157.01,328.73C149.38,339.4 137.65,348.38 125.04,353.24C118.29,355.84 109.49,357.75 104.21,357.75C102.21,357.75 101.91,357.67 100.41,356.79C98.36,355.56 97.18,354.25 96.09,352.02C95.33,350.43 95.24,349.97 95.24,347.78C95.24,345.54 95.33,345.14 96.12,343.55C96.61,342.57 97.7,340.98 98.58,340C100.06,338.39 100.16,338.17 100.16,336.97C100.16,335.85 100.03,335.52 99.21,334.68C97.98,333.42 94.89,331.89 92.78,331.51C86.58,330.39 80.01,334.76 78.05,341.34C77.47,343.25 77.47,347.29 78.02,349.42C79.6,355.48 84.83,360.67 91.83,363.1C92.81,363.45 93.6,363.86 93.6,364.03C93.6,364.57 90.51,366.89 88.46,367.9C76.93,373.61 60.22,369.95 48.96,359.25C37.23,348.11 32.77,331.89 37.31,316.85C39.91,308.25 45.37,301.94 52.46,299.43C54.21,298.8 54.97,298.69 57.79,298.67C60.71,298.64 61.34,298.72 63.45,299.43C66.13,300.3 66.59,300.25 68.26,299.05C69.63,298.07 70.04,297.17 69.87,295.61C69.71,294.11 68.67,292.66 66.45,290.89C51.85,279.15 31.38,276.66 14.48,284.61C12.92,285.34 11.04,286.33 10.3,286.76C9.53,287.23 8.85,287.53 8.77,287.45C8.33,287.01 11.06,278.16 13.5,272.16C16.31,265.2 19.51,258.67 30.67,237.21C39.41,220.37 52.98,195.03 53.25,195.06C53.33,195.06 53.96,195.93 54.64,197C55.33,198.03 56.88,199.86 58.12,201.04C60.69,203.47 61.2,204.64 61.2,208C61.2,210.65 60.63,212.42 59.26,213.98C57.05,216.46 54.18,217.17 51.99,215.73C49.8,214.28 49.48,211.88 51.23,210.13C52.56,208.79 53.55,208.87 55.11,210.46C56.5,211.88 57.35,212.01 58.33,211C59.21,210.15 59.18,209.55 58.22,208.22C55.22,204.07 48.76,204.83 46.71,209.55C45.95,211.33 46.06,213.95 46.96,215.7C48.98,219.71 54.15,221.46 58.25,219.55C62.38,217.64 65.03,213.1 65.03,207.94C65.03,206.85 65.09,205.95 65.14,205.95C65.22,205.95 66.37,206.3 67.68,206.77C69.02,207.21 71.02,207.7 72.14,207.89C74.9,208.33 79.93,208.05 82.45,207.34C83.54,207.01 84.55,206.77 84.72,206.77C84.88,206.77 84.99,207.53 84.99,208.54C84.99,212.12 86.38,216.87 88.46,220.39C94.72,230.93 106.83,234.67 117.69,229.43C121.96,227.38 125.18,224.21 127.15,220.2C128.35,217.74 128.82,217.36 131.71,216.49C135.02,215.51 138.03,216.16 140.41,218.35C145.66,223.12 143.88,230.9 137.4,231.51C135.65,231.7 133.85,230.85 132.92,229.46C131.99,228.07 132.1,227.44 133.52,226.26C134.97,225.09 135.1,224.3 134.04,223.23C133.46,222.66 133.16,222.58 132.37,222.69C131.14,222.9 129.58,224.11 128.95,225.36C127.81,227.57 128.71,230.79 131.09,232.98C133.46,235.16 136.25,235.85 139.4,235.05C144.02,233.88 147.03,230.19 147.27,225.42C147.74,216.6 138.96,210.37 129.66,212.94C129.12,213.08 129.06,212.97 128.9,211.14C128.19,203.93 123.81,197.57 117.58,194.7C115.47,193.75 112.93,193.12 111.02,193.12C109.71,193.12 109.43,193.23 108.61,194.05C108.01,194.65 107.68,195.25 107.66,195.74C107.55,198.72 108.45,199.75 111.59,200.19C114.19,200.57 116.21,201.55 118.02,203.44C121.79,207.26 122.94,212.99 120.81,217.31C117.5,224.05 108.07,226.78 100.77,223.12C98.25,221.84 95.46,218.92 94.04,216.02C92.4,212.69 91.96,210.78 91.99,206.91C91.99,203.36 92.32,201.75 93.77,198.72C96.34,193.26 102.02,188.37 108.23,186.32C112.8,184.79 118.43,184.49 123.27,185.47ZM213.16,185.37C222.27,187.22 229.37,193.06 232.19,200.98C232.96,203.17 233.01,203.66 233.04,206.91C233.04,210.95 232.55,213.05 230.77,216.46C229.46,218.97 226.5,221.98 224.23,223.12C218.36,226.07 210.76,224.9 206.33,220.37C201.87,215.78 202.14,208.35 206.98,203.44C208.81,201.55 210.81,200.57 213.54,200.16C214.99,199.94 215.68,199.67 216.28,199.15C217.81,197.79 217.78,195.14 216.2,193.83C215.21,192.98 213.52,192.9 210.84,193.53C202.91,195.38 196.98,202.51 196.1,211.22C195.94,212.97 195.88,213.08 195.34,212.94C195.01,212.83 193.83,212.64 192.68,212.48C186.42,211.55 180.02,215.45 178.17,221.35C177.4,223.72 177.59,227.08 178.58,229.16C181.01,234.26 186.78,236.72 191.45,234.67C194.32,233.39 196.54,230.3 196.54,227.6C196.54,225.44 195.66,224.08 193.61,223.04C192.41,222.44 191.7,222.49 190.93,223.29C189.9,224.3 190.03,225.2 191.34,226.1C191.95,226.51 192.52,227.11 192.6,227.46C192.98,228.83 191.51,230.71 189.54,231.34C186.67,232.3 182.6,229.98 181.75,226.92C181.31,225.31 181.58,222.71 182.32,221.24C183.14,219.6 184.89,217.8 186.56,216.93C187.76,216.27 188.23,216.19 190.52,216.19C192.88,216.19 193.29,216.27 194.93,217.04C196.7,217.88 196.76,217.94 197.85,220.18C200.2,225.03 204.44,228.64 210.04,230.55C220.79,234.24 232.05,229.43 237.28,218.92C238.97,215.48 239.74,212.8 239.93,209.42C240.09,206.85 240.12,206.71 240.67,206.85C247.86,208.6 252.45,208.54 257.78,206.61C258.79,206.25 259.7,205.95 259.8,205.95C259.89,205.95 259.97,206.85 259.97,207.94C259.97,213.1 262.62,217.64 266.75,219.52C269.98,220.99 274.02,220.28 276.51,217.83C280.12,214.22 279.43,208.38 275.14,206.14C273.5,205.29 270.88,205.32 269.15,206.22C266.53,207.56 265.35,210.02 266.78,211.19C267.79,211.98 268.58,211.79 269.89,210.46C271.45,208.87 272.43,208.79 273.77,210.13C275.52,211.88 275.22,214.25 273.06,215.7C270.82,217.17 267.98,216.52 265.74,213.98C264.37,212.42 263.8,210.65 263.8,208C263.8,204.7 264.34,203.41 266.72,201.2C267.87,200.13 269.45,198.33 270.27,197.16C271.1,195.99 271.81,195.03 271.86,195.03C271.92,195.03 272.57,196.18 273.31,197.54C285.78,220.75 293.4,235.27 301.61,251.27C309.97,267.65 313.25,275.35 315.71,284.52C316.15,286.22 316.4,287.58 316.26,287.58C316.13,287.58 315.41,287.2 314.68,286.76C312.33,285.32 307.79,283.3 304.53,282.29C294.69,279.17 284.03,279.23 274.18,282.42C266.89,284.8 257.51,290.64 255.73,293.92C254.39,296.35 255.02,298.23 257.64,299.62L258.82,300.25L261.25,299.49C274.4,295.34 286.65,305.71 289.08,323.08C290.23,331.48 288.67,340.44 284.71,347.86C282.47,352.07 280.47,354.74 276.92,358.32C270.44,364.82 263.3,368.56 254.47,370.06C248.18,371.15 241.4,370.36 236.7,367.99C234.57,366.92 231.18,364.41 231.32,363.97C231.37,363.84 232.22,363.45 233.18,363.1C239.35,360.97 244.27,356.55 246.35,351.33C247.09,349.45 247.23,348.71 247.34,346.12C247.5,341.58 246.54,338.77 243.84,335.83C241.1,332.85 238.07,331.46 234.13,331.46C231.34,331.46 229.48,332.03 227.24,333.56C224.18,335.66 223.99,337.35 226.5,340.06C227.35,341.01 228.45,342.54 228.88,343.5C231.26,348.6 229.13,354.55 223.96,357.17C222.57,357.88 219.91,357.94 215.81,357.34C202.69,355.48 189.9,349.83 179.86,341.42C174.56,337 167.01,328.37 167.01,326.73C167.01,324.96 168.62,321.46 170.76,318.68C173.93,314.5 181.2,309.67 186.18,308.47C188.58,307.87 194.02,307.65 196.54,308.03C204.41,309.23 211.36,314.53 213.63,321.08C216.36,328.95 212.37,337.16 204.66,339.51C196.62,341.94 188.34,334.21 190.66,326.43C191.81,322.56 195.99,320.13 199.74,321.16C200.97,321.52 202.47,322.75 204.11,324.8C204.82,325.67 205.51,325.72 206.49,324.96C207.88,323.87 207.17,321.82 204.63,319.61C200.64,316.09 194.32,316.39 190.17,320.32C187.49,322.86 186.26,326.02 186.48,329.87C186.94,337.46 193.83,343.8 201.65,343.82C208.9,343.82 215.7,338.28 217.76,330.72C218.41,328.26 218.36,324.11 217.65,321.41C215.73,314.26 209.85,308.11 202.53,305.63C199.85,304.7 199.41,304.89 207.2,303.55C217.81,301.7 223.58,300.03 229.78,297C233.78,295.04 235.55,294.55 237.79,294.76C242.63,295.2 246.24,298.53 247.12,303.36C247.88,307.57 245.59,311.91 241.54,313.87C239.54,314.86 238.12,315.13 235.28,315.16C233.07,315.16 232.82,315.21 232.24,315.84C230.93,317.23 231.15,319.64 232.71,321.08C233.5,321.79 233.97,321.95 235.5,322.12C239.02,322.5 243.4,321.36 246.41,319.25L247.91,318.19L248.35,319.74C249.41,323.32 251.52,326.38 254.36,328.43C255.73,329.38 257.15,330.04 259.97,330.99C264.67,332.6 266.2,333.42 268.17,335.44C270.96,338.23 272.38,341.7 272.38,345.6C272.35,349.48 270.85,352.59 267.92,354.94C262.95,358.84 255.95,357.42 254.58,352.18C253.19,346.86 258.71,343.14 262.67,346.72C264.34,348.22 266.53,347.81 266.53,346.04C266.53,345.14 264.75,343.36 262.98,342.43C261.94,341.89 261.33,341.78 259.15,341.78C256.99,341.78 256.36,341.89 255.4,342.4C252.78,343.8 251.25,345.93 250.67,348.98C249.52,355.1 255.02,361.02 261.86,361.02C265.52,361.02 268.47,359.71 271.31,356.82C276.54,351.52 277.71,343.99 274.43,337.27C273.5,335.42 272.82,334.49 270.99,332.66C269.73,331.43 268.72,330.36 268.77,330.34C272.9,328.43 275.93,324.44 276.65,319.99C277.85,312.48 271.29,305.85 264.4,307.62C262.37,308.14 261.01,308.96 259.61,310.49C258.46,311.74 258.36,312.45 259.15,313.25C260.05,314.15 261.33,313.96 262.46,312.81C263.71,311.47 264.75,311.01 266.26,311.01C269.81,311.01 272.95,314.5 272.93,318.43C272.9,324.08 267.13,328.62 261.44,327.44C256.74,326.46 253.13,322.99 251.9,318.3C251.25,315.76 251.36,314.56 252.45,312.29C255.65,305.68 254.36,297.85 249.25,292.8C247.53,291.08 244.96,289.44 242.88,288.78C242.14,288.54 241.49,288.29 241.43,288.27C241.4,288.24 242.28,286.85 243.4,285.15C245.4,282.18 246.65,279.42 247.61,276.03C247.99,274.64 248.07,273.3 248.02,268.74C247.99,265.55 247.8,262.19 247.61,260.94C246.71,255.64 248.49,248.19 251.79,243.3C256.17,236.88 264.04,233.36 271.07,234.65C274.7,235.3 278.53,237.87 280.5,240.92C284.66,247.42 283.1,254.96 276.97,257.77C273.88,259.19 270.88,258.32 269.13,255.53C268.25,254.08 268.2,253.43 268.58,250.04C268.77,248.49 268.72,248.32 268.03,247.5C266.61,245.81 264.75,245.35 263.44,246.36C262.48,247.09 261.58,249.61 261.42,251.95C261.31,253.7 261.8,256.46 262.54,258.1C262.67,258.42 262.32,258.7 261.14,259.24C258.96,260.25 257.1,262.11 256.06,264.32C255.27,265.99 255.18,266.4 255.18,268.74C255.18,270.98 255.29,271.56 255.92,272.89C256.88,274.97 258.49,276.66 260.57,277.78C262.21,278.65 262.43,278.71 265.03,278.71C267.46,278.71 267.9,278.63 269.13,277.97C270.96,277.02 272.22,275.87 272.41,275.02C272.65,273.96 271.67,272.84 270.49,272.84C269.98,272.84 269.48,272.98 269.37,273.14C269.29,273.3 268.64,273.8 267.95,274.23C266.94,274.86 266.39,275.02 265.11,275.02C261.55,275.02 258.87,272.24 258.87,268.58C258.87,266.81 260.35,264.16 261.96,263.09C263.93,261.78 264.92,261.67 266.17,262.68C269.65,265.41 274.51,266.18 278.7,264.68C279.57,264.38 280.34,264.1 280.36,264.1C280.39,264.1 280.47,264.68 280.58,265.39C281.43,271.61 285.8,275.92 291.96,276.55C299.01,277.29 305.49,270.93 305.02,263.69C304.7,258.83 301.44,255.37 297.18,255.37C293.08,255.37 290.32,257.99 290.32,261.84C290.32,263.8 290.83,264.65 291.98,264.65C293.27,264.65 294.14,263.61 294.09,262.08C294.06,260.47 294.66,259.54 295.92,259.3C299.04,258.73 301.25,260.94 301.25,264.68C301.25,267.49 299.28,270.49 296.49,271.97C295.32,272.57 294.74,272.7 292.91,272.7C290.51,272.7 288.59,272.02 286.84,270.55C285.07,269.05 284.11,265.71 284.55,262.57C284.77,261.18 285.01,260.61 285.97,259.41C287.45,257.55 289.08,254.08 289.52,251.87C289.96,249.61 289.69,244.83 289,242.67C287.31,237.35 283.48,232.6 278.83,230.03C278.01,229.57 276.29,228.86 275.01,228.45C271.97,227.46 266.78,227.25 263.22,227.9C261.94,228.15 260.79,228.34 260.65,228.34C260.54,228.34 260.52,227.87 260.6,227.3C261.06,224.41 259.56,220.26 257.18,217.88C251.66,212.37 242.77,213.73 239.41,220.64C238.59,222.3 238.51,222.69 238.51,225.06C238.51,227.3 238.62,227.87 239.22,229.18C240.91,232.82 245.04,235 248.43,234.04C250.97,233.33 253.21,230 252.2,228.45C251.25,227.03 249.44,227.33 248.59,229.07C247.77,230.74 246.32,230.96 244.38,229.65C242.99,228.69 242.33,227.19 242.33,224.93C242.33,223.34 242.47,222.8 243.1,221.73C245.4,217.83 250.78,217.06 254.31,220.15C256.03,221.68 256.8,223.67 256.61,226.29C256.41,229.35 255.87,230.33 253.43,231.97C247.36,236.04 242.77,243.19 241.08,251.19C240.91,251.98 240.72,252.64 240.67,252.64C240.61,252.64 239.96,252.2 239.22,251.68C235.72,249.17 230.99,247.8 226.8,248.1C217.78,248.73 211.27,255.53 211.22,264.38C211.19,265.66 211.36,267.38 211.55,268.2C212.62,272.76 216.63,277.75 219.2,277.75C220.49,277.75 221.96,276.31 222.16,274.83C222.38,273.14 222.07,272.38 220.57,270.79C218.79,268.94 218.14,267.19 218.14,264.51C218.14,259.22 221.66,255.53 227.1,255.18C232.49,254.79 237.14,257.5 239.46,262.3C240.75,264.98 241.18,267.02 241.16,270.25C241.13,275.79 239,280.62 234.62,284.93C231.92,287.61 229.89,289.03 226.2,290.86C220.46,293.7 215.81,294.98 203.65,297.14C189.57,299.62 184.32,301.02 178.36,303.94C174.2,305.96 171.39,307.92 168.46,310.82L166.14,313.11L166.27,298.23C166.44,280.67 166.82,275.79 168.57,269.56C171.09,260.45 176.5,253.51 183.09,250.92C189.79,248.32 197.85,250.92 200.64,256.57C203.21,261.76 200.86,268.39 195.58,270.93C192.85,272.24 188.91,272.18 187.08,270.79C186.01,269.97 185.71,268.88 186.12,267.13C186.72,264.43 184.59,262.44 181.77,263.04C180.35,263.37 179.45,264.54 179.1,266.53C178.27,271.09 180.74,275.65 185.06,277.73L186.59,278.46L185.93,280.08C185.11,282.01 184.84,285.21 185.3,287.28C185.79,289.66 186.94,291.68 188.77,293.53C192.66,297.41 198.12,298.34 203.1,295.99C205.23,294.95 207.64,292.66 208.73,290.56C209.44,289.22 209.52,288.84 209.52,286.35C209.52,283.92 209.44,283.46 208.79,282.23C205.94,276.85 198.84,276.31 195.72,281.22C194.73,282.78 194.65,283.84 195.5,284.42C196.48,285.1 197.5,284.96 198.29,284.01C198.67,283.54 199,283.05 199,282.91C199,282.78 199.41,282.42 199.9,282.12C202.39,280.59 205.51,282.53 205.78,285.81C206.33,292.44 197,296.05 191.67,291.27C189.35,289.17 188.47,286.11 189.27,282.91C189.51,281.96 190.03,280.73 190.39,280.18C190.99,279.26 191.15,279.17 193.07,278.9C197.33,278.24 200.37,276.74 203.37,273.69C208.79,268.25 210.24,260.42 207.09,253.81C206.54,252.69 206.11,251.74 206.11,251.68C206.11,251.65 207.01,251.46 208.1,251.3C210.89,250.84 213.22,249.69 215.1,247.8C217.43,245.46 218,244.09 218,240.9C218,238.79 217.89,238.06 217.4,237.02C216.55,235.19 214.47,233.06 212.53,232.08C211.11,231.34 210.59,231.23 208.71,231.23C206.85,231.21 206.3,231.31 205.12,231.94C202.36,233.39 200.64,236.45 201.02,239.2C201.24,240.87 202.5,243.03 203.76,243.96C205.07,244.88 205.67,244.91 206.52,244.04C207.53,243.05 207.39,242.21 205.97,240.82C204.47,239.31 204.33,238.17 205.45,236.8C206.46,235.63 207.5,235.16 209.2,235.16C211.17,235.16 212.7,236.23 213.65,238.25C215.27,241.72 213.6,245.43 209.66,247.07C207.34,248.05 202.83,247.78 200.89,246.49C199.05,245.32 196.57,244.17 194.43,243.57C192.74,243.08 191.59,242.97 188.88,242.97C184.15,242.97 181.12,243.79 176.72,246.33C174.09,247.83 169.06,252.66 167.34,255.37L166.19,257.14V238V218.86L167.67,215.97C169.47,212.39 172.51,207.78 175.4,204.18C178.33,200.52 185.44,192.96 187.11,191.7C190.36,189.24 196.73,186.51 201.54,185.5C204.77,184.82 210.21,184.76 213.16,185.37ZM26.21,288.18C18.58,291.4 13.36,295.09 9.07,300.22L7.07,302.63V300.2V297.74L8.93,296.24C13.33,292.63 19.81,289.44 25.53,288.05C26.51,287.8 26.89,287.88 26.21,288.18ZM302.62,289C307.32,290.48 312.16,293.07 316.1,296.24L317.93,297.71V300.17V302.65L316.78,301.18C314.98,298.86 311.12,295.23 308.5,293.34C306.47,291.92 302.97,290.07 298.79,288.16C298.16,287.88 298.19,287.86 299.07,288.02C299.58,288.1 301.2,288.57 302.62,289ZM34.52,290.56C25.14,294.24 17.92,300.85 13.63,309.7C12.62,311.8 11.45,315.13 10.6,318.43L10.27,319.66L9.5,317.29C9.09,315.98 8.49,313.63 8.16,312.07L7.56,309.26L8.11,308.17C9.15,306.15 12.05,302.49 14.51,300.06C19.54,295.17 26.05,291.7 33.04,290.2C34.03,289.98 35.2,289.79 35.64,289.79C36.27,289.79 36.02,289.96 34.52,290.56ZM291.9,290.2C301.8,292.22 310.49,298.23 316.15,306.94L317.46,308.96L317.11,310.9C316.75,312.89 315.06,319.2 314.81,319.44C314.76,319.53 314.57,319.03 314.4,318.41C311.12,304.92 302.76,295.25 290.21,290.42C288.24,289.68 288.89,289.58 291.9,290.2ZM39.47,296.48C39.17,296.7 37.88,297.63 36.6,298.53C35.31,299.46 32.99,301.51 31.4,303.12C25.74,308.82 21.78,316.03 20.19,323.48C19.48,326.95 19.18,333.31 19.62,336.42C19.78,337.68 19.87,338.77 19.81,338.83C19.76,338.88 19.21,338.09 18.61,337.08C17.73,335.58 17.43,334.7 17.08,332.66C15.93,325.8 17.05,318.65 20.3,312.24C24.08,304.78 30.04,299.51 37.86,296.73C40.04,295.96 40.21,295.94 39.47,296.48ZM288.54,297.25C300.16,301.67 308.36,314.04 308.36,327.14C308.36,331.7 307.73,334.84 306.42,337.08C305.79,338.12 305.27,338.91 305.22,338.86C305.16,338.8 305.22,337.9 305.35,336.86C305.74,333.97 305.68,328.97 305.22,326C304.7,322.47 304.15,320.51 302.86,317.2C299.69,309.1 294.03,302.27 285.67,296.54L284.98,296.07L285.8,296.29C286.27,296.43 287.47,296.86 288.54,297.25ZM33.18,308.39C28.7,317.34 27.44,327.33 29.49,337.87C31.51,348.36 37.64,359.03 45.48,365.69C51.66,370.93 59.56,374.92 67.16,376.59C78.95,379.18 90.81,376.59 97.9,369.82L99.48,368.31L99.43,374.81L99.34,381.34L96.47,382.78C92.92,384.56 87.89,386.22 83.68,387.02C81.05,387.51 79.47,387.62 75.01,387.62C69.11,387.64 66.65,387.32 61.75,385.95C56.56,384.5 56.83,384.7 51.88,378.77C49.48,375.88 45.18,370.83 42.39,367.6C28.04,351.03 27.25,349.99 25.44,344.89C23.8,340.27 23.34,337.38 23.34,331.95C23.34,326.68 23.67,324.49 25.03,320.35C26.62,315.62 29.57,310.63 32.91,307.02C33.92,305.93 34.77,305.06 34.79,305.06C34.85,305.06 34.11,306.56 33.18,308.39ZM295.65,311.58C298.41,315.7 300.1,319.77 301.17,324.71C301.85,327.96 301.85,335.91 301.17,339.18C300.46,342.54 298.93,346.96 297.75,349.07C296.55,351.25 292.69,355.97 282.66,367.58C278.56,372.3 273.75,377.98 271.92,380.19L268.64,384.23L265.33,385.3C252.91,389.31 239.79,388.41 228.53,382.76L225.66,381.34L225.57,374.81L225.52,368.31L227.08,369.79C233.04,375.44 242.44,378.31 251.99,377.43C258.27,376.86 263,375.49 268.85,372.65C279.08,367.63 286.21,360.51 291.3,350.24C293.32,346.14 294.69,342.13 295.48,338.01C297.64,326.79 296.36,317.1 291.38,307.51L290.04,304.92L291.96,306.94C293.02,308.03 294.69,310.13 295.65,311.58ZM158.81,349.83V361.84L140.44,361.82H122.04L124.91,360.78C133.9,357.56 141.34,353.46 148.42,347.81C150.99,345.76 158.54,338.47 158.54,338.04C158.54,337.93 158.59,337.82 158.67,337.82C158.75,337.82 158.81,343.22 158.81,349.83ZM176.31,347.56C183.36,353.27 190.41,357.23 199.41,360.51L202.96,361.82L184.59,361.84H166.19V349.89V337.9L169.83,341.58C171.8,343.61 174.72,346.28 176.31,347.56ZM154.98,369.16C154.98,369.27 150.55,373.77 145.11,379.18C139.7,384.59 135.13,389.23 135,389.47C134.86,389.75 134.75,398.13 134.75,409.46V429.01H120.67H106.59V398.97V368.94H130.79C144.1,368.94 154.98,369.05 154.98,369.16ZM218.41,398.97V429.01H204.33H190.25V409.46C190.25,395.75 190.17,389.75 189.95,389.34C189.79,389.01 185.19,384.29 179.78,378.83L169.88,368.94H194.16H218.41V398.97ZM158.86,402.49L158.81,429.01H150.2H141.59V410.8V392.56L150.12,384.04C154.82,379.34 158.73,375.63 158.81,375.74C158.89,375.88 158.92,387.92 158.86,402.49ZM183.41,410.77V429.01H174.8H166.19V402.2V375.36L174.8,383.96L183.41,392.56V410.77ZM99.48,391.03V396.46L96.56,397.96C90.98,400.8 86.19,401.84 79.93,401.62C75.42,401.43 73.02,400.97 69.19,399.46L66.34,398.37L64.87,396.05C64.05,394.8 62.76,392.89 62,391.85C61.23,390.78 60.66,389.88 60.71,389.83C60.77,389.8 62.16,390.05 63.8,390.4C71.79,392.09 80.04,391.96 87.72,390.02C91.2,389.12 95.52,387.59 97.84,386.39C98.66,385.98 99.37,385.62 99.43,385.6C99.45,385.6 99.48,388.05 99.48,391.03ZM232.79,388.68C242.2,391.93 253.16,392.45 262.54,390.1C263.41,389.86 264.21,389.72 264.26,389.77C264.29,389.83 263.06,391.79 261.5,394.11C258.85,398.02 258.55,398.4 257.32,398.92C252.94,400.8 248.51,401.7 243.7,401.7C238.29,401.7 233.5,400.53 228.47,397.96L225.52,396.46V391.06V385.62L227.79,386.69C229.02,387.26 231.29,388.16 232.79,388.68ZM99.15,415.68C98.47,416.12 95.76,417.05 93.19,417.76C90.84,418.39 90.1,418.47 85.4,418.47C81.22,418.49 79.77,418.39 77.94,417.98C76.71,417.7 75.53,417.32 75.31,417.16C75.12,416.99 74.63,415.87 74.19,414.67C73.78,413.47 72.99,411.42 72.41,410.08C71.84,408.77 71.48,407.71 71.62,407.71C71.76,407.71 73.02,407.93 74.38,408.17C77.94,408.83 85.07,408.8 88.54,408.15C91.58,407.57 96.09,406.13 98,405.17L99.34,404.49L99.43,409.98C99.48,414.18 99.4,415.49 99.15,415.68ZM228.83,405.91C235.47,408.61 243.54,409.43 250.81,408.12C252.01,407.9 253.13,407.71 253.3,407.71C253.49,407.71 253.21,408.67 252.64,409.95C252.09,411.2 251.27,413.31 250.78,414.67C249.96,416.99 249.85,417.16 248.9,417.48C245.7,418.55 239.33,418.96 234.92,418.33C232.57,418 228.85,416.99 226.83,416.12L225.52,415.57V410.11C225.52,405.04 225.55,404.65 226.01,404.79C226.26,404.87 227.54,405.36 228.83,405.91ZM99.48,424.36V429.01H88.68C82.75,429.01 77.88,428.92 77.88,428.84C77.88,428.73 77.58,427.12 77.2,425.24C76.82,423.38 76.54,421.8 76.6,421.74C76.62,421.69 77.83,421.85 79.25,422.07C82.45,422.62 89.56,422.43 92.65,421.77C94.18,421.42 98.09,420.27 99.43,419.75C99.45,419.72 99.48,421.8 99.48,424.36ZM228.39,420.68C231.84,421.8 234.32,422.21 238.78,422.37C242.03,422.48 243.81,422.4 245.75,422.07C247.17,421.85 248.38,421.69 248.43,421.74C248.49,421.8 248.21,423.38 247.83,425.27C247.45,427.12 247.12,428.73 247.12,428.84C247.12,428.92 242.25,429.01 236.32,429.01H225.52V424.34C225.52,420 225.55,419.67 226.01,419.86C226.26,419.97 227.35,420.35 228.39,420.68ZM107.44,439.84C106.13,441.92 104.51,444.51 103.88,445.58L102.71,447.57H91.11C84.39,447.57 79.5,447.46 79.39,447.33C79.22,447.02 78.81,442.77 78.57,438.75L78.43,436.1H94.12H109.84L107.44,439.84ZM146.12,436.98C145.9,437.47 144.67,440.06 143.39,442.71L141.04,447.57H124.22C114.98,447.57 107.41,447.49 107.41,447.38C107.41,447 113.32,437.58 114.19,436.57C114.57,436.13 115.69,436.1 130.57,436.1H146.51L146.12,436.98ZM158.81,441.84V447.57H152.27C148.67,447.57 145.66,447.46 145.58,447.35C145.49,447.24 146.67,444.65 148.15,441.62L150.85,436.1H154.82H158.81V441.84ZM176.88,441.62C178.36,444.68 179.59,447.24 179.59,447.35C179.59,447.49 176.58,447.57 172.89,447.57H166.19V441.84V436.1H170.18H174.15L176.88,441.62ZM212.26,438.64C215.62,443.86 217.59,447.05 217.59,447.3C217.59,447.46 211.47,447.57 200.78,447.57H183.93L182.4,444.35C181.58,442.6 180.35,440.01 179.7,438.62L178.52,436.1H194.57H210.62L212.26,438.64ZM246.43,439.02C246.22,442.71 245.78,447.02 245.59,447.33C245.51,447.46 240.23,447.57 233.88,447.57H222.29L221.12,445.58C220.49,444.51 218.88,441.92 217.56,439.84L215.16,436.1H230.88H246.6L246.43,439.02ZM98.61,454.72C98.55,454.92 97.43,457.21 96.12,459.8C93.33,465.32 93.93,465.02 89.69,462.97C86.79,461.58 84.03,459.17 82.61,456.8C81,454.15 80.21,454.4 90.05,454.4C96.83,454.4 98.69,454.48 98.61,454.72ZM137.59,455.41C137.37,455.98 136.17,458.85 134.97,461.82L132.78,467.17L128.52,467.2C117.99,467.28 98.33,466.16 97.62,465.45C97.49,465.34 102.63,455.32 103.09,454.72C103.31,454.48 107.16,454.4 120.7,454.4H138.03L137.59,455.41ZM158.81,460.1V465.81L157.11,465.97C154.63,466.22 147.38,466.63 141.89,466.85L137.13,467.04L137.32,466.33C137.4,465.95 138.55,463.11 139.84,460.02L142.21,454.4H150.5H158.81V460.1ZM183.77,456.64C184.32,457.89 185.49,460.73 186.4,462.97L188.06,467.04L183.2,466.85C177.76,466.63 170.46,466.22 167.91,465.97L166.19,465.81V460.1V454.4H174.5H182.81L183.77,456.64ZM221.91,454.72C222.43,455.38 227.49,465.34 227.35,465.48C227.1,465.73 220.57,466.38 215.4,466.65C212.62,466.82 206.35,467.04 201.46,467.12C194,467.28 192.52,467.26 192.27,466.93C192.08,466.71 191.02,464.28 189.9,461.49C188.77,458.71 187.63,455.98 187.41,455.41L186.97,454.4H204.3C217.84,454.4 221.69,454.48 221.91,454.72ZM243.56,454.53C243.56,455.3 241.73,457.92 240.04,459.61C238.37,461.28 237.44,461.93 235.36,462.94C231.07,465.04 231.7,465.34 228.83,459.61C227.46,456.91 226.34,454.61 226.34,454.53C226.34,454.45 230.22,454.4 234.95,454.4C239.68,454.4 243.56,454.45 243.56,454.53Z" + android:fillColor="#000E8E"/> + </group> +</vector> diff --git a/app/src/main/res/drawable/ic_location.xml b/app/src/main/res/drawable/ic_location.xml new file mode 100644 index 0000000000000000000000000000000000000000..779e9ff0ec736f65b79e398842aa25e711961bd1 --- /dev/null +++ b/app/src/main/res/drawable/ic_location.xml @@ -0,0 +1,20 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="16dp" + android:viewportWidth="16" + android:viewportHeight="16"> + <path + android:pathData="M8.005,1.5C5.52,1.5 3.504,3.419 3.504,5.783C3.504,8.502 6.505,12.811 7.606,14.3C7.652,14.363 7.712,14.414 7.781,14.449C7.851,14.484 7.927,14.503 8.005,14.503C8.083,14.503 8.159,14.484 8.228,14.449C8.298,14.414 8.358,14.363 8.403,14.3C9.505,12.812 12.506,8.504 12.506,5.783C12.506,3.419 10.49,1.5 8.005,1.5Z" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#535A92" + android:strokeLineCap="round"/> + <path + android:pathData="M8.006,7.504C8.836,7.504 9.508,6.832 9.508,6.003C9.508,5.173 8.836,4.501 8.006,4.501C7.177,4.501 6.505,5.173 6.505,6.003C6.505,6.832 7.177,7.504 8.006,7.504Z" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#535A92" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_map.xml b/app/src/main/res/drawable/ic_map.xml new file mode 100644 index 0000000000000000000000000000000000000000..ffd9dd90c5b45dff6468ea4995e28bc6718b2c91 --- /dev/null +++ b/app/src/main/res/drawable/ic_map.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#FFFFFF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48V20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48V3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM15,19l-6,-2.11V5l6,2.11V19z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_money_bill_wave.xml b/app/src/main/res/drawable/ic_money_bill_wave.xml new file mode 100644 index 0000000000000000000000000000000000000000..ad9fb6759702a465df41dc36c1e9b6f8a4078fa5 --- /dev/null +++ b/app/src/main/res/drawable/ic_money_bill_wave.xml @@ -0,0 +1,4 @@ +<vector android:height="28dp" android:viewportHeight="512" + android:viewportWidth="576" android:width="31.5dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="#FF000000" android:pathData="M0,112.5L0,422.3c0,18 10.1,35 27,41.3c87,32.5 174,10.3 261,-11.9c79.8,-20.3 159.6,-40.7 239.3,-18.9c23,6.3 48.7,-9.5 48.7,-33.4L576,89.7c0,-18 -10.1,-35 -27,-41.3C462,15.9 375,38.1 288,60.3C208.2,80.6 128.4,100.9 48.7,79.1C25.6,72.8 0,88.6 0,112.5zM288,352c-44.2,0 -80,-43 -80,-96s35.8,-96 80,-96s80,43 80,96s-35.8,96 -80,96zM64,352c35.3,0 64,28.7 64,64L64,416L64,352zM128,144c0,35.3 -28.7,64 -64,64L64,144h64zM512,304v64L448,368c0,-35.3 28.7,-64 64,-64zM448,96h64v64c-35.3,0 -64,-28.7 -64,-64z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_more.xml b/app/src/main/res/drawable/ic_more.xml new file mode 100644 index 0000000000000000000000000000000000000000..6a7f27486b5865f637ed23c45b34d6ea1f32a2c3 --- /dev/null +++ b/app/src/main/res/drawable/ic_more.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#FFFFFF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_remove.xml b/app/src/main/res/drawable/ic_remove.xml new file mode 100644 index 0000000000000000000000000000000000000000..128a7430fd985e7f784ba6b57f0caee824d2b7a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#FFFFFF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M19,13H5v-2h14v2z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_scan.xml b/app/src/main/res/drawable/ic_scan.xml new file mode 100644 index 0000000000000000000000000000000000000000..1e87f14a65d1b738179ff879eddee418545763a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_scan.xml @@ -0,0 +1,34 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="25dp" + android:height="24dp" + android:viewportWidth="25" + android:viewportHeight="24"> + <path + android:pathData="M16.35,21.001H18.976C19.672,21.001 20.34,20.725 20.833,20.232C21.325,19.74 21.602,19.072 21.602,18.375V15.749" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M21.602,8.252V5.625C21.602,4.929 21.325,4.261 20.833,3.769C20.34,3.276 19.672,2.999 18.976,2.999H16.35" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M8.853,21.001H6.227C5.531,21.001 4.863,20.725 4.37,20.232C3.878,19.74 3.601,19.072 3.601,18.375V15.749" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M3.601,8.252V5.625C3.601,4.929 3.878,4.261 4.37,3.769C4.863,3.276 5.531,2.999 6.227,2.999H8.853" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0710431e0396984b370e557331f8fa549f486c9e --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="25dp" + android:height="24dp" + android:viewportWidth="25" + android:viewportHeight="24"> + <path + android:pathData="M16.11,21.03C16.01,21.71 15.39,22.25 14.65,22.25H10.95C10.21,22.25 9.59,21.71 9.5,20.98L9.23,19.09C8.96,18.95 8.7,18.8 8.44,18.63L6.64,19.35C5.94,19.61 5.17,19.32 4.83,18.7L3,15.53C2.65,14.87 2.8,14.09 3.36,13.65L4.89,12.46C4.88,12.31 4.87,12.16 4.87,12C4.87,11.85 4.88,11.69 4.89,11.54L3.37,10.35C2.78,9.9 2.63,9.09 3,8.47L4.85,5.28C5.19,4.66 5.96,4.38 6.64,4.65L8.45,5.38C8.71,5.21 8.97,5.06 9.23,4.92L9.5,3.01C9.59,2.31 10.21,1.76 10.94,1.76H14.64C15.38,1.76 16,2.3 16.09,3.03L16.36,4.92C16.63,5.06 16.89,5.21 17.15,5.38L18.95,4.66C19.66,4.4 20.43,4.69 20.77,5.31L22.61,8.49C22.97,9.15 22.81,9.93 22.25,10.37L20.73,11.56C20.74,11.71 20.75,11.86 20.75,12.02C20.75,12.18 20.74,12.33 20.73,12.48L22.25,13.67C22.81,14.12 22.97,14.9 22.62,15.53L20.76,18.75C20.42,19.37 19.65,19.65 18.96,19.38L17.16,18.66C16.9,18.83 16.64,18.98 16.38,19.12L16.11,21.03ZM11.42,20.25H14.18L14.55,17.7L15.08,17.48C15.52,17.3 15.96,17.04 16.42,16.7L16.87,16.36L19.25,17.32L20.63,14.92L18.6,13.34L18.67,12.78L18.673,12.753C18.702,12.503 18.73,12.261 18.73,12C18.73,11.73 18.7,11.47 18.67,11.22L18.6,10.66L20.63,9.08L19.24,6.68L16.85,7.64L16.4,7.29C15.98,6.97 15.53,6.71 15.07,6.52L14.55,6.3L14.18,3.75H11.42L11.05,6.3L10.52,6.51C10.08,6.7 9.64,6.95 9.18,7.3L8.73,7.63L6.35,6.68L4.96,9.07L6.99,10.65L6.92,11.21C6.89,11.47 6.86,11.74 6.86,12C6.86,12.26 6.88,12.53 6.92,12.78L6.99,13.34L4.96,14.92L6.34,17.32L8.73,16.36L9.18,16.71C9.61,17.04 10.04,17.29 10.51,17.48L11.04,17.7L11.42,20.25ZM16.3,12C16.3,13.933 14.733,15.5 12.8,15.5C10.867,15.5 9.3,13.933 9.3,12C9.3,10.067 10.867,8.5 12.8,8.5C14.733,8.5 16.3,10.067 16.3,12Z" + android:fillColor="#46464F" + android:fillType="evenOdd"/> +</vector> diff --git a/app/src/main/res/drawable/ic_shopping_cart.xml b/app/src/main/res/drawable/ic_shopping_cart.xml new file mode 100644 index 0000000000000000000000000000000000000000..aeda9020e5a587baa49b759306c5dbd40d033cf5 --- /dev/null +++ b/app/src/main/res/drawable/ic_shopping_cart.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#FFFFFF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2zM1,2v2h2l3.6,7.59 -1.35,2.45c-0.16,0.28 -0.25,0.61 -0.25,0.96 0,1.1 0.9,2 2,2h12v-2L7.42,15c-0.14,0 -0.25,-0.11 -0.25,-0.25l0.03,-0.12 0.9,-1.63h7.45c0.75,0 1.41,-0.41 1.75,-1.03l3.58,-6.49c0.08,-0.14 0.12,-0.31 0.12,-0.48 0,-0.55 -0.45,-1 -1,-1L5.21,4l-0.94,-2L1,2zM17,18c-1.1,0 -1.99,0.9 -1.99,2s0.89,2 1.99,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_transaction.xml b/app/src/main/res/drawable/ic_transaction.xml new file mode 100644 index 0000000000000000000000000000000000000000..4b98922a357c1a3b0c3b50b057cb795ca1ed24e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_transaction.xml @@ -0,0 +1,32 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M7.498,15.749V2.249L8.998,2.999L10.498,2.249L11.995,2.999L13.513,2.249L14.998,2.999L16.488,2.249L17.985,2.999L19.498,2.249L20.999,2.999L22.498,2.249V12.749" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000"/> + <path + android:pathData="M22.5,12.751V18.001C22.5,18.996 22.104,19.949 21.401,20.653C20.698,21.356 19.744,21.751 18.75,21.751V21.751C17.755,21.751 16.801,21.356 16.098,20.653C15.395,19.949 15,18.996 15,18.001V15.751H2.25C2.151,15.75 2.053,15.769 1.962,15.806C1.87,15.844 1.787,15.899 1.717,15.969C1.647,16.038 1.592,16.122 1.555,16.213C1.517,16.304 1.499,16.402 1.5,16.501C1.5,19.501 1.815,21.751 5.25,21.751H18.75" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000"/> + <path + android:pathData="M10.499,6.75H19.5" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> + <path + android:pathData="M13.5,10.501H19.501" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_twibbon.xml b/app/src/main/res/drawable/ic_twibbon.xml new file mode 100644 index 0000000000000000000000000000000000000000..644aa5ac01c332d607613094becb83e53f76d3e7 --- /dev/null +++ b/app/src/main/res/drawable/ic_twibbon.xml @@ -0,0 +1,13 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M16.542,3.751C13.499,3.751 11.999,6.751 11.999,6.751C11.999,6.751 10.499,3.751 7.456,3.751C4.983,3.751 3.024,5.82 2.999,8.289C2.947,13.414 7.064,17.058 11.577,20.121C11.701,20.206 11.848,20.251 11.999,20.251C12.149,20.251 12.296,20.206 12.421,20.121C16.933,17.058 21.05,13.414 20.999,8.289C20.974,5.82 19.015,3.751 16.542,3.751Z" + android:strokeLineJoin="round" + android:strokeWidth="1.00189" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeLineCap="round"/> +</vector> diff --git a/app/src/main/res/drawable/ic_twibbon_faker.png b/app/src/main/res/drawable/ic_twibbon_faker.png new file mode 100644 index 0000000000000000000000000000000000000000..2f7ab4110c111eb722a713067f5e045e7d06c637 Binary files /dev/null and b/app/src/main/res/drawable/ic_twibbon_faker.png differ diff --git a/app/src/main/res/drawable/ic_twibbon_soobin.png b/app/src/main/res/drawable/ic_twibbon_soobin.png new file mode 100644 index 0000000000000000000000000000000000000000..14d2dad929ae7e0050f1ec926a895a06f43d095c Binary files /dev/null and b/app/src/main/res/drawable/ic_twibbon_soobin.png differ diff --git a/app/src/main/res/drawable/img_logo.png b/app/src/main/res/drawable/img_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e05c890c4162cf3dee6875d64707718be68ee9d7 Binary files /dev/null and b/app/src/main/res/drawable/img_logo.png differ diff --git a/app/src/main/res/drawable/img_no_network.png b/app/src/main/res/drawable/img_no_network.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa347a162c6e2fec034d454fc89d9efb6df6672 Binary files /dev/null and b/app/src/main/res/drawable/img_no_network.png differ diff --git a/app/src/main/res/drawable/no_data_cuate.xml b/app/src/main/res/drawable/no_data_cuate.xml new file mode 100644 index 0000000000000000000000000000000000000000..e6c0aaeb1d8d22069c48d3e89a23ca8dfc1adc6b --- /dev/null +++ b/app/src/main/res/drawable/no_data_cuate.xml @@ -0,0 +1,524 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="750dp" + android:height="500dp" + android:viewportWidth="750" + android:viewportHeight="500"> + <path + android:pathData="M666.95,150.27l-9.57,46.35l-6.16,-6.01l-10.48,7.48l-8.01,-9.95l-17.96,13.06l-15.35,-25.67l-17.12,10.03l-6.79,-9.36l-21.74,12.25l-6.54,-14.01l15.24,-73.81l81.7,16.87l22.78,32.77z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M644.17,117.5l22.78,32.77l-28.34,-5.85l5.56,-26.92z" + android:fillColor="#dbdbdb"/> + <path + android:pathData="M655.34,205.88l-14.03,68l-110.05,-22.72l13.93,-67.45l6.54,14l21.75,-12.25l6.78,9.36l17.13,-10.02l15.34,25.67l17.97,-13.06l8,9.94l10.49,-7.47l6.15,6z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M497.83,197.91l-112.15,6.94l-8.91,-143.96l83.28,-5.16l30.57,25.65l7.21,116.53z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M460.05,55.73l30.57,25.65l-28.88,1.79l-1.69,-27.44z" + android:fillColor="#dbdbdb"/> + <path + android:pathData="M429,152.6l-0.44,-3.25c-1.13,-6.73 0.71,-14.26 6.56,-22.13 5.28,-7 8.14,-12 7.82,-17.68 -0.36,-6.4 -4.61,-10.44 -12.52,-10.12a22.31,22.31 0,0 0,-12.45 4.6l-3.45,-7.73c4,-3.25 11,-5.65 17.65,-6 14.43,-0.8 21.45,7.74 22,17.27 0.48,8.53 -3.94,14.94 -9.56,22.43 -5.16,6.83 -6.85,12.46 -6.12,18.83l0.31,3.26ZM427.22,170.31c-0.26,-4.64 2.69,-8.08 7.08,-8.32s7.59,2.84 7.85,7.49c0.24,4.39 -2.45,7.93 -7.09,8.19C430.63,177.92 427.43,174.7 427.18,170.31Z" + android:fillColor="#dbdbdb"/> + <path + android:pathData="M148.48,128.11 L137.2,123l-1.57,3.45a3,3 0,0 1,-2.57 1.72,14.48 14.48,0 0,0 -1.85,0.18 3,3 0,0 1,-2.85 -1.18l-2.21,-3.09 -10.07,7.22 2.21,3.09a3,3 0,0 1,0.2 3.07,18.29 18.29,0 0,0 -0.77,1.69 3,3 0,0 1,-2.45 1.89l-3.77,0.37 1.21,12.33 3.79,-0.38a3,3 0,0 1,2.77 1.38c0.16,0.26 0.33,0.51 0.51,0.76s0.36,0.49 0.55,0.73a2.94,2.94 0,0 1,0.42 3.05l-1.58,3.48 11.29,5.12 1.57,-3.47a3,3 0,0 1,2.58 -1.71,16.19 16.19,0 0,0 1.83,-0.18 3,3 0,0 1,2.85 1.18l2.21,3.09 10.08,-7.22 -2.21,-3.09a2.91,2.91 0,0 1,-0.2 -3.07,17.94 17.94,0 0,0 0.75,-1.68 2.94,2.94 0,0 1,2.45 -1.89l3.79,-0.38 -1.22,-12.33 -3.79,0.37a2.94,2.94 0,0 1,-2.75 -1.37c-0.17,-0.26 -0.34,-0.51 -0.52,-0.76s-0.36,-0.5 -0.55,-0.73a3,3 0,0 1,-0.42 -3.07ZM142.08,139.52a10.15,10.15 0,1 1,-14.16 -2.34A10.15,10.15 0,0 1,142.08 139.52Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M658.38,291.71l-7.52,4.34 1.33,2.3a2,2 0,0 1,-0.07 2.17c-0.23,0.36 -0.45,0.73 -0.65,1.12a2,2 0,0 1,-1.83 1.14L647,302.78v8.69h2.66a2,2 0,0 1,1.83 1.14c0.2,0.39 0.42,0.76 0.65,1.12a2,2 0,0 1,0.07 2.17l-1.33,2.3 7.52,4.34 1.34,-2.31a2.05,2.05 0,0 1,1.91 -1h1.28a2.06,2.06 0,0 1,1.91 1l1.34,2.32 7.51,-4.34 -1.33,-2.31a2.05,2.05 0,0 1,0.08 -2.16c0.23,-0.36 0.45,-0.74 0.65,-1.12a2,2 0,0 1,1.83 -1.14h2.66v-8.69L674.9,302.79a2,2 0,0 1,-1.83 -1.14c-0.2,-0.38 -0.42,-0.76 -0.65,-1.12a2.05,2.05 0,0 1,-0.08 -2.16l1.33,-2.31 -7.51,-4.34L664.82,294a2.05,2.05 0,0 1,-1.91 1l-0.64,0 -0.64,0a2.08,2.08 0,0 1,-1.92 -1ZM662.27,300.01a7.12,7.12 0,1 1,-7.11 7.11A7.11,7.11 0,0 1,662.27 300Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M171.3,91.16l-6.89,5.28L166,98.55a2,2 0,0 1,0.21 2.15,10.47 10.47,0 0,0 -0.5,1.2 2.05,2.05 0,0 1,-1.67 1.37l-2.64,0.34 1.12,8.61 2.64,-0.34a2.06,2.06 0,0 1,2 0.9,11.14 11.14,0 0,0 0.78,1 2,2 0,0 1,0.36 2.13l-1,2.46 8,3.33 1,-2.46a2.05,2.05 0,0 1,1.77 -1.25l0.64,-0.07 0.63,-0.1a2.06,2.06 0,0 1,2 0.75l1.63,2.13 6.89,-5.28 -1.61,-2.11a2.06,2.06 0,0 1,-0.21 -2.16,11.12 11.12,0 0,0 0.5,-1.19 2.05,2.05 0,0 1,1.67 -1.37l2.64,-0.34 -1.12,-8.61 -2.64,0.34a2.06,2.06 0,0 1,-2 -0.89c-0.25,-0.36 -0.51,-0.7 -0.79,-1A2.07,2.07 0,0 1,186 96l1,-2.46 -8,-3.33 -1,2.46a2.07,2.07 0,0 1,-1.77 1.25l-0.64,0.06L175,94a2.06,2.06 0,0 1,-2 -0.75ZM176.23,98.89a7.11,7.11 0,1 1,-6.14 8A7.11,7.11 0,0 1,176.23 98.89Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M119.82,316.78a275.64,275.64 0,0 0,-0.4 -29,370.79 370.79,0 0,0 -9.09,-59.16c-2.54,-10.94 -5.66,-21.7 -8.92,-32.45 -0.1,-0.33 -0.62,-0.24 -0.53,0.1 10.07,37.9 18.33,77 17.76,116.4 -0.16,11 -1.44,21.85 -2.48,32.81 0,0.29 0.45,0.41 0.52,0.11C118.75,336.18 119.43,326.36 119.82,316.78Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M100.88,196.24S85.64,234.94 89.05,244s10.45,11 10.45,11 -9.33,13.32 -2.81,25.81 21,11.9 22,26.06C118.66,306.94 119.46,247.73 100.88,196.24Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M117,282.49a0.28,0.28 0,0 0,0 -0.2,354.31 354.31,0 0,0 -14.78,-77.85c0,-0.07 -0.15,-0.05 -0.13,0q4.53,17 8,34.14a16.87,16.87 0,0 0,-7.28 -4.06s-0.08,0.06 0,0.08a19.35,19.35 0,0 1,7.52 5c0.44,2.25 0.88,4.49 1.29,6.74 -3.41,-3.81 -8.13,-5.7 -12.86,-7.5a0.06,0.06 0,0 0,0 0.11c4.93,2 9.83,4.58 13.17,8.83q1.74,9.63 3.06,19.33a18.43,18.43 0,0 0,-9.09 -5.21c-0.11,0 -0.17,0.13 -0.06,0.16A19.16,19.16 0,0 1,115 268l0.06,0q0.45,3.4 0.86,6.83a23.37,23.37 0,0 0,-6.37 -3.84c-0.06,0 -0.1,0.07 0,0.09a21.89,21.89 0,0 1,6.39 4.23s0.05,0 0.08,0c0.25,2.17 0.5,4.34 0.72,6.51a31,31 0,0 0,-12.93 -9.24,0.08 0.08,0 0,0 0,0.16 33.68,33.68 0,0 1,12.74 9.81,0.3 0.3,0 0,0 0.32,0.1c0.33,3.33 0.63,6.66 0.87,10 0,0.05 0.08,0.05 0.08,0Q117.43,287.62 117,282.49Z" + android:fillColor="#fff"/> + <path + android:pathData="M104.75,230.71a19.09,19.09 0,0 0,-9.16 -2.86,0.06 0.06,0 0,0 0,0.12 36.16,36.16 0,0 1,9.06 3C104.77,231 104.86,230.79 104.75,230.71Z" + android:fillColor="#fff"/> + <path + android:pathData="M106.6,271.68a19.06,19.06 0,0 0,-6.88 -2.35c-0.08,0 -0.09,0.11 0,0.13a26.05,26.05 0,0 1,6.8 2.38C106.61,271.89 106.69,271.73 106.6,271.68Z" + android:fillColor="#fff"/> + <path + android:pathData="M159.9,244.67a103.7,103.7 0,0 0,-17.65 15.42,63.19 63.19,0 0,0 -12.37,21 156.93,156.93 0,0 0,-9.22 50.2,122.32 122.32,0 0,0 2.71,28.23 0.27,0.27 0,0 0,0.53 -0.1,158.6 158.6,0 0,1 0.28,-49.35c2.62,-16 6.73,-33.42 16.91,-46.43 5.54,-7.09 12.45,-12.66 19.28,-18.42C160.73,244.9 160.27,244.41 159.9,244.67Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M122.9,319.75a95,95 0,0 1,12.86 -16.44c7.63,-7.63 14.05,-13.05 15.05,-18.09s-7.64,-8.76 -7.64,-8.76 10.55,1.9 13.44,-2.53 4.28,-30.09 4.28,-30.09 -19.2,13.71 -28.15,32.93S122.9,319.75 122.9,319.75Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M154.25,250.42c-8.08,7.93 -16.21,16.39 -21,26.82A102.83,102.83 0,0 0,129 288.29v0c-0.24,0.76 -0.49,1.52 -0.72,2.28a0.19,0.19 0,0 0,0 0.12,218.27 218.27,0 0,0 -5.46,23.71c0,0.05 0.07,0.07 0.08,0 0.83,-4 1.74,-8 2.76,-12.07a0.27,0.27 0,0 0,0.12 0,17.14 17.14,0 0,1 5,-1.28c0.11,0 0.1,-0.21 0,-0.2a18.78,18.78 0,0 0,-5 0.91c0.93,-3.63 1.94,-7.26 3.08,-10.83a53.32,53.32 0,0 1,11.39 -1.49,0 0,0 0,0 0,-0.06 43,43 0,0 0,-11.2 0.95c0.2,-0.61 0.41,-1.22 0.61,-1.83a59.12,59.12 0,0 1,7.58 -1.29s0,-0.08 0,-0.08a37,37 0,0 0,-7.42 0.9c1,-3.09 2.17,-6.14 3.42,-9.1a55,55 0,0 1,3.63 -7,45.52 45.52,0 0,1 6.15,-1.1s0,-0.1 0,-0.1a16.67,16.67 0,0 0,-5.75 0.57c1,-1.63 2.07,-3.23 3.21,-4.78h0c4.31,-0.95 8.67,-1.84 13.08,-1a0.07,0.07 0,0 0,0 -0.13c-4.19,-1.11 -8.35,-0.47 -12.52,0.35 0.45,-0.6 0.92,-1.2 1.39,-1.79a28.43,28.43 0,0 1,8 -1.27,0 0,0 0,0 0,-0.09 21.09,21.09 0,0 0,-7.5 0.67c3.56,-4.42 7.49,-8.58 11.38,-12.69C154.58,250.34 154.44,250.23 154.25,250.42Z" + android:fillColor="#fff"/> + <path + android:pathData="M154,267.91a16.84,16.84 0,0 0,-3.82 -0.13c-0.15,0 -0.14,0.26 0,0.27 1.26,0 2.53,-0.06 3.79,0A0.08,0.08 0,0 0,154 267.91Z" + android:fillColor="#fff"/> + <path + android:pathData="M140.21,292.8a17.2,17.2 0,0 0,-5.92 1.18s0,0.1 0,0.09c2,-0.47 3.93,-0.66 5.91,-1A0.15,0.15 0,0 0,140.21 292.8Z" + android:fillColor="#fff"/> + <path + android:pathData="M136.07,284.2a13.23,13.23 0,0 0,-2.51 0.22,0.08 0.08,0 0,0 0,0.15 12.39,12.39 0,0 0,2.51 -0.11A0.13,0.13 0,0 0,136.07 284.2Z" + android:fillColor="#fff"/> + <path + android:pathData="M66.61,271.89a87.15,87.15 0,0 1,17.85 8.41,53.33 53.33,0 0,1 14.87,14.12 132.2,132.2 0,0 1,19.06 38.49,102.52 102.52,0 0,1 4.32,23.48 0.23,0.23 0,0 1,-0.45 0,133.21 133.21,0 0,0 -11.62,-39.87c-5.83,-12.35 -13.18,-25.49 -24.42,-33.67 -6.12,-4.45 -13,-7.37 -19.86,-10.45C66,272.28 66.25,271.77 66.61,271.89Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M113.91,324.1A80.28,80.28 0,0 0,99.7 313.77c-7.94,-4.41 -14.39,-7.31 -16.36,-11.16s4.16,-8.85 4.16,-8.85 -8.1,4 -11.46,1.05 -10.42,-23.35 -10.42,-23.35S84.33,278.11 96,291.6 113.91,324.1 113.91,324.1Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M112.93,319.89C103.58,302.33 91.09,286.44 74,276h0a86.26,86.26 0,0 1,12.52 9.8,19.88 19.88,0 0,0 -10.06,2.12 0.06,0.06 0,0 0,0 0.11,27.5 27.5,0 0,1 10.35,-1.75 0.25,0.25 0,0 0,0.12 0c0.61,0.57 1.2,1.16 1.8,1.75a31.46,31.46 0,0 0,-5.38 0.71s0,0.08 0,0.08a27,27 0,0 1,5.67 -0.47,116.91 116.91,0 0,1 8.83,10 8.84,8.84 0,0 0,-3.76 0.27,0.07 0.07,0 1,0 0,0.14 19.92,19.92 0,0 1,4 -0.05c0.51,0.65 1,1.3 1.53,2a35.87,35.87 0,0 0,-11.35 1.1c-0.06,0 0,0.1 0,0.09A45.65,45.65 0,0 1,100 301c0.48,0.63 0.93,1.28 1.4,1.92a24.56,24.56 0,0 0,-6.76 0.78,0.07 0.07,0 0,0 0,0.13 26.09,26.09 0,0 1,7 -0.54c2,2.77 3.94,5.61 5.79,8.47a6.36,6.36 0,0 0,-3 0.18,0 0,0 0,0 0,0.08 13.26,13.26 0,0 1,3.21 0.16q2.5,3.88 4.82,7.85C112.7,320.29 113.06,320.12 112.93,319.89Z" + android:fillColor="#fff"/> + <path + android:pathData="M98.38,305.32a14.35,14.35 0,0 0,-5.44 0.67s0,0.09 0,0.08a40.82,40.82 0,0 1,5.41 -0.56C98.48,305.51 98.51,305.33 98.38,305.32Z" + android:fillColor="#fff"/> + <path + android:pathData="M82.06,283.92a9.19,9.19 0,0 0,-2.51 0.14c-0.09,0 -0.06,0.16 0,0.15 0.83,-0.09 1.64,-0.06 2.46,-0.08A0.11,0.11 0,0 0,82.06 283.92Z" + android:fillColor="#fff"/> + <path + android:pathData="M138.04,382.18l-42.23,0l6.02,-44.11l1.54,-11.31l27.11,0l1.54,11.31l6.02,44.11z" + android:fillColor="#dbdbdb"/> + <path + android:pathData="M132.02,338.07l-30.19,0l1.54,-11.31l27.11,0l1.54,11.31z" + android:fillColor="#c7c7c7"/> + <path + android:pathData="M99.49,322.84h34.86v9.58h-34.86z" + android:fillColor="#dbdbdb"/> + <path + android:pathData="M68.96,382.18l76.01,-0.24l76.01,-0.09l152.02,-0.17l152.02,0.17l76.01,0.09l76.01,0.24l-76.01,0.25l-76.01,0.08l-152.02,0.17l-152.02,-0.17l-76.01,-0.09l-76.01,-0.24z" + android:fillColor="#263238"/> + <path + android:pathData="M88.26,425.29a286.74,31.42 0,1 0,573.48 0a286.74,31.42 0,1 0,-573.48 0z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M308.25,420.09c-2.33,0.79 -69.14,1 -71.7,-0.58 -1,-0.6 -1.57,-10.33 -2,-22.11 -0.09,-2.54 -0.16,-5.17 -0.22,-7.83L229,353.93l44.67,-0.29 4.21,35.65 -0.17,7.84s25.62,11.35 28.24,13.41S310.58,419.3 308.25,420.09Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M308.25,420.09c-2.33,0.79 -69.14,1 -71.7,-0.58 -1.18,-0.74 -1.82,-14.95 -2.18,-29.94l43.46,-0.28 -0.17,7.84s25.62,11.35 28.24,13.41S310.58,419.3 308.25,420.09Z" + android:fillColor="#fff"/> + <path + android:pathData="M308.25,420.09c-2.33,0.79 -69.14,1 -71.7,-0.58 -1,-0.6 -1.57,-10.33 -2,-22.11l43.07,-0.27s25.62,11.35 28.24,13.41S310.58,419.3 308.25,420.09Z" + android:fillColor="#a6a6a6"/> + <path + android:pathData="M307.28,417.42c-11.2,-0.24 -56.4,-0.13 -67.49,0.49 -0.09,0 -0.09,0.06 0,0.07 11.1,0.47 56.3,0 67.49,-0.38C307.52,417.59 307.52,417.42 307.28,417.42Z" + android:fillColor="#263238"/> + <path + android:pathData="M301.59,408.15a9,9 0,0 0,-6.69 2.76,8.66 8.66,0 0,0 -2.48,6c0,0.07 0.12,0.07 0.13,0a10.4,10.4 0,0 1,9 -8.6A0.07,0.07 0,0 0,301.59 408.15Z" + android:fillColor="#263238"/> + <path + android:pathData="M282,398.23c-4.48,-0.05 -9.67,1.55 -12.45,5.23 -0.1,0.14 0.1,0.29 0.23,0.22a62.24,62.24 0,0 1,12.3 -4.9A0.28,0.28 0,0 0,282 398.23Z" + android:fillColor="#263238"/> + <path + android:pathData="M285.48,399.56c-4.49,0 -9.68,1.56 -12.45,5.23 -0.11,0.15 0.09,0.3 0.23,0.23a61.59,61.59 0,0 1,12.29 -4.91A0.28,0.28 0,0 0,285.48 399.56Z" + android:fillColor="#263238"/> + <path + android:pathData="M288.94,400.9c-4.48,0 -9.67,1.55 -12.45,5.23 -0.1,0.14 0.1,0.29 0.23,0.22a62.24,62.24 0,0 1,12.3 -4.9A0.28,0.28 0,0 0,288.94 400.9Z" + android:fillColor="#263238"/> + <path + android:pathData="M292.41,402.24c-4.49,-0.05 -9.68,1.55 -12.45,5.23 -0.11,0.14 0.1,0.29 0.23,0.22a62,62 0,0 1,12.3 -4.9A0.28,0.28 0,0 0,292.41 402.24Z" + android:fillColor="#263238"/> + <path + android:pathData="M242.61,407.26c-5,0 -5,7.85 0,7.82S247.65,407.23 242.61,407.26Z" + android:fillColor="#263238"/> + <path + android:pathData="M286.81,386.25c-2.27,-1.88 -5.13,0 -6.52,1.93a23.58,23.58 0,0 0,-4 11.48c0,0.09 0.07,0.13 0.14,0.13a0.54,0.54 0,0 0,0.81 0.35c3.18,-2.21 6.86,-4.19 9.27,-7.32C287.88,391 289,388 286.81,386.25ZM281.35,395.79c-1.54,1.13 -3.13,2.18 -4.63,3.37 0.8,-2.24 1.49,-4.5 2.51,-6.66a25.05,25.05 0,0 1,1.62 -3c1,-1.49 5.36,-5.25 5.82,-0.38C286.93,391.79 283.18,394.45 281.35,395.79Z" + android:fillColor="#263238"/> + <path + android:pathData="M265.13,401.36c3.9,0.58 7.93,-0.54 11.76,-1.15a0.55,0.55 0,0 0,0.33 -0.82,0.12 0.12,0 0,0 0,-0.19 23.5,23.5 0,0 0,-10.86 -5.47c-2.36,-0.45 -5.7,0.2 -6,3.13C260,399.62 262.85,401 265.13,401.36ZM262.41,398.82c-3,-3.84 2.73,-4.17 4.45,-3.77a25.58,25.58 0,0 1,3.28 1.06,69.56 69.56,0 0,1 6.41,3.05c-1.9,0.19 -3.77,0.53 -5.66,0.79C268.63,400.25 264.09,400.93 262.41,398.82Z" + android:fillColor="#263238"/> + <path + android:pathData="M163.32,189.2s51.87,88.24 53.26,94.44C218.71,293.16 230,387.17 230,387.17l54,-1s-9.3,-82.89 -18.11,-110.2c-6.34,-19.67 -52.12,-84.91 -52.12,-84.91Z" + android:fillColor="#37474f"/> + <path + android:pathData="M279.09,377.93c-7.75,-0.06 -35.22,-0.37 -45.54,0.59 -0.08,0 -0.07,0.14 0,0.15 3.55,0.51 37.78,-0.28 45.53,-0.53A0.11,0.11 0,1 0,279.09 377.93Z" + android:fillColor="#263238"/> + <path + android:pathData="M172.17,197.3c3.4,5.33 7,10.55 10.46,15.84S189.57,223.72 193,229q10.26,16 20,32.21A98.63,98.63 0,0 1,221.1 277a96.75,96.75 0,0 1,4.55 16.94c1.06,5.79 1.76,11.64 2.41,17.49q1,9.33 2.09,18.67 2.13,19.11 4.27,38.22c0.17,1.56 0.34,3.12 0.5,4.69 0,0.23 -0.39,0.27 -0.42,0 -1.59,-12.65 -2.91,-25.35 -4.35,-38q-1.08,-9.47 -2.15,-18.93c-0.67,-5.87 -1.31,-11.75 -2.22,-17.58a115,115 0,0 0,-3.8 -17A81.65,81.65 0,0 0,214.52 265c-6.25,-10.79 -12.87,-21.39 -19.49,-32s-13.42,-21.31 -20.4,-31.79c-0.86,-1.29 -1.73,-2.58 -2.63,-3.85C171.93,197.29 172.11,197.2 172.17,197.3Z" + android:fillColor="#263238"/> + <path + android:pathData="M180.32,425.29c-2.46,-0.15 -66,-25.89 -67.76,-28.33a0.84,0.84 0,0 1,-0.1 -0.47c0,-2.19 4.41,-9.83 8.09,-19.87 0.23,-0.64 1.87,-3.62 4.14,-7.63C131,358 142,339.07 142,339.07l41.53,16.5 -19.88,29.75 -3.09,7.2s19.49,20.15 21.13,23S182.77,425.43 180.32,425.29Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M180.32,425.29c-2.46,-0.15 -66,-25.89 -67.76,-28.33a0.84,0.84 0,0 1,-0.1 -0.47c0,-2.19 4.41,-9.83 8.09,-19.87 0.23,-0.64 1.87,-3.62 4.14,-7.63l39,16.33 -3.09,7.2s19.49,20.15 21.13,23S182.77,425.43 180.32,425.29Z" + android:fillColor="#fff"/> + <path + android:pathData="M180.32,425.29c-2.46,-0.15 -66,-25.89 -67.76,-28.33 -0.68,-0.93 2.16,-9.6 8,-20.34l40,15.91s19.49,20.13 21.14,23S182.77,425.43 180.32,425.29Z" + android:fillColor="#a6a6a6"/> + <path + android:pathData="M180.42,422.45c-10.29,-4.42 -52.23,-21.28 -62.74,-24.86 -0.09,0 -0.11,0 0,0.06 10.11,4.6 52.18,21.12 62.7,25C180.58,422.7 180.64,422.54 180.42,422.45Z" + android:fillColor="#263238"/> + <path + android:pathData="M178.62,411.72a9,9 0,0 0,-7.24 0,8.7 8.7,0 0,0 -4.54,4.62c0,0.06 0.09,0.11 0.12,0.05a10.41,10.41 0,0 1,11.61 -4.59A0.07,0.07 0,0 0,178.62 411.72Z" + android:fillColor="#263238"/> + <path + android:pathData="M164.19,395.18c-4.13,-1.73 -9.55,-2.19 -13.5,0.18 -0.15,0.09 0,0.3 0.13,0.29a62.34,62.34 0,0 1,13.24 0.07A0.28,0.28 0,0 0,164.19 395.18Z" + android:fillColor="#263238"/> + <path + android:pathData="M166.9,397.72c-4.13,-1.73 -9.55,-2.19 -13.5,0.18 -0.15,0.09 0,0.3 0.13,0.29a61.69,61.69 0,0 1,13.24 0.07A0.28,0.28 0,0 0,166.9 397.72Z" + android:fillColor="#263238"/> + <path + android:pathData="M169.62,400.26c-4.14,-1.73 -9.56,-2.19 -13.5,0.18 -0.16,0.09 0,0.3 0.12,0.29a61.69,61.69 0,0 1,13.24 0.07A0.28,0.28 0,0 0,169.62 400.26Z" + android:fillColor="#263238"/> + <path + android:pathData="M172.33,402.8c-4.14,-1.73 -9.55,-2.19 -13.5,0.17 -0.16,0.1 0,0.31 0.12,0.3a61.69,61.69 0,0 1,13.24 0.07A0.28,0.28 0,0 0,172.33 402.8Z" + android:fillColor="#263238"/> + <path + android:pathData="M124.28,388.77c-4.67,-1.86 -7.57,5.41 -2.88,7.27S129,390.63 124.28,388.77Z" + android:fillColor="#263238"/> + <path + android:pathData="M173.14,385.88c-1.41,-2.59 -4.74,-1.95 -6.77,-0.66a23.52,23.52 0,0 0,-8 9.13,0.12 0.12,0 0,0 0.08,0.17c0,0.33 0.22,0.72 0.61,0.64 3.79,-0.87 7.94,-1.32 11.34,-3.32C172.35,390.68 174.47,388.33 173.14,385.88ZM164.49,392.67c-1.85,0.47 -3.71,0.85 -5.54,1.39a69.94,69.94 0,0 1,4.81 -5.23,25.34 25.34,0 0,1 2.65,-2.2c1.45,-1 6.93,-2.85 5.53,1.84C171.17,391.06 166.7,392.11 164.49,392.67Z" + android:fillColor="#263238"/> + <path + android:pathData="M147.37,391.75c3.4,2 7.55,2.47 11.33,3.35 0.39,0.09 0.65,-0.3 0.62,-0.64a0.11,0.11 0,0 0,0.08 -0.17,23.52 23.52,0 0,0 -8,-9.15c-2,-1.3 -5.35,-1.95 -6.77,0.63S145.38,390.58 147.37,391.75ZM145.81,388.37c-1.39,-4.69 4.08,-2.83 5.53,-1.82a24.33,24.33 0,0 1,2.64 2.21,70 70,0 0,1 4.8,5.24c-1.83,-0.54 -3.69,-0.93 -5.54,-1.4C151,392 146.57,391 145.81,388.37Z" + android:fillColor="#263238"/> + <path + android:pathData="M166.88,383.66l-46.49,-18.77s57.64,-84.75 58.06,-91.06c0.38,-5.58 -24.94,-54.2 -25.93,-68.37 -1.08,-15.3 6.28,-27.13 14.38,-34.48l47.95,20.39s-5.06,8.09 -13,12.6c0,0 24.59,56.2 23.19,73.48S166.88,383.66 166.88,383.66Z" + android:fillColor="#37474f"/> + <path + android:pathData="M168.94,374.82c-6.72,-2.89 -4.75,-2.16 -11.51,-5 -3.3,-1.38 -25,-10.41 -28.34,-11.16 -0.07,0 -0.12,0.1 -0.05,0.14 2.89,1.77 24.77,10.42 28.1,11.74 6.81,2.68 4.88,1.84 11.72,4.44A0.1,0.1 0,1 0,168.94 374.82Z" + android:fillColor="#263238"/> + <path + android:pathData="M209.71,202.94a90.5,90.5 0,0 0,-14.6 4.74,0.15 0.15,0 1,0 0.1,0.29c4.9,-1.43 9.88,-2.77 14.7,-4.46C210.28,203.38 210.09,202.86 209.71,202.94Z" + android:fillColor="#263238"/> + <path + android:pathData="M204,201a21.65,21.65 0,0 0,-1.23 2.57,5.91 5.91,0 0,0 -0.63,2.15c0,0.15 0.2,0.18 0.29,0.09a7.51,7.51 0,0 0,1.2 -2c0.41,-0.79 0.83,-1.57 1.22,-2.38C205.12,200.84 204.31,200.46 204,201Z" + android:fillColor="#263238"/> + <path + android:pathData="M204.6,196.46c0.3,-0.74 0.59,-1.47 0.9,-2.21s0.7,-1.5 1,-2.28c0,-0.12 0.24,0 0.19,0.09 -0.3,0.74 -0.49,1.52 -0.72,2.28s-0.49,1.52 -0.74,2.28c-0.47,1.41 -1,2.81 -1.65,4.18a5.3,5.3 0,0 0,2.3 -0.4,4.13 4.13,0 0,0 1.63,-2c0.42,-0.82 0.81,-1.66 1.24,-2.48a16.57,16.57 0,0 0,1.33 -2.79c0,-0.12 0.24,0 0.19,0.09a32.45,32.45 0,0 1,-2.55 5.91c-0.45,0.73 -0.8,1.5 -1.62,1.78a6.78,6.78 0,0 1,-2.73 0.19c-0.12,0 -0.26,0 -0.22,-0.18A47.4,47.4 0,0 1,204.6 196.46Z" + android:fillColor="#263238"/> + <path + android:pathData="M202.56,205.8c1.71,3.61 3.21,7.21 4.8,10.81s3,7.08 4.43,10.66c2.86,7.22 5.42,14.58 7.67,22 1.11,3.68 2.14,7.39 3.06,11.13a80,80 0,0 1,2.22 11.36,30 30,0 0,1 -1,11.4 66.68,66.68 0,0 1,-4.23 10.63c-1.05,2.16 -1.4,1.87 -0.9,0.78 1.43,-3.1 5.18,-12.49 4.91,-20.38A58.82,58.82 0,0 0,221.78 263q-1.31,-5.67 -2.95,-11.25c-2.13,-7.34 -4.66,-14.53 -7.26,-21.71 -1.46,-4 -3,-8 -4.5,-12s-3,-7.68 -4.68,-12.1C202.34,205.76 202.51,205.69 202.56,205.8Z" + android:fillColor="#263238"/> + <path + android:pathData="M167.27,193.87c0.83,-0.31 2,0.2 2.84,0.34a24.28,24.28 0,0 0,3.29 0.33,23.78 23.78,0 0,0 3.27,-0.11 7,7 0,0 0,3.13 -0.83,15.93 15.93,0 0,0 4,-4.23 24.61,24.61 0,0 0,3.11 -5.46c0,-0.12 0.21,0 0.17,0.08 -0.35,1.11 -0.61,2.23 -1,3.32a20.15,20.15 0,0 1,-1.54 2.95,12.61 12.61,0 0,1 -4.14,4.7c-1.93,1.1 -4.41,1 -6.56,0.91a25.63,25.63 0,0 1,-3.71 -0.49c-0.88,-0.19 -2.36,-0.33 -2.92,-1.1A0.27,0.27 0,0 1,167.27 193.87Z" + android:fillColor="#263238"/> + <path + android:pathData="M133.66,356q11.46,-17.36 22.5,-35t21.78,-35.55c1.71,-2.85 3.68,-5.69 4.78,-8.85 1.2,-3.43 0.52,-6.76 -0.56,-10.12a171.63,171.63 0,0 0,-7.14 -18c-2.68,-5.91 -5.57,-11.72 -8.41,-17.55s-5.81,-11.59 -8,-17.67c-2,-5.81 -2.81,-11.83 -1.25,-17.85s4.92,-11.34 8.43,-16.35c0.92,-1.32 1.87,-2.63 2.8,-4 0.07,-0.1 0.22,0 0.15,0.12 -3.87,5.22 -7.64,10.75 -9.91,16.88a29.15,29.15 0,0 0,-1.92 9.45,30.59 30.59,0 0,0 1.51,9.67c1.88,6.08 4.85,11.83 7.62,17.55s5.73,11.64 8.46,17.53A187.64,187.64 0,0 1,182 264.45c0.93,2.75 2,5.63 1.92,8.58 -0.07,3.23 -1.61,6.14 -3.21,8.86 -7,11.85 -14.17,23.56 -21.47,35.2s-14.81,23.28 -22.41,34.8l-2.88,4.35C133.8,356.42 133.54,356.21 133.66,356Z" + android:fillColor="#263238"/> + <path + android:pathData="M217.51,137.47c4.33,9.5 26.2,22.59 36.44,24 7.36,1 29.74,1.36 37.41,0.19 9,-1.38 2.12,-25.63 -3.19,-25 -14.6,1.7 -27,3.6 -30.9,3.6 -4.76,0 -30.51,-8.26 -33.61,-9.43C216.06,128 215.06,132.08 217.51,137.47Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M217.65,140c5.48,8.11 23.69,21.37 23.69,21.37l2.53,-5.6 8.37,-18.52S235.51,132 224.5,129.6a24.12,24.12 0,0 0,-3.94 -0.56C213.53,128.66 212.92,133 217.65,140Z" + android:fillColor="#8AB0FF"/> + <path + android:pathData="M217.65,140c5.48,8.11 23.69,21.37 23.69,21.37l2.53,-5.6c-6.79,-7.89 -17.28,-19.84 -23.31,-26.71C213.53,128.66 212.92,133 217.65,140Z" + android:fillColor="#263238"/> + <path + android:pathData="M238.06,157.61c1.39,-3.41 7.57,-17.14 9.11,-20 0.1,-0.2 0.26,-0.18 0.17,0a201.71,201.71 0,0 1,-9.14 20C238.16,157.73 238,157.69 238.06,157.61Z" + android:fillColor="#263238"/> + <path + android:pathData="M285.49,136.91c8.88,-1.16 19.87,-3.15 29.18,0.8a5,5 0,0 1,2.49 2.13c4.2,1.7 4.66,4.19 4.66,4.19 3.43,2.78 3.55,5.4 3.55,5.4s4.92,2 4.17,5.22c-0.82,3.56 -7.56,0 -12.46,0.29 -11.25,0.7 -27,4.83 -30.25,5.35Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M304.78,147.39a72.4,72.4 0,0 1,9.88 0,71.88 71.88,0 0,1 10.6,2.15 0.09,0.09 0,0 0,0.06 -0.17,38.29 38.29,0 0,0 -20.54,-2.08C304.62,147.27 304.62,147.4 304.78,147.39Z" + android:fillColor="#263238"/> + <path + android:pathData="M303.38,140.67c3.23,0 8.91,0.16 18.41,3.47a0,0 0,0 0,0 -0.06,34.41 34.41,0 0,0 -18.43,-3.57C303.18,140.53 303.16,140.66 303.38,140.67Z" + android:fillColor="#263238"/> + <path + android:pathData="M302.69,137c5.49,0.28 8.92,1.16 14.44,2.82a0,0 0,0 0,0 -0.06c-6.08,-2.54 -8.57,-2.78 -14.47,-3C302.47,136.84 302.48,137 302.69,137Z" + android:fillColor="#263238"/> + <path + android:pathData="M303.58,156.64c-1.43,0.67 -1.08,1.42 1.65,2.05s14.08,0.82 13.68,4.78 -16.41,3.46 -20.88,2.06 -11.2,-5.24 -11.2,-5.24C290,159.76 297.44,157.75 303.58,156.64Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M229.4,152.61c-0.07,1.71 -0.23,3.45 -0.47,5.18 0,-0.07 0,-0.13 0.07,-0.19 0.33,-0.9 0.66,-1.82 1.06,-2.69 0,0 0.1,0 0.09,0a14.42,14.42 0,0 1,-0.86 2.78c-0.18,0.43 -0.35,0.85 -0.54,1.27 -0.12,0.77 -0.26,1.53 -0.41,2.29 -0.3,1.43 -1.65,7.51 -2,8.54 -0.06,0.21 -0.32,0.16 -0.3,-0.08 0.07,-1.12 1.2,-7.45 1.43,-8.89a77.71,77.71 0,0 1,1.79 -8.25C229.31,152.52 229.41,152.56 229.4,152.61Z" + android:fillColor="#263238"/> + <path + android:pathData="M219,198.08c-2.67,1.37 -6.11,3.5 -21.61,0.45 -1,-0.2 -1.94,-0.44 -2.92,-0.73 -14.53,-4.36 -32,-21.45 -32.95,-22.66 0,0 23.09,-37.43 52.62,-49.2 3.65,-1.45 9.69,1.35 13,4.84 1.19,1.25 3.78,10.44 2.79,17.88S221.66,196.71 219,198.08Z" + android:fillColor="#8AB0FF"/> + <path + android:pathData="M216.92,148.32a11.34,11.34 0,0 1,-0.65 4.66,10.85 10.85,0 0,1 0.65,-4.66Z" + android:fillColor="#fff"/> + <path + android:pathData="M206.85,173.81a10.33,10.33 0,0 1,-0.08 2.36,9.8 9.8,0 0,1 -0.57,2.3 9.85,9.85 0,0 1,0.08 -2.37A10.37,10.37 0,0 1,206.85 173.81Z" + android:fillColor="#fff"/> + <path + android:pathData="M189.74,154.54a11.35,11.35 0,0 1,-0.65 4.67,10.93 10.93,0 0,1 0.65,-4.67Z" + android:fillColor="#fff"/> + <path + android:pathData="M223.51,172.51a10.39,10.39 0,0 1,-0.08 2.37,9.8 9.8,0 0,1 -0.57,2.3 9.85,9.85 0,0 1,0.08 -2.37A10.32,10.32 0,0 1,223.51 172.51Z" + android:fillColor="#fff"/> + <path + android:pathData="M201.54,151.24a10.33,10.33 0,0 1,2.36 0.07,9.83 9.83,0 0,1 2.3,0.58 11.27,11.27 0,0 1,-4.66 -0.65Z" + android:fillColor="#fff"/> + <path + android:pathData="M182.12,169.65a11.34,11.34 0,0 1,4.66 0.65,10.85 10.85,0 0,1 -4.66,-0.65Z" + android:fillColor="#fff"/> + <path + android:pathData="M205,189.58a11.27,11.27 0,0 1,4.66 0.65,10.91 10.91,0 0,1 -4.66,-0.65Z" + android:fillColor="#fff"/> + <path + android:pathData="M176.13,182.34a11.34,11.34 0,0 1,4.66 0.65,10.91 10.91,0 0,1 -4.66,-0.65Z" + android:fillColor="#fff"/> + <path + android:pathData="M216.77,130.4a11.34,11.34 0,0 1,4.66 0.65,11.34 11.34,0 0,1 -4.66,-0.65Z" + android:fillColor="#fff"/> + <path + android:pathData="M211.12,136.78a9.75,9.75 0,0 1,-1.72 1.62,10.62 10.62,0 0,1 -2,1.22A10.17,10.17 0,0 1,209.1 138,10.54 10.54,0 0,1 211.12,136.78Z" + android:fillColor="#fff"/> + <path + android:pathData="M180.33,154.91a10.11,10.11 0,0 1,-1.73 1.61,9.43 9.43,0 0,1 -2,1.22 10.53,10.53 0,0 1,1.73 -1.61A9.68,9.68 0,0 1,180.33 154.91Z" + android:fillColor="#fff"/> + <path + android:pathData="M218.78,163.09a10.17,10.17 0,0 1,-1.73 1.62,9.68 9.68,0 0,1 -2,1.22 10.17,10.17 0,0 1,1.73 -1.62A10.32,10.32 0,0 1,218.78 163.09Z" + android:fillColor="#fff"/> + <path + android:pathData="M193.88,178.77a10.17,10.17 0,0 1,-1.73 1.62,9.86 9.86,0 0,1 -2,1.22 10.17,10.17 0,0 1,1.73 -1.62A10.32,10.32 0,0 1,193.88 178.77Z" + android:fillColor="#fff"/> + <path + android:pathData="M228.32,141.67a10.17,10.17 0,0 1,-1.73 1.62,10.62 10.62,0 0,1 -2,1.22 10.17,10.17 0,0 1,1.73 -1.62A9.86,9.86 0,0 1,228.32 141.67Z" + android:fillColor="#fff"/> + <path + android:pathData="M227.8,159.84a10.17,10.17 0,0 1,-1.62 -1.73,9.61 9.61,0 0,1 -1.22,-2 9.75,9.75 0,0 1,1.62 1.72A10.93,10.93 0,0 1,227.8 159.84Z" + android:fillColor="#fff"/> + <path + android:pathData="M172.3,172.36a10.17,10.17 0,0 1,-1.62 -1.73,10.32 10.32,0 0,1 -1.22,-2 10.17,10.17 0,0 1,1.62 1.73A9.86,9.86 0,0 1,172.3 172.36Z" + android:fillColor="#fff"/> + <path + android:pathData="M221.05,187.25a9.75,9.75 0,0 1,-1.62 -1.72,10.62 10.62,0 0,1 -1.22,-2 10.17,10.17 0,0 1,1.62 1.73A10.05,10.05 0,0 1,221.05 187.25Z" + android:fillColor="#fff"/> + <path + android:pathData="M196.62,144.8a10.11,10.11 0,0 1,-1.62 -1.72,10.93 10.93,0 0,1 -1.22,-2 9.75,9.75 0,0 1,1.62 1.72A10.93,10.93 0,0 1,196.62 144.8Z" + android:fillColor="#fff"/> + <path + android:pathData="M197.05,195.73a10.17,10.17 0,0 1,-1.62 -1.73,10.54 10.54,0 0,1 -1.22,-2 9.75,9.75 0,0 1,1.62 1.72A10.42,10.42 0,0 1,197.05 195.73Z" + android:fillColor="#fff"/> + <path + android:pathData="M201.2,165.69a10.53,10.53 0,0 1,-1.61 -1.73,9.43 9.43,0 0,1 -1.22,-2 10.11,10.11 0,0 1,1.61 1.73A9.68,9.68 0,0 1,201.2 165.69Z" + android:fillColor="#fff"/> + <path + android:pathData="M221.73,140.75c-3.77,-0.7 -7.31,-8.49 -7.76,-13.73 0,-0.36 1.76,-3.21 3.77,-6.78 1.22,-2.17 2.51,-4.62 3.54,-6.94 0.21,-0.47 1.44,1.12 1.44,1.12l2.68,2 8.85,6.79a40.34,40.34 0,0 0,-5.33 8.27,5 5,0 0,0 -0.32,1 1.22,1.22 0,0 0,0 0.17C228.05,134.63 225.36,141.42 221.73,140.75Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M228.6,132.53a1.22,1.22 0,0 0,0 0.17,9.91 9.91,0 0,1 -1.53,-0.59c-9.69,-4.54 -5.42,-17.52 -5.42,-17.52l3.8,1.88 8.85,6.79a40.34,40.34 0,0 0,-5.33 8.27A5,5 0,0 0,228.6 132.53Z" + android:fillColor="#263238"/> + <path + android:pathData="M244.42,95.58s4.43,2.81 4.45,7.81 -2,9.89 -2.42,10.07S244.42,95.58 244.42,95.58Z" + android:fillColor="#263238"/> + <path + android:pathData="M222.44,98.18c-2.66,5.25 -2.52,21.8 0.8,26.06 4.82,6.18 14.1,8.31 19.71,2.2 5.43,-5.92 4.87,-27.48 1,-31.5C238.32,89 226.38,90.41 222.44,98.18Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M222.87,124h0" + android:strokeLineJoin="round" + android:strokeWidth="0" + android:fillColor="#00000000" + android:strokeColor="#f5a79e" + android:strokeLineCap="round"/> + <path + android:pathData="M236.56,111.43s-0.09,0.06 -0.08,0.1c0.06,1.13 -0.06,2.43 -1.07,2.83 0,0 0,0.07 0,0.06C236.66,114.22 236.8,112.49 236.56,111.43Z" + android:fillColor="#263238"/> + <path + android:pathData="M235.53,110.28c-1.82,-0.1 -1.88,3.54 -0.19,3.63S237.05,110.36 235.53,110.28Z" + android:fillColor="#263238"/> + <path + android:pathData="M242.73,111.39s0.09,0 0.09,0.1c-0.06,1.13 0.07,2.43 1.09,2.82 0,0 0,0.07 0,0.06C242.65,114.18 242.5,112.45 242.73,111.39Z" + android:fillColor="#263238"/> + <path + android:pathData="M243.76,110.23c1.81,-0.11 1.9,3.53 0.22,3.63S242.24,110.32 243.76,110.23Z" + android:fillColor="#263238"/> + <path + android:pathData="M234.39,107.51a14.64,14.64 0,0 0,1.41 -0.48,2.4 2.4,0 0,0 1.36,-0.76 0.77,0.77 0,0 0,-0.11 -0.93,1.91 1.91,0 0,0 -1.92,-0.23 2.83,2.83 0,0 0,-1.64 1.19A0.83,0.83 0,0 0,234.39 107.51Z" + android:fillColor="#263238"/> + <path + android:pathData="M245,109.12a14.65,14.65 0,0 1,-1.44 -0.4,2.4 2.4,0 0,1 -1.39,-0.69 0.75,0.75 0,0 1,0.06 -0.93,1.89 1.89,0 0,1 1.9,-0.33 2.8,2.8 0,0 1,1.7 1.1A0.82,0.82 0,0 1,245 109.12Z" + android:fillColor="#263238"/> + <path + android:pathData="M234,122.12c0.27,0.27 0.53,0.63 0.94,0.67a3,3 0,0 0,1.22 -0.26s0.07,0 0,0.06a1.51,1.51 0,0 1,-1.44 0.59,1.21 1.21,0 0,1 -0.88,-1A0.06,0.06 0,0 1,234 122.12Z" + android:fillColor="#263238"/> + <path + android:pathData="M240.54,117.3s0.05,1.68 0,2.47a16.48,16.48 0,0 0,-4.61 0.16c-0.36,0.08 -0.32,-0.21 0.09,-0.4a6.76,6.76 0,0 1,3.92 -0.52c0.08,-0.21 -0.13,-2.6 0,-2.59a6.68,6.68 0,0 1,1.74 0.6c0,-3.52 -0.56,-7 -0.51,-10.52 0,-0.12 0.19,-0.14 0.21,0a56.64,56.64 0,0 1,1 11.3C242.39,118.23 240.84,117.46 240.54,117.3Z" + android:fillColor="#263238"/> + <path + android:pathData="M238.29,119.17a5,5 0,0 1,-2.1 2.51c-1.51,0.61 -2,-0.76 -0.48,-2A4.88,4.88 0,0 1,238.29 119.17Z" + android:fillColor="#263238"/> + <path + android:pathData="M236.72,121.37a2,2 0,0 1,-0.53 0.31c-1.39,0.56 -1.94,-0.55 -0.82,-1.67C236.13,120.07 237,120.35 236.72,121.37Z" + android:fillColor="#ff99ba"/> + <path + android:pathData="M221.68,112.33c1.83,0.56 3.93,-4.94 4.53,-7 0.52,-1.86 1.12,-7.77 1.21,-8.18s8,5.23 12.58,3.89 7.69,-5.49 7.76,-7.42 -5.66,-6.83 -10.61,-7.08 -11.66,6 -11.66,6a23,23 0,0 0,2.2 -2.94c-0.08,-0.22 -3.28,1.06 -3.87,3.34 0,0 0.64,-2.87 0.4,-2.92s-2.73,2.4 -2.17,4.26c0,0 -2.88,2.49 -3.14,5.22S219.53,111.67 221.68,112.33Z" + android:fillColor="#263238"/> + <path + android:pathData="M243.28,100a15.21,15.21 0,0 1,-4.35 1.56,10.33 10.33,0 0,1 -5,-0.8 15.36,15.36 0,0 1,-4.36 -2.58c-1.15,-0.94 -2.18,-2.09 -3.41,-2.93 -0.31,-0.22 -0.66,0.23 -0.47,0.51a16.52,16.52 0,0 0,8.36 6.16,9.53 9.53,0 0,0 9.22,-1.88S243.3,100 243.28,100Z" + android:fillColor="#263238"/> + <path + android:pathData="M223.59,111.84s-2.84,-5.76 -5.4,-4.83 -1,8.9 1.63,10.36a2.85,2.85 0,0 0,4 -0.94Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M218.7,109.28s-0.06,0 0,0.08c1.82,1.08 2.56,3 3,5a1.57,1.57 0,0 0,-2.26 -0.78c-0.06,0 0,0.11 0,0.11a1.75,1.75 0,0 1,1.81 0.9,8.45 8.45,0 0,1 0.68,1.68c0.06,0.19 0.39,0.14 0.36,-0.07v0C222.72,113.71 221.32,109.94 218.7,109.28Z" + android:fillColor="#263238"/> + <path + android:pathData="M204.84,137.56c-2,11.33 10.28,49.5 18.15,56.63 11.71,10.6 33.36,17.57 41.21,19.84 3.42,1 12.88,-23.07 9.42,-24.66C266.21,186 243.19,178.8 241,177s-15.39,-20.87 -21.27,-31.85C211.86,130.37 205.83,131.83 204.84,137.56Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M267.79,187.25s10.22,2.61 16.81,4.62c3.68,1.13 9.82,3.62 12.15,5.68 3.48,3.09 16.06,18.21 12.46,21.34 -3.26,2.84 -12.42,-11.53 -12.42,-11.53s10.52,13.68 6,16.37S290,208.81 290,208.81s10.49,14.3 5.36,16.33c-3.88,1.53 -12.2,-14 -12.2,-14s8.94,12.35 5,14.1c-4.34,1.94 -12.91,-11.92 -12.91,-11.92 -10.72,2.77 -17,-0.3 -21.13,-3C253.15,209.66 267.79,187.25 267.79,187.25Z" + android:fillColor="#eb9481"/> + <path + android:pathData="M293.45,202.39c1.3,1.56 2.62,3.14 3.77,4.81s2.24,3.39 3.23,5.16a34.62,34.62 0,0 1,3.2 7.26c-1.72,-4.4 -5.75,-10.45 -6.9,-12.12s-2.22,-3.4 -3.36,-5.07C293.36,202.39 293.42,202.35 293.45,202.39Z" + android:fillColor="#263238"/> + <path + android:pathData="M287.34,206.44c2.22,1.76 6.87,8.3 8.66,12.69 0.08,0.18 0,0.17 -0.13,0 -1.4,-2.17 -7.08,-10.57 -8.58,-12.66C287.26,206.44 287.31,206.41 287.34,206.44Z" + android:fillColor="#263238"/> + <path + android:pathData="M281.47,209a31.33,31.33 0,0 1,6.42 10c0.07,0.18 -0.07,0.15 -0.18,0 -2.07,-3.37 -3.67,-6 -6.35,-9.91C281.32,209 281.41,208.91 281.47,209Z" + android:fillColor="#263238"/> + <path + android:pathData="M216,138.39c-9.13,-12.91 -14.59,-8.13 -12.76,5.89 1.72,13.11 6.31,28.73 6.31,28.73l23,-11.16S221.81,146.66 216,138.39Z" + android:fillColor="#8AB0FF"/> + <path + android:pathData="M221.55,143.47a10.28,10.28 0,0 1,0.65 2.27,10.39 10.39,0 0,1 0.15,2.37 10.34,10.34 0,0 1,-0.64 -2.28A9.77,9.77 0,0 1,221.55 143.47Z" + android:fillColor="#fff"/> + <path + android:pathData="M207.92,151.32a11,11 0,0 1,4.63 -0.8,10.26 10.26,0 0,1 -2.27,0.64A9.8,9.8 0,0 1,207.92 151.32Z" + android:fillColor="#fff"/> + <path + android:pathData="M208.51,131.24a11.16,11.16 0,0 1,-2.71 3.85,11.16 11.16,0 0,1 2.71,-3.85Z" + android:fillColor="#fff"/> + <path + android:pathData="M228,157.35a10.44,10.44 0,0 1,-1.15 2.07,10.11 10.11,0 0,1 -1.56,1.78 11.16,11.16 0,0 1,2.71 -3.85Z" + android:fillColor="#fff"/> + <path + android:pathData="M212,165.18a10,10 0,0 1,-2.07 -1.15,10.06 10.06,0 0,1 -1.78,-1.56 11.16,11.16 0,0 1,3.85 2.71Z" + android:fillColor="#fff"/> + <path + android:pathData="M219,142.28c1.23,1.69 2.5,3.34 3.76,5q-0.48,-1.26 -0.84,-2.55a0,0 0,1 1,0.06 0c0.25,0.66 0.54,1.31 0.78,2l0.36,1a1.8,1.8 0,0 1,0.08 0.21c1,1.29 2,2.58 2.92,3.9 1.13,1.58 2.22,3.18 3.32,4.78s2.21,3.59 3.4,5.2c0.11,0.14 -2,1 -2.23,1.11s-0.35,-0.08 -0.13,-0.15 1.9,-1.1 1.92,-1.12c-1.1,-1.62 -2.37,-3.11 -3.52,-4.68s-2.29,-3.14 -3.4,-4.73c-2.25,-3.24 -4.31,-6.6 -6.55,-9.85A0,0 0,0 1,219 142.28Z" + android:fillColor="#263238"/> + <path + android:pathData="M203.78,153.56c0.35,0.68 0.73,1.35 1,2.05l0.38,0.87c-0.53,-2.49 -1,-5 -1.55,-7.49 0,0 0,0 0,0 1.06,4 2.13,8.09 3.11,12.15 0.93,3.88 2.06,7.8 2.6,11.76a13.05,13.05 0,0 1,2.16 -0.73,10.66 10.66,0 0,1 -2.38,1.15 124.82,124.82 0,0 1,-3 -12.24c-0.25,-1.12 -0.48,-2.24 -0.72,-3.36 -0.26,-0.68 -0.57,-1.33 -0.88,-2s-0.59,-1.42 -0.87,-2.13C203.69,153.55 203.76,153.51 203.78,153.56Z" + android:fillColor="#263238"/> + <path + android:pathData="M209.89,169.15c3.2,-1.8 16.57,-8.72 19.56,-10 0.21,-0.09 0.32,0 0.11,0.14a201.57,201.57 0,0 1,-19.6 10C209.88,169.31 209.8,169.2 209.89,169.15Z" + android:fillColor="#263238"/> + <path + android:pathData="M576.32,432.05l-304.68,0l44.05,-249.85l304.68,0l-44.05,249.85z" + android:fillColor="#8AB0FF"/> + <path + android:pathData="M419.97,156.32l-99.71,0l-4.57,25.88l106.71,0l-2.43,-25.88z" + android:fillColor="#8AB0FF"/> + <path + android:fillColor="#FF000000" + android:pathData="M576.32,432.05l-304.68,0l44.05,-249.85l304.68,0l-44.05,249.85z" + android:strokeAlpha="0.1" + android:fillAlpha="0.1"/> + <path + android:fillColor="#FF000000" + android:pathData="M419.97,156.32l-99.71,0l-4.57,25.88l106.71,0l-2.43,-25.88z" + android:strokeAlpha="0.1" + android:fillAlpha="0.1"/> + <path + android:pathData="M309.5,166.88a19.17,19.17 0,0 1,0 -8.7,19.17 19.17,0 0,1 0,8.7Z" + android:fillColor="#263238"/> + <path + android:pathData="M300.64,169.44a17,17 0,0 1,-2.61 -3.52,17.35 17.35,0 0,1 -1.75,-4 16.58,16.58 0,0 1,2.61 3.51A17.61,17.61 0,0 1,300.64 169.44Z" + android:fillColor="#263238"/> + <path + android:pathData="M294.24,176.09a19.18,19.18 0,0 1,-7.53 -4.35,17.16 17.16,0 0,1 4,1.74A17.58,17.58 0,0 1,294.24 176.09Z" + android:fillColor="#263238"/> + <path + android:pathData="M292,185.05a19.17,19.17 0,0 1,-8.7 0,19.17 19.17,0 0,1 8.7,0Z" + android:fillColor="#263238"/> + <path + android:pathData="M294.6,193.91a17.64,17.64 0,0 1,-3.52 2.61,17.16 17.16,0 0,1 -4,1.74 17,17 0,0 1,3.52 -2.61A16.8,16.8 0,0 1,294.6 193.91Z" + android:fillColor="#263238"/> + <path + android:pathData="M301.24,200.3a19.13,19.13 0,0 1,-4.35 7.54,16.83 16.83,0 0,1 1.75,-4A17.31,17.31 0,0 1,301.24 200.3Z" + android:fillColor="#263238"/> + <path + android:pathData="M310.2,202.51a17.45,17.45 0,0 1,0.5 4.35,17 17,0 0,1 -0.5,4.35 16.57,16.57 0,0 1,-0.5 -4.35A17.45,17.45 0,0 1,310.2 202.51Z" + android:fillColor="#263238"/> + <path + android:pathData="M319.06,200a17,17 0,0 1,2.61 3.52,16.8 16.8,0 0,1 1.74,4 19.13,19.13 0,0 1,-4.35 -7.54Z" + android:fillColor="#263238"/> + <path + android:pathData="M325.45,193.3a16.8,16.8 0,0 1,4 1.74,17 17,0 0,1 3.52,2.61 16.8,16.8 0,0 1,-4 -1.74A17,17 0,0 1,325.45 193.3Z" + android:fillColor="#263238"/> + <path + android:pathData="M327.66,184.34a19.22,19.22 0,0 1,8.71 0,19.22 19.22,0 0,1 -8.71,0Z" + android:fillColor="#263238"/> + <path + android:pathData="M325.1,175.48a17.31,17.31 0,0 1,3.52 -2.6,16.44 16.44,0 0,1 4,-1.75 19.13,19.13 0,0 1,-7.54 4.35Z" + android:fillColor="#263238"/> + <path + android:pathData="M318.45,169.09a17.58,17.58 0,0 1,1.74 -4,17 17,0 0,1 2.61,-3.52 16.8,16.8 0,0 1,-1.74 4A17,17 0,0 1,318.45 169.09Z" + android:fillColor="#263238"/> + <path + android:pathData="M575.87,432.05l-305.33,0l-43.36,-240.78l305.34,0l43.35,240.78z" + android:fillColor="#8AB0FF"/> + <path + android:pathData="M332.99,325.77m-12.69,0a12.69,12.69 0,1 1,25.38 0a12.69,12.69 0,1 1,-25.38 0" + android:fillColor="#263238"/> + <path + android:pathData="M433.31,325.77m-12.69,0a12.69,12.69 0,1 1,25.38 0a12.69,12.69 0,1 1,-25.38 0" + android:fillColor="#263238"/> + <path + android:pathData="M401.38,340.49l-0.7,-1.33c-0.06,-0.12 -6.62,-12.24 -19.81,-12.24 -12,0 -15,11.41 -15.08,11.9l-0.36,1.45 -2.91,-0.7 0.35,-1.46c0,-0.14 3.58,-14.19 18,-14.19 15,0 22.17,13.28 22.47,13.85l0.7,1.32Z" + android:fillColor="#263238"/> + <path + android:pathData="M555.71,324.8l-0.21,-1c0.65,-0.14 1.29,-0.29 1.93,-0.46l0.25,1C557,324.51 556.37,324.66 555.71,324.8Z" + android:fillColor="#263238"/> + <path + android:pathData="M561.55,323.19l-0.32,-0.94c1.25,-0.43 2.5,-0.9 3.71,-1.41l0.39,0.92C564.1,322.28 562.83,322.76 561.55,323.19ZM569,320l-0.45,-0.88c1.17,-0.61 2.34,-1.27 3.45,-2l0.52,0.85C571.38,318.76 570.19,319.43 569,320ZM575.88,315.77 L575.29,314.96c1.08,-0.79 2.12,-1.62 3.1,-2.47l0.66,0.75C578,314.15 577,315 575.87,315.81ZM581.98,310.45 L581.25,309.76c0.92,-1 1.79,-2 2.59,-3l0.79,0.61C583.8,308.47 582.91,309.5 582,310.49ZM586.93,304.05 L586.08,303.52a29.08,29.08 0,0 0,1.84 -3.48l0.92,0.41A33.74,33.74 0,0 1,586.92 304.09ZM590.24,296.63 L589.24,296.35a26.14,26.14 0,0 0,0.81 -3.83l1,0.13A25.66,25.66 0,0 1,590.23 296.67ZM591.35,288.63h-1v-0.29c0,-1.21 -0.07,-2.44 -0.19,-3.65l1,-0.1a36.24,36.24 0,0 1,0.2 3.75ZM589.55,280.8a39.3,39.3 0,0 0,-1 -3.82l1,-0.3c0.41,1.3 0.76,2.62 1,3.91ZM587.18,273.27c-0.48,-1.18 -1,-2.39 -1.64,-3.61l0.9,-0.45c0.61,1.24 1.17,2.48 1.66,3.68ZM583.68,266.14c-0.62,-1.09 -1.3,-2.24 -2,-3.42l0.85,-0.53c0.73,1.19 1.42,2.35 2,3.46ZM579.5,259.35c-0.73,-1.1 -1.47,-2.21 -2.23,-3.32l0.83,-0.56c0.76,1.11 1.5,2.22 2.23,3.34ZM575,252.73c-0.75,-1.1 -1.51,-2.21 -2.25,-3.31l0.83,-0.56c0.74,1.1 1.49,2.21 2.24,3.3ZM570.53,246.07c-0.73,-1.12 -1.44,-2.26 -2.14,-3.4l0.85,-0.52c0.7,1.14 1.41,2.26 2.13,3.38ZM566.36,239.2c-0.68,-1.21 -1.31,-2.41 -1.88,-3.56l0.9,-0.45c0.56,1.14 1.19,2.32 1.85,3.52ZM562.81,232c-0.53,-1.25 -1,-2.52 -1.44,-3.76l1,-0.32c0.42,1.21 0.89,2.46 1.41,3.69ZM560.21,224.37c-0.33,-1.3 -0.62,-2.63 -0.84,-4l1,-0.16c0.22,1.28 0.49,2.58 0.82,3.86ZM558.87,216.37c-0.1,-1.23 -0.15,-2.47 -0.15,-3.71v-0.33h1v0.32c0,1.21 0,2.43 0.15,3.63ZM559.87,208.37 L558.87,208.27c0,-0.27 0.05,-0.55 0.08,-0.84 0.12,-1.07 0.27,-2.14 0.45,-3.16l1,0.17c-0.17,1 -0.32,2.05 -0.44,3.1C560,207.85 560,208.12 559.92,208.4ZM561.26,200.59 L560.26,200.32c0.37,-1.32 0.8,-2.61 1.28,-3.84l0.93,0.36A36.6,36.6 0,0 0,561.31 200.62ZM611.09,194.76c-0.56,0 -1.14,-0.08 -1.71,-0.16 -0.78,-0.11 -1.56,-0.24 -2.33,-0.39l0.2,-1c0.74,0.14 1.51,0.27 2.27,0.38 0.54,0.07 1.09,0.12 1.62,0.15ZM615.2,194.45 L614.99,193.45a11.54,11.54 0,0 0,3.56 -1.38l0.52,0.85A12.45,12.45 0,0 1,615.25 194.48ZM564.14,193.26 L563.25,192.79a35.46,35.46 0,0 1,2.11 -3.46l0.82,0.57A32.66,32.66 0,0 0,564.19 193.29ZM603.14,193.2a38.51,38.51 0,0 1,-3.8 -1.43l0.41,-0.92a34.09,34.09 0,0 0,3.69 1.39ZM622.14,190.08 L621.31,189.52a7,7 0,0 0,1.22 -3.49l1,0.07A8,8 0,0 1,622.17 190.11ZM595.74,189.93a36.69,36.69 0,0 1,-3.39 -2.23l0.59,-0.8a35.28,35.28 0,0 0,3.3 2.16ZM568.64,186.81 L567.9,186.14a33.81,33.81 0,0 1,2.89 -2.85l0.66,0.75A33.41,33.41 0,0 0,568.67 186.84ZM589.23,185.12a37,37 0,0 1,-2.83 -2.91l0.75,-0.66a36.84,36.84 0,0 0,2.75 2.83ZM621.78,182.41a9.77,9.77 0,0 0,-2.33 -3l0.66,-0.75a10.8,10.8 0,0 1,2.57 3.29ZM574.56,181.62 L573.99,180.8a38.58,38.58 0,0 1,3.47 -2.11l0.47,0.88A37.77,37.77 0,0 0,574.59 181.65ZM583.9,179.02c-0.38,-0.54 -0.75,-1.09 -1.1,-1.66l-1.3,0.51 -0.38,-0.92 1.15,-0.46c-0.18,-0.3 -0.36,-0.6 -0.53,-0.9l0.87,-0.49c0.2,0.35 0.4,0.7 0.61,1q0.84,-0.3 1.71,-0.57l0.29,1c-0.49,0.15 -1,0.31 -1.46,0.48 0.31,0.49 0.63,1 1,1.43ZM616.23,177.3a21.3,21.3 0,0 0,-3 -1.22l-0.66,-0.21 0.29,-1 0.68,0.22a21.6,21.6 0,0 1,3.12 1.27ZM589.05,175.51 L588.84,174.51c1.29,-0.29 2.63,-0.53 4,-0.72l0.15,1C591.67,175 590.36,175.25 589.08,175.54ZM608.75,174.97c-1.25,-0.22 -2.57,-0.39 -3.92,-0.51l0.08,-1c1.39,0.12 2.74,0.29 4,0.52ZM596.9,174.39 L596.83,173.39c1.19,-0.07 2.38,-0.11 3.56,-0.11h0.49v1h-0.48C599.27,174.31 598.09,174.34 596.93,174.42ZM580,172c-0.54,-1.22 -1,-2.49 -1.45,-3.78l1,-0.31c0.42,1.26 0.89,2.5 1.41,3.69ZM577.47,164.32c-0.3,-1.29 -0.55,-2.63 -0.74,-4l1,-0.14c0.19,1.32 0.43,2.63 0.72,3.9ZM576.35,156.32c-0.05,-0.9 -0.08,-1.82 -0.08,-2.74 0,-0.43 0,-0.87 0,-1.3l1,0c0,0.43 0,0.85 0,1.28 0,0.9 0,1.81 0.07,2.68ZM577.54,148.32 L576.54,148.22c0.14,-1.32 0.33,-2.67 0.56,-4l1,0.17C577.83,145.72 577.64,147 577.51,148.34ZM578.91,140.51 L577.91,140.27c0.32,-1.29 0.69,-2.59 1.1,-3.89l1,0.31C579.56,138 579.19,139.27 578.88,140.53ZM581.31,132.94 L580.38,132.58c0.49,-1.25 1,-2.5 1.61,-3.71l0.9,0.44C582.29,130.51 581.76,131.73 581.28,133ZM584.75,125.81 L583.88,125.3c0.68,-1.15 1.41,-2.3 2.17,-3.4l0.82,0.57C586.09,123.57 585.38,124.69 584.72,125.83ZM589.26,119.3 L588.48,118.67c0.84,-1 1.74,-2.06 2.67,-3l0.72,0.69C590.93,117.3 590.05,118.3 589.23,119.32ZM594.7,113.54 L594.03,112.8c1,-0.89 2,-1.77 3.07,-2.62l0.62,0.79C596.65,111.82 595.63,112.69 594.67,113.56ZM600.91,108.6 L600.34,107.77c1.09,-0.75 2.23,-1.49 3.39,-2.19l0.51,0.85C603.08,107.14 602,107.87 600.88,108.62ZM607.7,104.47 L607.23,103.59c1.18,-0.63 2.4,-1.23 3.62,-1.79l0.42,0.91C610,103.28 608.83,103.88 607.67,104.49ZM614.93,101.15 L614.56,100.21c1.26,-0.49 2.53,-1 3.79,-1.37l0.32,1C617.4,100.22 616.14,100.68 614.9,101.17Z" + android:fillColor="#263238"/> + <path + android:pathData="M622.64,98.62l-0.25,-1c1.24,-0.32 2,-0.46 2,-0.46l0.18,1S623.85,98.31 622.64,98.62Z" + android:fillColor="#263238"/> + <path + android:pathData="M640.32,92.16c-2.55,-7.9 -19.63,-5.06 -16.3,5.27S642.87,100.07 640.32,92.16Z" + android:fillColor="#263238"/> + <path + android:pathData="M614.73,89c0.13,-3.47 4.95,-6.14 11.77,-4.91s13.23,5.83 13.23,5.83S633,94 626.11,94.75 614.6,92.46 614.73,89Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M639.73,89.9c-3.54,0 -7.07,-0.1 -10.6,-0.21s-7.07,-0.29 -10.6,-0.57c3.54,0 7.08,0.09 10.61,0.2S636.21,89.61 639.73,89.9Z" + android:fillColor="#263238"/> + <path + android:pathData="M621.58,85.91a29.75,29.75 0,0 1,5.65 3.53,26.64 26.64,0 0,1 -2.92,-1.6A28.63,28.63 0,0 1,621.58 85.91Z" + android:fillColor="#263238"/> + <path + android:pathData="M630.85,89.57A32.47,32.47 0,0 1,625 93.35a32.47,32.47 0,0 1,5.88 -3.78Z" + android:fillColor="#263238"/> + <path + android:pathData="M631.88,87.62a7.24,7.24 0,0 1,2.58 2.08,6.85 6.85,0 0,1 -1.41,-0.89A7.32,7.32 0,0 1,631.88 87.62Z" + android:fillColor="#263238"/> + <path + android:pathData="M621.23,109.55c2.13,2.74 7.6,2.08 12.41,-2.9S641,94.18 641,94.18s-7.88,0.6 -13.89,4S619.09,106.8 621.23,109.55Z" + android:fillColor="#ebebeb"/> + <path + android:pathData="M641,94.18c-2.88,2 -5.68,4.22 -8.49,6.37s-5.56,4.37 -8.25,6.66c2.88,-2 5.68,-4.21 8.48,-6.36S638.27,96.48 641,94.18Z" + android:fillColor="#263238"/> + <path + android:pathData="M628.58,108a28.53,28.53 0,0 0,1.43 -3,26.73 26.73,0 0,0 1.08,-3.16 27.77,27.77 0,0 0,-1.43 3A28.52,28.52 0,0 0,628.58 108Z" + android:fillColor="#263238"/> + <path + android:pathData="M634,99.64a33.06,33.06 0,0 0,-7 0.37,29.2 29.2,0 0,0 3.5,0A31.11,31.11 0,0 0,634 99.64Z" + android:fillColor="#263238"/> + <path + android:pathData="M635.93,100.63a7.15,7.15 0,0 0,0.62 -1.56,7.48 7.48,0 0,0 0.26,-1.65 7.45,7.45 0,0 0,-0.88 3.21Z" + android:fillColor="#263238"/> + <path + android:pathData="M640.32,92.16a3,3 0,1 1,1.93 -3.77A3,3 0,0 1,640.32 92.16Z" + android:fillColor="#455a64"/> + <path + android:pathData="M642.16,97.87a3,3 0,1 1,1.93 -3.78A3,3 0,0 1,642.16 97.87Z" + android:fillColor="#455a64"/> + <path + android:pathData="M314.31,95.32a24.92,24.92 0,0 1,-41.64 15.77l-12.47,1.83 6.24,-10.78a24.92,24.92 0,1 1,47.87 -6.82Z" + android:fillColor="#fff"/> + <path + android:pathData="M314.31,95.32a25,25 0,0 1,-5 12.63,22.11 22.11,0 0,1 -4.89,4.83 24.26,24.26 0,0 1,-6 3.35,24.53 24.53,0 0,1 -6.71,1.6 25,25 0,0 1,-3.46 0.07,22.18 22.18,0 0,1 -3.45,-0.36 25.16,25.16 0,0 1,-12.33 -6.09l0.29,0.09 -12.45,1.91 -0.91,0.14 0.46,-0.8 6.2,-10.8 0,0.43a25.18,25.18 0,0 1,1.54 -22.21,25.54 25.54,0 0,1 7.8,-8.32 25.37,25.37 0,0 1,21.91 -3,25.53 25.53,0 0,1 9.61,5.9A25,25 0,0 1,314.31 95.32ZM314.31,95.32a24.65,24.65 0,0 0,-28.26 -27,24.38 24.38,0 0,0 -10.29,4.06 25.69,25.69 0,0 0,-7.46 8.14,24.62 24.62,0 0,0 -3.17,10.54A24.87,24.87 0,0 0,266.89 102l0.09,0.22 -0.12,0.21 -6.28,10.76 -0.44,-0.66 12.48,-1.75 0.17,0 0.12,0.11A24.56,24.56 0,0 0,284.85 117a21.23,21.23 0,0 0,3.38 0.41,24.26 24.26,0 0,0 3.41,0 25,25 0,0 0,6.66 -1.47,23.44 23.44,0 0,0 6,-3.24 22.78,22.78 0,0 0,4.9 -4.77A25,25 0,0 0,314.31 95.32Z" + android:fillColor="#263238"/> + <path + android:pathData="M277.34,104.35a2.42,2.42 0,0 1,2.44 -2.56,2.56 2.56,0 0,1 0,5.12A2.42,2.42 0,0 1,277.34 104.35ZM278.34,98.44 L277.76,78.6h4l-0.58,19.84Z" + android:fillColor="#8AB0FF"/> + <path + android:pathData="M286.85,104.35a2.42,2.42 0,0 1,2.43 -2.56,2.56 2.56,0 0,1 0,5.12A2.42,2.42 0,0 1,286.85 104.35ZM287.85,98.44L287.3,78.6h4l-0.58,19.84Z" + android:fillColor="#8AB0FF"/> + <path + android:pathData="M296.35,104.35a2.42,2.42 0,0 1,2.44 -2.56,2.56 2.56,0 0,1 0,5.12A2.42,2.42 0,0 1,296.35 104.35ZM297.35,98.44 L296.77,78.6h4l-0.57,19.84Z" + android:fillColor="#8AB0FF"/> +</vector> diff --git a/app/src/main/res/drawable/round_button.xml b/app/src/main/res/drawable/round_button.xml new file mode 100644 index 0000000000000000000000000000000000000000..a4c6e5099fbe20b9e073dbea48279d04b6ce8d61 --- /dev/null +++ b/app/src/main/res/drawable/round_button.xml @@ -0,0 +1,13 @@ +<?xml version = "1.0" encoding = "utf-8"?> +<selector xmlns:android = "http://schemas.android.com/apk/res/android"> + <item android:state_pressed = "false"> + <shape android:shape = "oval"> + <solid android:color = "#ffffff"/> + </shape> + </item> + <item android:state_pressed = "true"> + <shape android:shape = "oval"> + <solid android:color = "#ffffff"/> + </shape> + </item> +</selector> \ No newline at end of file diff --git a/app/src/main/res/drawable/round_button_blue.xml b/app/src/main/res/drawable/round_button_blue.xml new file mode 100644 index 0000000000000000000000000000000000000000..93b9c33707ace6d9c3014ede825dcb9c127c1594 --- /dev/null +++ b/app/src/main/res/drawable/round_button_blue.xml @@ -0,0 +1,13 @@ +<?xml version = "1.0" encoding = "utf-8"?> +<selector xmlns:android = "http://schemas.android.com/apk/res/android"> + <item android:state_pressed = "false"> + <shape android:shape = "oval"> + <solid android:color = "@color/md_theme_primary" /> + </shape> + </item> + <item android:state_pressed = "true"> + <shape android:shape = "oval"> + <solid android:color = "@color/md_theme_primary"/> + </shape> + </item> +</selector> \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_button.xml b/app/src/main/res/drawable/rounded_button.xml new file mode 100644 index 0000000000000000000000000000000000000000..390fd78f3e5f70b7572a61c569a217c1585f9cd8 --- /dev/null +++ b/app/src/main/res/drawable/rounded_button.xml @@ -0,0 +1,6 @@ +<!-- rounded_button_background.xml --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/md_theme_blue" /> + <corners android:radius="15dp" /> <!-- Adjust the radius to change the roundness --> +</shape> diff --git a/app/src/main/res/drawable/rounded_dialog.xml b/app/src/main/res/drawable/rounded_dialog.xml new file mode 100644 index 0000000000000000000000000000000000000000..78ba6c2d8d395d1a3fee721b15ec0fb9c227d467 --- /dev/null +++ b/app/src/main/res/drawable/rounded_dialog.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/md_theme_surfaceContainer"/> + <corners android:topLeftRadius="50dp" + android:topRightRadius="50dp"/> + +</shape> diff --git a/app/src/main/res/drawable/scan.png b/app/src/main/res/drawable/scan.png new file mode 100644 index 0000000000000000000000000000000000000000..c838cd68be6b992eaabe1f6e26ce6235cc9e205f Binary files /dev/null and b/app/src/main/res/drawable/scan.png differ diff --git a/app/src/main/res/drawable/twibbon_faker.png b/app/src/main/res/drawable/twibbon_faker.png new file mode 100644 index 0000000000000000000000000000000000000000..c002a4c3b7dfb53c3ae5c38633a092a0c6d2ac6c Binary files /dev/null and b/app/src/main/res/drawable/twibbon_faker.png differ diff --git a/app/src/main/res/drawable/twibbon_soobim.png b/app/src/main/res/drawable/twibbon_soobim.png new file mode 100644 index 0000000000000000000000000000000000000000..cc6a2b3cca00d053074399b92788d9250725c409 Binary files /dev/null and b/app/src/main/res/drawable/twibbon_soobim.png differ diff --git a/app/src/main/res/font/nunito.xml b/app/src/main/res/font/nunito.xml new file mode 100644 index 0000000000000000000000000000000000000000..28b18c42b353b7a12b2451c55e1105c68bc46140 --- /dev/null +++ b/app/src/main/res/font/nunito.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<font-family xmlns:app="http://schemas.android.com/apk/res-auto" + app:fontProviderAuthority="com.google.android.gms.fonts" + app:fontProviderPackage="com.google.android.gms" + app:fontProviderQuery="Nunito" + app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"> +</font-family> diff --git a/app/src/main/res/font/nunito_bold.xml b/app/src/main/res/font/nunito_bold.xml new file mode 100644 index 0000000000000000000000000000000000000000..44848841cef6a446fa51c2c2663db5763377b9cb --- /dev/null +++ b/app/src/main/res/font/nunito_bold.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<font-family xmlns:app="http://schemas.android.com/apk/res-auto" + app:fontProviderAuthority="com.google.android.gms.fonts" + app:fontProviderPackage="com.google.android.gms" + app:fontProviderQuery="name=Nunito&weight=700" + app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"> +</font-family> diff --git a/app/src/main/res/font/nunito_italic.xml b/app/src/main/res/font/nunito_italic.xml new file mode 100644 index 0000000000000000000000000000000000000000..43fd8f4c01ffe61be63b62682f40a2a50857d335 --- /dev/null +++ b/app/src/main/res/font/nunito_italic.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<font-family xmlns:app="http://schemas.android.com/apk/res-auto" + app:fontProviderAuthority="com.google.android.gms.fonts" + app:fontProviderPackage="com.google.android.gms" + app:fontProviderQuery="name=Nunito&italic=1" + app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"> +</font-family> diff --git a/app/src/main/res/layout-land/fragment_graph.xml b/app/src/main/res/layout-land/fragment_graph.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc83539a7fc87b91cb263af91d96389c02dbdd68 --- /dev/null +++ b/app/src/main/res/layout-land/fragment_graph.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".view.graph.GraphFragment" + android:background="@color/md_theme_surface" + > + <TextView + android:id="@+id/textView" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="20dp" + android:layout_marginTop="10dp" + android:padding="10dp" + android:text="@string/title_chart" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/cl_empty_rv" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/textView"> + + <ImageView + android:id="@+id/iv_no_data" + android:layout_width="300dp" + android:layout_height="300dp" + android:layout_marginTop="20dp" + android:contentDescription="@string/cd_transaction_empty" + android:src="@drawable/no_data_cuate" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:text="@string/msg_empty_transaction" + android:textColor="@color/md_theme_tertiary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/iv_no_data" + + /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <RelativeLayout + android:id="@+id/relativeLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/textView" + app:layout_goneMarginTop="@dimen/title_top_margin"> + + <com.github.mikephil.charting.charts.PieChart + android:id="@+id/chart1" + android:layout_width="match_parent" + android:layout_height="200dp" + /> + + </RelativeLayout> +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 06ea6cae22113f243efe317f984f7742418737e8..ff8ea4437924a5d916dd4d7c47ddd94eebb0eef7 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,22 +1,37 @@ <?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/md_theme_background" > +<androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/container" + android:visibility="gone" android:layout_width="match_parent" + android:background="@color/md_theme_surface" android:layout_height="match_parent" - android:paddingTop="?attr/actionBarSize"> + > <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/nav_view" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="0dp" - android:layout_marginEnd="0dp" - android:background="?android:attr/windowBackground" + android:background="@color/md_theme_surface" + android:paddingBottom="10dp" + android:paddingTop="4dp" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" - app:menu="@menu/bottom_nav_menu" /> + app:itemTextColor="@color/btm_nav_color" + app:itemIconTint="@color/btm_nav_color" + app:itemBackground="@color/md_theme_surface" + app:labelVisibilityMode="labeled" + app:itemTextAppearanceInactive="@style/BottomNavigationViewTextStyle" + app:itemTextAppearanceActive="@style/BottomNavigationViewTextStyle" + app:menu="@menu/bottom_nav_menu" /> <fragment android:id="@+id/nav_host_fragment_activity_main" @@ -25,9 +40,25 @@ android:layout_height="match_parent" app:defaultNavHost="true" app:layout_constraintBottom_toTopOf="@id/nav_view" + app:layout_constraintHorizontal_bias="1.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="1.0" app:navGraph="@navigation/mobile_navigation" /> - -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file +</androidx.constraintlayout.widget.ConstraintLayout> + <FrameLayout + android:id="@+id/loading" + android:visibility="visible" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <ProgressBar + android:layout_width="100dp" + android:layout_height="100dp" + android:layout_gravity="center" + android:indeterminate="true" + android:indeterminateTint="@color/md_theme_primary" + android:indeterminateTintMode="src_atop" + android:translationZ="10dp" /> + </FrameLayout> +</FrameLayout> diff --git a/app/src/main/res/layout/bottom_dialog_map.xml b/app/src/main/res/layout/bottom_dialog_map.xml new file mode 100644 index 0000000000000000000000000000000000000000..cfe1ccaf306118c3a8f6ab6849b63e238f9d1423 --- /dev/null +++ b/app/src/main/res/layout/bottom_dialog_map.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + + <TextView + android:id="@+id/tv_btm_dialog_name" + android:layout_width="330dp" + style="@style/TextAppearance.HeadlineMedium" + android:textColor="@color/md_theme_primary" + android:layout_marginTop="20dp" + android:gravity="center" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/tv_address" + android:layout_width="330dp" + style="@style/TextAppearance.BodyLarge" + android:textColor="@color/md_theme_primary" + android:layout_marginTop="20dp" + android:gravity="center" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_btm_dialog_name" /> + + <Button + android:id="@+id/btn_open_map" + style="@style/buttonStylePrimary" + android:layout_width="330dp" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="30dp" + android:width="200dp" + android:drawableStart="@drawable/ic_map" + android:focusable="false" + android:layout_marginBottom="30dp" + android:focusableInTouchMode="false" + android:text="@string/btn_open_map" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.493" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_address" + app:layout_constraintVertical_bias="0.028" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_custom.xml b/app/src/main/res/layout/dialog_custom.xml new file mode 100644 index 0000000000000000000000000000000000000000..274d6aa40675a4489f32eee5255d9c82593c547b --- /dev/null +++ b/app/src/main/res/layout/dialog_custom.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + + <androidx.cardview.widget.CardView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:cardBackgroundColor="@color/md_theme_surfaceContainer" + app:cardCornerRadius="20dp" + app:cardElevation="10dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="330dp" + android:layout_height="wrap_content" + android:paddingVertical="20dp" + android:paddingHorizontal="20dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <TextView + android:id="@+id/dialog_tv_title" + style="@style/TextAppearance.HeadlineMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="15dp" + android:text="@string/dialog_title" + android:gravity="center" + android:textColor="@color/md_theme_primary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/dialog_tv_message" + style="@style/TextAppearance.BodyMedium" + android:layout_width="250dp" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/dialog_message" + android:gravity="center" + android:textColor="@color/md_theme_primary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/dialog_tv_title" + /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="40dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/dialog_tv_message" + app:layout_constraintVertical_bias="0.0" + > + + <Button + android:id="@+id/dialog_btn_cancel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:backgroundTint="@color/md_theme_red" + android:text="@string/btn_cancel" + android:textAllCaps="true" + android:layout_marginEnd="76dp" + android:textAppearance="@style/TextAppearance.LabelLarge" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@+id/dialog_btn_submit" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.0" /> + + <Button + android:id="@+id/dialog_btn_submit" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:backgroundTint="@color/md_theme_primary" + android:text="@string/btn_submit" + android:textAllCaps="true" + android:textAppearance="@style/TextAppearance.LabelLarge" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + + </androidx.constraintlayout.widget.ConstraintLayout> + </androidx.cardview.widget.CardView> +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_no_network.xml b/app/src/main/res/layout/dialog_no_network.xml new file mode 100644 index 0000000000000000000000000000000000000000..41ad33d85b4c079070804892cc8a04faebe1f77e --- /dev/null +++ b/app/src/main/res/layout/dialog_no_network.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + + <androidx.cardview.widget.CardView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:cardBackgroundColor="@color/md_theme_surfaceContainer" + app:cardCornerRadius="20dp" + app:cardElevation="10dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="330dp" + android:layout_height="wrap_content" + android:paddingVertical="20dp" + android:paddingHorizontal="20dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + > + + <ImageView + android:id="@+id/img_no_network" + android:layout_width="200dp" + android:layout_height="200dp" + android:layout_marginBottom="18dp" + android:contentDescription="@string/img_no_network_description" + android:src="@drawable/img_no_network" + app:layout_constraintBottom_toTopOf="@id/text_no_network" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/text_no_network" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/no_network" + android:textAlignment="center" + android:textColor="@color/md_theme_primary" + android:paddingBottom="7dp" + app:layout_constraintBottom_toTopOf="@id/text_no_network_description" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/img_no_network" /> + + <TextView + android:id="@+id/text_no_network_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/no_network_description" + android:textAlignment="center" + android:textSize="14sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/text_no_network" + app:layout_constraintBottom_toTopOf="@id/dialog_btn_okay"/> + + <Button + android:id="@+id/dialog_btn_okay" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:text="@string/okay" + android:layout_marginTop="30dp" + style="@style/buttonStylePrimary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/text_no_network_description" + /> + </androidx.constraintlayout.widget.ConstraintLayout> + </androidx.cardview.widget.CardView> +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml index 166ab0e9e603c1f230a7b9514d293b963ab2309e..9b360e21e81cb94a2129baf0187188982e428fc3 100644 --- a/app/src/main/res/layout/fragment_dashboard.xml +++ b/app/src/main/res/layout/fragment_dashboard.xml @@ -4,19 +4,25 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.dashboard.DashboardFragment"> + tools:context=".view.dashboard.DashboardFragment"> - <TextView - android:id="@+id/text_dashboard" + <androidx.fragment.app.FragmentContainerView + android:id="@+id/dashboard_child_fragment" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:textAlignment="center" - android:textSize="20sp" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@id/button_logout" + /> + + <Button + android:id="@+id/button_logout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Logout" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/dashboard_child_fragment" + /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_graph.xml b/app/src/main/res/layout/fragment_graph.xml new file mode 100644 index 0000000000000000000000000000000000000000..c5026257ae8494c365d336c436fe2de0e09db831 --- /dev/null +++ b/app/src/main/res/layout/fragment_graph.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".view.graph.GraphFragment" + android:background="@color/md_theme_surface" + > + <TextView + android:id="@+id/textView" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="20dp" + android:layout_marginTop="10dp" + android:padding="10dp" + android:text="@string/title_chart" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/cl_empty_rv" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + android:visibility="gone" + app:layout_constraintTop_toBottomOf="@id/textView"> + + <ImageView + android:id="@+id/iv_no_data" + android:layout_width="300dp" + android:layout_height="300dp" + android:layout_marginTop="20dp" + android:contentDescription="@string/cd_transaction_empty" + android:src="@drawable/no_data_cuate" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:text="@string/msg_empty_transaction" + android:textColor="@color/md_theme_tertiary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/iv_no_data" + + /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <RelativeLayout + android:id="@+id/relativeLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/textView" + app:layout_goneMarginTop="@dimen/title_top_margin"> + + <com.github.mikephil.charting.charts.PieChart + android:id="@+id/chart1" + android:layout_width="match_parent" + android:layout_height="match_parent" + /> + + </RelativeLayout> +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml deleted file mode 100644 index f3d9b08ffe6101e25c77c5fae7e28bb5dfa11fbd..0000000000000000000000000000000000000000 --- a/app/src/main/res/layout/fragment_home.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - tools:context=".ui.home.HomeFragment"> - - <TextView - android:id="@+id/text_home" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:textAlignment="center" - android:textSize="20sp" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_login.xml b/app/src/main/res/layout/fragment_login.xml new file mode 100644 index 0000000000000000000000000000000000000000..3020057fa8253b52ba8f6e99ef70a85c3d4c1b24 --- /dev/null +++ b/app/src/main/res/layout/fragment_login.xml @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/md_theme_background" > +<androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/login_fragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingHorizontal="30dp" + android:paddingBottom="100dp" + android:layout_gravity="center" + tools:context=".view.login.LoginFragment"> + + <ImageView + android:id="@+id/img_logo" + android:layout_width="80dp" + android:layout_height="120dp" + android:layout_marginBottom="25dp" + android:contentDescription="@string/img_logo_description" + android:src="@drawable/img_logo" + app:layout_constraintBottom_toTopOf="@id/text_login" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.498" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/text_login" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:layout_marginBottom="50dp" + android:text="@string/login" + android:textAlignment="center" + android:textColor="@color/md_theme_primary" + app:layout_constraintBottom_toTopOf="@id/email_text_input" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + + app:layout_constraintTop_toBottomOf="@id/img_logo" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/email_text_input" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_email" + android:layout_marginBottom="20dp" + app:layout_constraintBottom_toTopOf="@id/password_text_input" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/text_login"> + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_email" + style="@style/TextAppearance.BodyLarge" + android:textColor="@color/md_theme_primary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:autofillHints="emailAddress" + android:inputType="textEmailAddress" + android:maxLength="255" + /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/password_text_input" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_password" + app:passwordToggleEnabled="true" + app:layout_constraintBottom_toTopOf="@id/button_next_container" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/email_text_input"> + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_password" + style="@style/TextAppearance.BodyLarge" + android:textColor="@color/md_theme_primary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:autofillHints="password" + android:inputType="textPassword" + android:maxLength="100" + /> + </com.google.android.material.textfield.TextInputLayout> + + <RelativeLayout + android:id="@+id/button_next_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/password_text_input"> + + <ProgressBar + android:id="@+id/button_login_progress" + android:layout_width="wrap_content" + android:layout_height="30dp" + android:layout_alignStart="@+id/button_login_text" + android:layout_alignTop="@+id/button_login_text" + android:layout_alignBottom="@+id/button_login_text" + android:layout_gravity="center" + android:layout_marginVertical="12dp" + android:layout_marginStart="100dp" + android:indeterminate="true" + android:indeterminateTint="@color/md_theme_onSurface" + android:indeterminateTintMode="src_atop" + android:visibility="gone" + android:translationZ="10dp" /> + + <Button + android:id="@+id/button_login_text" + style="@style/buttonStylePrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="30dp" + android:width="200dp" + android:focusable="false" + android:focusableInTouchMode="false" + android:text="@string/login_button_text" /> + </RelativeLayout> +</androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.fragment.app.FragmentContainerView + android:id="@+id/login_child_fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="gone" + /> +</FrameLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_no_network.xml b/app/src/main/res/layout/fragment_no_network.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea323b684310d3652c8998e328ed4f4c9341da32 --- /dev/null +++ b/app/src/main/res/layout/fragment_no_network.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingHorizontal="30dp" + android:layout_gravity="center" + android:background="@color/md_theme_background" + tools:context=".view.network.NoNetworkFragment"> + + <ImageView + android:id="@+id/img_no_network" + android:layout_width="245dp" + android:layout_height="245dp" + android:layout_marginBottom="18dp" + android:contentDescription="@string/img_no_network_description" + android:src="@drawable/img_no_network" + app:layout_constraintBottom_toTopOf="@id/text_no_network" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/text_no_network" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/no_network" + android:textAlignment="center" + android:textColor="@color/md_theme_primary" + android:paddingBottom="7dp" + app:layout_constraintBottom_toTopOf="@id/text_no_network_description" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/img_no_network" /> + + <TextView + android:id="@+id/text_no_network_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/no_network_description" + android:textAlignment="center" + android:textSize="20sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/text_no_network" + /> +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml deleted file mode 100644 index d41793572bb3b8347ec4bced74b7bd4a43bed5d4..0000000000000000000000000000000000000000 --- a/app/src/main/res/layout/fragment_notifications.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - tools:context=".ui.notifications.NotificationsFragment"> - - <TextView - android:id="@+id/text_notifications" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:textAlignment="center" - android:textSize="20sp" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_scan.xml b/app/src/main/res/layout/fragment_scan.xml new file mode 100644 index 0000000000000000000000000000000000000000..54ebb32706a503200cf06c7d2597da1787e704fd --- /dev/null +++ b/app/src/main/res/layout/fragment_scan.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/md_theme_primary" + android:paddingHorizontal="30dp"> + + <TextView + android:id="@+id/tv_scan_title" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/title_top_margin" + android:text="@string/title_scan" + android:textColor="@color/white" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.cardview.widget.CardView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="90dp" + app:cardCornerRadius="50dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_scan_title"> + + <androidx.camera.view.PreviewView + android:id="@+id/viewFinder" + android:layout_width="330dp" + android:layout_height="330dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.476" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.394" /> + </androidx.cardview.widget.CardView> + + <androidx.appcompat.widget.AppCompatButton + android:id="@+id/shutter" + android:layout_width="57dp" + android:layout_height="57dp" + android:layout_marginBottom="112dp" + android:background="@drawable/round_button" + android:elevation="2dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" /> +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_scan_home.xml b/app/src/main/res/layout/fragment_scan_home.xml new file mode 100644 index 0000000000000000000000000000000000000000..ebd34b798e5f7cfce0f05a9f2814f5ed594314c2 --- /dev/null +++ b/app/src/main/res/layout/fragment_scan_home.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/md_theme_background" > +<androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/scan_fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/md_theme_primary"> + <TextView + android:id="@+id/tv_scan_title" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/title_top_margin" + android:layout_marginStart="30dp" + android:text="@string/title_scan" + android:textColor="@color/white" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id = "@+id/tv_scan_deskripsi" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:text="@string/scan_description" + android:textColor="@color/white" + android:textSize="16sp" + app:layout_constraintStart_toStartOf="@+id/tv_scan_title" + app:layout_constraintTop_toBottomOf="@+id/tv_scan_title" + tools:layout_editor_absoluteX="1dp" /> + + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="0dp" + android:src="@drawable/scan" + app:layout_constraintStart_toStartOf="@+id/tv_scan_title" + app:layout_constraintTop_toBottomOf="@+id/tv_scan_deskripsi" + android:contentDescription="@string/scan_image" /> + + <LinearLayout + android:id = "@+id/ll_button" + android:layout_width="match_parent" + android:layout_height="220dp" + android:background="@color/white" + android:orientation="vertical" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + tools:layout_editor_absoluteX="60dp"> + + <Button + android:id = "@+id/to_scan_button" + style="@style/buttonStylePrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="30dp" + android:layout_marginTop="25dp" + android:layout_marginEnd="30dp" + android:text="@string/btn_scan" /> + + <Button + android:id = "@+id/to_galeri_button" + style="@style/buttonStylePrimary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="30dp" + android:layout_marginTop="10dp" + android:layout_marginEnd="30dp" + android:text="@string/btn_scan_gallery" /> + </LinearLayout> +</androidx.constraintlayout.widget.ConstraintLayout> + <androidx.fragment.app.FragmentContainerView + android:id="@+id/scan_child_fragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="gone" + /> +</FrameLayout> diff --git a/app/src/main/res/layout/fragment_scan_result.xml b/app/src/main/res/layout/fragment_scan_result.xml new file mode 100644 index 0000000000000000000000000000000000000000..6b61d8ae2303802c420ae299c784fc957eb75be1 --- /dev/null +++ b/app/src/main/res/layout/fragment_scan_result.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:background="@color/md_theme_primary"> + + <TextView + android:id="@+id/tv_scan_result_title" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="30dp" + android:layout_marginTop="20dp" + android:text="Hasil Scan" + android:textColor="@color/white" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="430dp" + android:layout_marginStart="30dp" + android:layout_marginEnd="30dp" + android:layout_marginTop="20dp" + android:orientation="vertical" + + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_scan_result_title"> + <TextView + android:id= "@+id/test_aja" + android:textColor="@color/white" + android:layout_width="match_parent" + android:layout_height="match_parent" + /> +<!-- <androidx.recyclerview.widget.RecyclerView--> +<!-- android:id="@+id/rvTransaction"--> +<!-- android:layout_width="match_parent"--> +<!-- android:layout_height="match_parent"--> +<!-- app:layout_constraintEnd_toEndOf="parent"--> +<!-- app:layout_constraintStart_toStartOf="parent"--> +<!-- app:layout_constraintTop_toTopOf="parent" />--> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="180dp" + android:orientation="vertical" + android:background="@color/white" + app:layout_constraintBottom_toBottomOf="parent" + > + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text = "Apakah anda ingin mengulang pengambilan foto?" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + android:textColor="@color/textColor" + android:layout_marginTop="20dp" + android:layout_marginStart="80dp" + android:layout_marginEnd = "80dp" + android:gravity="center_horizontal" + /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="horizontal" + android:layout_marginTop="10dp"> + + <androidx.appcompat.widget.AppCompatButton + android:id="@+id/button_tidak_ulang" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="0dp" + android:layout_marginEnd="30dp" + android:background="@drawable/rounded_button" + android:text="Tidak" + android:textColor="@color/white" + app:layout_constraintStart_toStartOf="parent" /> + + <Button + android:id="@+id/button_ulang" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="30dp" + android:layout_marginTop="0dp" + android:background="@drawable/rounded_button" + android:text="Ya" + android:textColor="@color/white" + app:layout_constraintEnd_toEndOf="parent" /> + </LinearLayout> + </LinearLayout> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..ca2d4c0ca52489b6e78d4b4d2854343e86476f00 --- /dev/null +++ b/app/src/main/res/layout/fragment_settings.xml @@ -0,0 +1,277 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingHorizontal="@dimen/fragment_horizontal_padding" + android:background="@color/md_theme_surface"> + + <TextView + android:id="@+id/tv_transaction_new" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/title_top_margin" + android:text="@string/title_settings" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/constraintLayout4" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="30dp" + android:background="@drawable/bg_settings_card_user" + android:padding="@dimen/card_padding" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_transaction_new"> + + <ImageView + android:id="@+id/avatar" + android:layout_width="60dp" + android:layout_height="60dp" + android:layout_marginStart="4dp" + android:contentDescription="@string/excel_pic" + android:padding="5dp" + android:src="@drawable/avatar" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/user_email" + app:layout_constraintTop_toTopOf="parent" + /> + <TextView + android:id="@+id/user_email" + style="@style/TextAppearance.TitleMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/title_start_margin" + android:textColor="@color/textColor" + app:layout_constraintStart_toEndOf="@id/avatar" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + /> + + + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/constraintLayout3" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_gap" + android:background="@drawable/bg_settings_card_user" + android:padding="@dimen/card_padding" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/constraintLayout4"> + <ImageView + android:id="@+id/icon_settings_card_excel" + android:layout_width="32dp" + android:layout_height="32dp" + android:contentDescription="@string/excel_pic" + android:src="@drawable/excel_icon" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/tv_title_settings_card_excel" + app:layout_constraintTop_toTopOf="parent" + app:tint="@color/textColor" /> + + <TextView + android:id="@+id/tv_title_settings_card_excel" + style="@style/TextAppearance.TitleMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/save_transaction" + android:textColor="@color/textColor" + android:textStyle="bold" + android:layout_marginStart="@dimen/title_start_margin" + app:layout_constraintStart_toEndOf="@id/icon_settings_card_excel" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@id/tv_description_settings_card_excel" /> + <TextView + android:id="@+id/tv_description_settings_card_excel" + style="@style/TextAppearance.LabelMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/file_type" + android:textColor="@color/textColor" + android:layout_marginStart="@dimen/title_start_margin" + app:layout_constraintStart_toEndOf="@id/icon_settings_card_excel" + app:layout_constraintTop_toBottomOf="@id/tv_title_settings_card_excel" + app:layout_constraintBottom_toTopOf="@id/button_save_excel" /> + + <Button + android:id="@+id/button_save_excel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/simpan" + style="@style/buttonStylePrimary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_description_settings_card_excel" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/constraintLayout5" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_gap" + android:background="@drawable/bg_settings_card_user" + android:padding="@dimen/card_padding" + app:layout_constraintTop_toBottomOf="@+id/constraintLayout3" + tools:layout_editor_absoluteX="-16dp"> + + <ImageView + android:id="@+id/icon_email" + android:layout_width="32dp" + android:layout_height="32dp" + android:contentDescription="@string/gmail_pic" + android:src="@drawable/email_icon" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/tv_title_settings_card_email" + app:layout_constraintTop_toTopOf="parent" + app:tint="@color/textColor" /> + + <TextView + android:id="@+id/tv_title_settings_card_email" + style="@style/TextAppearance.TitleMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/kirim_daftar_transaksi" + android:textColor="@color/textColor" + android:textStyle="bold" + android:layout_marginStart="@dimen/title_start_margin" + app:layout_constraintStart_toEndOf="@id/icon_email" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@id/tv_description_settings_card_email" + /> + + <TextView + android:id="@+id/tv_description_settings_card_email" + style="@style/TextAppearance.LabelMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/gmail" + android:textColor="@color/textColor" + android:layout_marginStart="@dimen/title_start_margin" + app:layout_constraintStart_toEndOf="@id/icon_email" + app:layout_constraintTop_toBottomOf="@id/tv_title_settings_card_email" + /> + + <Button + android:id="@+id/button_send_email" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/kirim" + style="@style/buttonStylePrimary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_description_settings_card_email" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/no_network_email_alert" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/bg_settings_alert_card_email" + android:paddingVertical="10dp" + android:layout_marginTop="10dp" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_description_settings_card_email" + > + <TextView + android:id="@+id/tv_title_no_network_email_alert" + style="@style/TextAppearance.TitleSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/tv_settings_alert_email_no_network" + android:textColor="@color/md_theme_error" + android:textStyle="bold" + android:layout_marginStart="@dimen/title_start_margin" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@id/description_no_network_email_alert" + /> + + <TextView + android:id="@+id/description_no_network_email_alert" + style="@style/TextAppearance.LabelMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/tv_description_settings_email_no_network" + android:textColor="@color/md_theme_error" + android:layout_marginStart="@dimen/title_start_margin" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_title_no_network_email_alert" + app:layout_constraintBottom_toTopOf="@id/no_network_email_alert" + /> + </androidx.constraintlayout.widget.ConstraintLayout> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/constraintLayout6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_gap" + android:background="@drawable/bg_settings_card_user" + android:padding="@dimen/card_padding" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/constraintLayout5"> + + <TextView + android:id="@+id/textView2" + style="@style/TextAppearance.TitleMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/title_start_margin" + android:text="@string/random_transaksi" + android:textColor="@color/textColor" + android:textStyle="bold" + app:layout_constraintStart_toEndOf="@+id/icon_random_transaction" + app:layout_constraintTop_toTopOf="parent" /> + + <ImageView + android:id="@+id/icon_random_transaction" + android:layout_width="32dp" + android:layout_height="32dp" + android:contentDescription="@string/gmail_pic" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_transaction" + app:tint="@color/textColor" /> + + <Button + android:id="@+id/buttonRandom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/title_top_margin" + android:text="@string/button_random" + style="@style/buttonStylePrimary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textView2" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_end="405dp" /> + + <Button + android:id="@+id/button_log_out" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="50dp" + android:text="@string/button_logout" + style="@style/buttonStylePrimary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/constraintLayout6" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_transaction.xml b/app/src/main/res/layout/fragment_transaction.xml new file mode 100644 index 0000000000000000000000000000000000000000..a588bb6b8dd56c04a9064ccc68996d2531d704e2 --- /dev/null +++ b/app/src/main/res/layout/fragment_transaction.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:background="@color/md_theme_surface" + android:layout_height="match_parent" + android:paddingHorizontal="@dimen/fragment_horizontal_padding" + tools:context=".view.transaction.TransactionFragment" + > + + <TextView + android:id="@+id/tv_title_fragment" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/title_top_margin" + android:text="@string/title_transactions" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/constraintLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="15dp" + android:layout_marginBottom="20dp" + android:background="@drawable/bg_transaction_balance" + android:paddingLeft="@dimen/card_padding" + android:paddingTop="22dp" + android:paddingRight="@dimen/card_padding" + android:paddingBottom="22dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_title_fragment"> + + <TextView + android:id="@+id/tv_email" + style="@style/TextAppearance.LabelSmall" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textColor="@color/md_theme_surface" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/tv_balance" + style="@style/TextAppearance.LabelLargeBold" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/balance" + android:textColor="@color/md_theme_surface" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_email" /> + + <TextView + android:id="@+id/tv_balance_nominal" + style="@style/TextAppearance.TitleLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textColor="@color/md_theme_surface" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_balance" /> + + + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/constraintLayout2" + android:layout_width="match_parent" + android:layout_height="580dp" + app:layout_constraintVertical_bias="0" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/constraintLayout"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/rvTransaction" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginBottom="40dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent"/> + + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/fab_create_transaction" + style="@style/FloatingActionButtonStyle" + android:layout_width="60dp" + android:layout_height="60dp" + android:layout_marginBottom="30dp" + android:clickable="true" + app:backgroundTint="@color/md_theme_primary" + android:contentDescription="@string/cd_transaction_create" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:srcCompat="@drawable/ic_add" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/cl_empty_rv" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/constraintLayout" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + android:visibility="gone" + > + + <ImageView + android:id="@+id/iv_no_data" + android:layout_width="300dp" + android:layout_height="300dp" + android:layout_marginTop="20dp" + android:contentDescription="@string/cd_transaction_empty" + android:src="@drawable/no_data_cuate" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + + <TextView + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:text="@string/msg_empty_transaction" + android:textColor="@color/md_theme_tertiary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/iv_no_data" + /> + </androidx.constraintlayout.widget.ConstraintLayout> +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_transaction_create.xml b/app/src/main/res/layout/fragment_transaction_create.xml new file mode 100644 index 0000000000000000000000000000000000000000..eeafc7e8e1d10363d10a2c303e927400f8f0290c --- /dev/null +++ b/app/src/main/res/layout/fragment_transaction_create.xml @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingHorizontal="@dimen/fragment_horizontal_padding" + tools:context=".view.transaction.CreateTransactionFragment"> + + <TextView + android:id="@+id/tv_transaction_new" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/title_top_margin" + android:text="@string/title_transaction_new" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/cl_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="30dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_new"> + + <TextView + android:id="@+id/tv_transaction_title" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/label_transaction" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/tf_transaction_name" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_transaction_new" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_title"> + + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_transaction_name" + style="@style/TextAppearance.BodyLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textColor="@color/md_theme_primary" + android:maxLength="50" + android:inputType="text" /> + + </com.google.android.material.textfield.TextInputLayout> + + <TextView + android:id="@+id/tv_transaction_price" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/label_price" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tf_transaction_name" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/tf_transaction_price" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_transaction_price" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_price"> + + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_transaction_price" + style="@style/TextAppearance.BodyLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="number" + android:maxLength="9" + android:textColor="@color/md_theme_primary" + /> + </com.google.android.material.textfield.TextInputLayout> + + + <TextView + android:id="@+id/tv_transaction_location" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/label_location" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/rg_category" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/tf_transaction_location" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_transaction_location" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_location"> + + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_transaction_location" + style="@style/TextAppearance.BodyLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:maxLength="150" + android:textColor="@color/md_theme_primary"/> + </com.google.android.material.textfield.TextInputLayout> + + <TextView + android:id="@+id/tv_transaction_category" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/label_category" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tf_transaction_price" /> + + <RadioGroup + android:id="@+id/rg_category" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:orientation="horizontal" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_transaction_category"> + + <RadioButton + android:id="@+id/rb_pembelian" + style="@style/TextAppearance.LabelLarge" + android:layout_width="155dp" + android:layout_height="wrap_content" + android:text="@string/label_pembelian" + android:buttonTint="@color/md_theme_primary" + android:textColor="@color/md_theme_primary" /> + + <RadioButton + android:id="@+id/rb_pemasukan" + style="@style/TextAppearance.LabelLarge" + android:layout_width="155dp" + android:layout_height="wrap_content" + android:text="@string/label_pemasukan" + android:buttonTint="@color/md_theme_primary" + android:textColor="@color/md_theme_primary" /> + </RadioGroup> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/cl_field"> + + <Button + android:id="@+id/btn_cancel" + android:layout_width="150dp" + android:layout_height="wrap_content" + android:text="@string/btn_cancel" + style="@style/buttonStyleDanger" + app:backgroundTint="@null" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@+id/btn_submit" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.0" /> + + <Button + android:id="@+id/btn_submit" + android:layout_width="150dp" + android:layout_height="wrap_content" + style="@style/buttonStylePrimary" + android:text="@string/btn_submit" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_transaction_edit.xml b/app/src/main/res/layout/fragment_transaction_edit.xml new file mode 100644 index 0000000000000000000000000000000000000000..52a007704d425ee2776eecea938b139554b7c00d --- /dev/null +++ b/app/src/main/res/layout/fragment_transaction_edit.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingHorizontal="@dimen/fragment_horizontal_padding" + tools:context=".view.transaction.EditTransactionFragment"> + + <TextView + android:id="@+id/tv_transaction_edit" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/title_top_margin" + android:text="@string/title_transaction_new" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/cl_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="30dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_edit"> + + <TextView + android:id="@+id/tv_transaction_title" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/label_transaction" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/tf_transaction_name" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_transaction_new" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_title"> + + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_transaction_name" + style="@style/TextAppearance.BodyLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textColor="@color/md_theme_primary" + android:maxLength="50" + android:inputType="text" /> + + </com.google.android.material.textfield.TextInputLayout> + + <TextView + android:id="@+id/tv_transaction_price" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/label_price" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tf_transaction_name" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/tf_transaction_price" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_transaction_price" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_price"> + + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_transaction_price" + style="@style/TextAppearance.BodyLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="number" + android:maxLength="9" + android:textColor="@color/md_theme_primary"/> + + </com.google.android.material.textfield.TextInputLayout> + + + <TextView + android:id="@+id/tv_transaction_location" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/label_location" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/rg_category" /> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/tf_transaction_location" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:hint="@string/hint_transaction_location" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_transaction_location"> + + <!--This is the actual edit text which takes the input--> + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/et_transaction_location" + style="@style/TextAppearance.BodyLarge" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:maxLength="150" + android:textColor="@color/md_theme_primary" + /> + + </com.google.android.material.textfield.TextInputLayout> + + <TextView + android:id="@+id/tv_transaction_category" + style="@style/TextAppearance.LabelLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="@string/label_category" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tf_transaction_price" /> + + <RadioGroup + android:id="@+id/rg_category" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:orientation="horizontal" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_transaction_category"> + + <RadioButton + android:id="@+id/rb_pembelian" + style="@style/TextAppearance.LabelLarge" + android:layout_width="155dp" + android:layout_height="wrap_content" + android:text="@string/label_pembelian" + android:textColor="@color/md_theme_primary" /> + + <RadioButton + android:id="@+id/rb_pemasukan" + style="@style/TextAppearance.LabelLarge" + android:layout_width="155dp" + android:layout_height="wrap_content" + android:text="@string/label_pemasukan" + android:textColor="@color/md_theme_primary" /> + </RadioGroup> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/cl_field"> + + <Button + android:id="@+id/btn_cancel" + android:layout_width="150dp" + android:layout_height="wrap_content" + android:text="@string/btn_cancel" + style="@style/buttonStyleDanger" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@+id/btn_submit" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.0" /> + + <Button + android:id="@+id/btn_submit" + android:layout_width="150dp" + android:layout_height="wrap_content" + style="@style/buttonStylePrimary" + android:text="@string/btn_submit" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_twibbon.xml b/app/src/main/res/layout/fragment_twibbon.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac37b109c61ee31b426092faffdb73b47475c0d7 --- /dev/null +++ b/app/src/main/res/layout/fragment_twibbon.xml @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:background="@color/md_theme_surface" + android:layout_height="match_parent" + tools:context=".view.twibbon.TwibbonFragment" + > + <TextView + android:id="@+id/tv_title_fragment" + style="@style/TextAppearance.HeadlineLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/title_start_margin" + android:layout_marginTop="@dimen/title_top_margin" + android:text="@string/title_twibbon" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <androidx.cardview.widget.CardView + android:id="@+id/cardView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="60dp" + app:cardCornerRadius="50dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_title_fragment"> + + <androidx.camera.view.PreviewView + android:id="@+id/viewFinder" + android:layout_width="330dp" + android:layout_height="330dp" + app:layout_constraintBottom_toTopOf="@id/twibbon1" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + > + + <ImageView + android:id="@+id/twibbon1" + android:layout_width="330dp" + android:layout_height="330dp" + android:src="@drawable/twibbon_soobim" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + android:contentDescription="@string/cd_twibon_soobin" + app:layout_constraintTop_toBottomOf="@+id/viewFinder" /> + + <ImageView + android:id="@+id/twibbon2" + android:layout_width="330dp" + android:layout_height="330dp" + android:src="@drawable/twibbon_faker" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + android:contentDescription="@string/cd_twibon_faker" + app:layout_constraintTop_toBottomOf="@+id/viewFinder" /> + </FrameLayout> + + + </androidx.cardview.widget.CardView> + + + <androidx.appcompat.widget.AppCompatButton + android:id="@+id/shutter" + android:layout_width="57dp" + android:layout_height="57dp" + android:layout_marginBottom="112dp" + android:background="@drawable/round_button_blue" + android:elevation="2dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + android:text="@string/label_shutter" + android:textColor="@color/md_theme_primary" + android:tooltipText="@string/label_shutter" + /> + + <Button + android:id="@+id/buttonRetake" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="112dp" + android:text="@string/btn_retake" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + + <ImageButton + android:id="@+id/imageButtonSoobin" + android:layout_width="72dp" + android:layout_height="72dp" + android:layout_marginStart="76dp" + android:layout_marginTop="72dp" + android:src="@drawable/ic_twibbon_soobin" + android:scaleType="fitCenter" + android:backgroundTint="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + android:contentDescription="@string/cd_twibon_soobin" + app:layout_constraintTop_toBottomOf="@+id/cardView" /> + + <ImageButton + android:id="@+id/imageButtonFaker" + android:layout_width="72dp" + android:layout_height="72dp" + android:layout_marginTop="72dp" + android:layout_marginEnd="84dp" + android:contentDescription="@string/cd_twibon_faker" + android:src="@drawable/ic_twibbon_faker" + android:backgroundTint="@color/md_theme_primary" + app:layout_constraintEnd_toEndOf="parent" + android:scaleType="fitCenter" + app:layout_constraintHorizontal_bias="0.971" + app:layout_constraintStart_toEndOf="@+id/imageButtonSoobin" + app:layout_constraintTop_toBottomOf="@+id/cardView" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/item_transaction.xml b/app/src/main/res/layout/item_transaction.xml new file mode 100644 index 0000000000000000000000000000000000000000..290cc35561d1113c806998af0fec3991d8f4e99b --- /dev/null +++ b/app/src/main/res/layout/item_transaction.xml @@ -0,0 +1,146 @@ +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/vertical_gap" + android:background="@drawable/bg_transaction_card_view" + android:padding="@dimen/card_padding"> + + <ImageView + android:id="@+id/img_icon_category" + android:layout_width="32dp" + android:layout_height="32dp" + android:background="@drawable/bg_transaction_icon" + android:contentDescription="@string/transaction_category" + android:padding="5dp" + android:src="@drawable/ic_money_bill_wave" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:tint="@color/md_theme_primary" /> + + <TextView + android:id="@+id/tv_transaction_name" + style="@style/TextAppearance.TitleSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxWidth="140dp" + android:layout_marginStart="10dp" + android:ellipsize="end" + android:maxLines="2" + android:text="@string/transaction_name" + android:textColor="@color/md_theme_primary" + android:textStyle="bold" + app:layout_constraintStart_toEndOf="@+id/img_icon_category" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" /> + + <TextView + android:id="@+id/tv_transaction_category" + style="@style/TextAppearance.LabelMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:ellipsize="end" + android:maxLines="1" + android:text="@string/transaction_category" + android:textColor="@color/md_theme_primary" + app:layout_constraintStart_toEndOf="@+id/img_icon_category" + app:layout_constraintTop_toBottomOf="@+id/tv_transaction_name" /> + + <TextView + android:id="@+id/tv_transaction_date" + style="@style/TextAppearance.LabelSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:ellipsize="end" + android:maxLines="1" + android:text="@string/transaction_date" + android:textColor="@color/md_theme_onSurface" + app:layout_constraintStart_toEndOf="@+id/img_icon_category" + app:layout_constraintTop_toBottomOf="@+id/tv_transaction_category" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/locationLayout" + android:layout_marginTop="10dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_transaction_date" + > + <ImageView + android:id="@+id/iv_location" + android:layout_width="14dp" + android:layout_height="14dp" + android:layout_marginTop="2dp" + android:contentDescription="@string/transaction_category" + android:src="@drawable/ic_location" + app:tint="@color/md_theme_primary" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <TextView + android:id="@+id/tv_transaction_location" + style="@style/TextAppearance.LabelSmall" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="4dp" + android:gravity="start" + android:text="@string/transaction_location" + android:textColor="@color/md_theme_primary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@+id/iv_location" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + +<!-- <ImageView--> +<!-- android:id="@+id/img_icon_value"--> +<!-- android:layout_width="20dp"--> +<!-- android:layout_height="20dp"--> +<!-- android:contentDescription="@string/transaction_category"--> +<!-- android:padding="2dp"--> +<!-- android:src="@drawable/ic_remove"--> +<!-- app:layout_constraintEnd_toStartOf="@+id/tv_transaction_amount"--> +<!-- app:layout_constraintHorizontal_bias="0.5"--> +<!-- app:layout_constraintHorizontal_chainStyle="packed"--> +<!-- app:layout_constraintTop_toTopOf="parent"--> +<!-- app:tint="@color/md_theme_red" />--> + +<!-- <TextView--> +<!-- android:id="@+id/tv_currency"--> +<!-- style="@style/TextAppearance.LabelLarge"--> +<!-- android:layout_width="wrap_content"--> +<!-- android:layout_height="wrap_content"--> +<!-- android:ellipsize="end"--> +<!-- android:maxLines="1"--> +<!-- android:text="@string/label_mata_uang"--> +<!-- android:textColor="@color/md_theme_primary"--> +<!-- app:layout_constraintEnd_toStartOf="@+id/tv_transaction_amount"--> +<!-- app:layout_constraintHorizontal_bias="0.5"--> +<!-- app:layout_constraintTop_toTopOf="parent" />--> + + <TextView + android:id="@+id/tv_transaction_amount" + style="@style/TextAppearance.LabelMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="start" + android:singleLine="true" + android:text="@string/transaction_price" + android:textColor="@color/md_theme_red" + app:layout_constraintEnd_toStartOf="@+id/img_more_action" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintTop_toTopOf="parent" /> + + <ImageView + android:id="@+id/img_more_action" + android:layout_width="30dp" + android:layout_height="30dp" + android:contentDescription="@string/cd_transaction_modify" + android:src="@drawable/ic_more" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:tint="@color/md_theme_onSurface" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index fb6d040b9a026ddaa05df0e530ab6f95e6c1f999..e98be4655ae7a013b38122570821f359fb76630e 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -2,18 +2,27 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item - android:id="@+id/navigation_home" - android:icon="@drawable/ic_home_black_24dp" - android:title="@string/title_home" /> + android:id="@+id/navigation_transaction" + android:icon="@drawable/ic_transaction" + android:enabled="true" + android:title="@string/title_transactions" /> <item - android:id="@+id/navigation_dashboard" - android:icon="@drawable/ic_dashboard_black_24dp" - android:title="@string/title_dashboard" /> - + android:id="@+id/navigation_scan" + android:icon="@drawable/ic_scan" + android:title="@string/title_scan" + /> <item - android:id="@+id/navigation_notifications" - android:icon="@drawable/ic_notifications_black_24dp" - android:title="@string/title_notifications" /> - + android:id="@+id/navigation_twibbon" + android:icon="@drawable/ic_twibbon" + android:title="@string/title_twibbon" + /> + <item + android:id="@+id/navigation_graph" + android:icon="@drawable/ic_graph" + android:title="@string/title_chart" /> + <item + android:id="@+id/navigation_settings" + android:icon="@drawable/ic_settings" + android:title="@string/title_settings" /> </menu> \ No newline at end of file diff --git a/app/src/main/res/menu/transaction_menu.xml b/app/src/main/res/menu/transaction_menu.xml new file mode 100644 index 0000000000000000000000000000000000000000..e747626a13ac62364a4ff9616a23b30175a6e4dd --- /dev/null +++ b/app/src/main/res/menu/transaction_menu.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:title="@string/title_edit_transaction" + android:id="@+id/edit_transaction" + android:icon="@drawable/ic_edit" + /> + <item android:title="@string/title_delete_transaction" + android:id="@+id/delete_transaction" + android:icon="@drawable/ic_delete" /> +</menu> \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 56% rename from app/src/main/res/mipmap-anydpi/ic_launcher.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 6f3b755bf50c6b03d8714a9c6184705e6a08389f..c4a603d4cce78b2fbd8094bd0224d4778bc8c976 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> - <background android:drawable="@drawable/ic_launcher_background" /> - <foreground android:drawable="@drawable/ic_launcher_foreground" /> - <monochrome android:drawable="@drawable/ic_launcher_foreground" /> + <background android:drawable="@drawable/ic_launcher_background"/> + <foreground android:drawable="@mipmap/ic_launcher_foreground"/> </adaptive-icon> \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 56% rename from app/src/main/res/mipmap-anydpi/ic_launcher_round.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 6f3b755bf50c6b03d8714a9c6184705e6a08389f..c4a603d4cce78b2fbd8094bd0224d4778bc8c976 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> - <background android:drawable="@drawable/ic_launcher_background" /> - <foreground android:drawable="@drawable/ic_launcher_foreground" /> - <monochrome android:drawable="@drawable/ic_launcher_foreground" /> + <background android:drawable="@drawable/ic_launcher_background"/> + <foreground android:drawable="@mipmap/ic_launcher_foreground"/> </adaptive-icon> \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp index c209e78ecd372343283f4157dcfd918ec5165bb3..239f3c0f17c76ac077d0d339b1814698c0dea08f 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..2fdda8498c8999e042bda1845f5b87b3b658fa3c Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index b2dfe3d1ba5cf3ee31b3ecc1ced89044a1f3b7a9..f7f51f0edd371e7e03fb6898a360ef2a6256e1c2 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp index 4f0f1d64e58ba64d180ce43ee13bf9a17835fbca..eaf4b5bf37f59aba5e7e92c0663a9243486180d7 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..0e55d34aa1c2932d4f1112254a3a780899aef4f5 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 62b611da081676d42f6c3f78a2c91e7bcedddedb..723547cc6adad38b7d2ea1e45b5a0d86cb3d46e6 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 948a3070fe34c611c42c0d3ad3013a0dce358be0..b556dc3d0d843fe0629ad93f98b3dc05f3dfaa9b 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..db088ff97f6c72701c1760cc8d5e5c3092f994a4 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 1b9a6956b3acdc11f40ce2bb3f6efbd845cc243f..34a2eb42fceae4313d595c2af2e7e19641b22e7c 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 28d4b77f9f036a47549d47db79c16788749dca10..c9422ca43fb62fc8868968b4841f4e4f89d4af3f 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..ce9878ba6303a7a2aaa01488f5128751865cfabf Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index 9287f5083623b375139afb391af71cc533a7dd37..6007a74466ea7475ae6cab377956f2fc477729c1 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index aa7d6427e6fa1074b79ccd52ef67ac15c5637e85..6d10043853328c276b744de7488ce4892ee37a5f 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..b6babe43e1daa208ba91280d0539b44068d9264e Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 9126ae37cbc3587421d6889eadd1d91fbf1994d4..18ffa6164ceea0f6deb91f97330ab902a8905193 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 096bfed79d1d61e37a42e42752aa6a44c38cffdf..c61f52eb11e27b9feb991ee44c3775ba00697024 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -3,23 +3,133 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/mobile_navigation" - app:startDestination="@+id/navigation_home"> + app:startDestination="@id/fragment_login"> <fragment - android:id="@+id/navigation_home" - android:name="com.example.bandung_bondowoso.ui.home.HomeFragment" - android:label="@string/title_home" - tools:layout="@layout/fragment_home" /> + android:id="@+id/navigation_transaction" + android:name="com.example.bandung_bondowoso.view.transaction.TransactionFragment" + android:label="@string/title_transactions" + tools:layout="@layout/fragment_transaction" > + <action + android:id="@+id/action_navigation_transaction_to_newTransactionFragment" + app:destination="@id/newTransactionFragment" + android:label="Transaksi Baru" + /> + <action + android:id="@+id/action_navigation_transaction_to_editTransactionFragment" + app:destination="@id/editTransactionFragment" /> + </fragment> + <fragment + android:id = "@+id/scan_result" + android:name = "com.example.bandung_bondowoso.view.scan.ScanResultFragment" + android:label = "ScanResult" + tools:layout="@layout/fragment_scan_result"> + <action + android:id = "@+id/action_navigation_result_to_scan" + app:destination="@id/navigation_scan"/> + <action + android:id = "@+id/action_navigation_result_to_transaction" + app:destination="@id/newTransactionFragment" /> + + </fragment> + + <fragment + android:id = "@+id/camera_scan" + android:name = "com.example.bandung_bondowoso.view.scan.ScanFragment" + android:label = "CameraScan" + tools:layout="@layout/fragment_scan"> + <action + android:id = "@+id/action_navigation_camera_to_result" + app:destination="@id/scan_result" + /> + </fragment> + <fragment + android:id="@+id/navigation_scan" + android:name="com.example.bandung_bondowoso.view.scan.ScanHomeFragment" + android:label="@string/title_scan" + tools:layout="@layout/fragment_scan_home"> + <action + android:id = "@+id/action_navigation_scan_to_camera_scan" + app:destination = "@id/camera_scan" + /> + <action + android:id = "@+id/action_navigation_scan_to_result" + app:destination="@id/scan_result" /> + </fragment> + + + <fragment + android:id = "@+id/navigation_settings" + android:name= "com.example.bandung_bondowoso.view.setting.SettingFragment" + android:label="Settings" + tools:layout="@layout/fragment_settings" > + <action + android:id="@+id/action_navigation_settings_to_newTransactionFragment" + app:destination="@id/newTransactionFragment" /> + </fragment> <fragment - android:id="@+id/navigation_dashboard" - android:name="com.example.bandung_bondowoso.ui.dashboard.DashboardFragment" - android:label="@string/title_dashboard" - tools:layout="@layout/fragment_dashboard" /> + android:id="@+id/fragment_login" + android:name="com.example.bandung_bondowoso.view.login.LoginFragment" + android:label="fragment_login" + tools:layout="@layout/fragment_login" > + <action + android:id="@+id/action_fragment_login_to_noNetworkFragment" + app:destination="@id/noNetworkFragment" + app:popUpTo="@id/mobile_navigation" + app:popUpToInclusive="true" + /> + <action + android:id="@+id/action_fragment_login_to_navigation_transaction" + app:destination="@id/navigation_transaction" + app:popUpTo="@id/mobile_navigation" + app:popUpToInclusive="true" + /> + </fragment> + <fragment + android:id="@+id/newTransactionFragment" + android:name="com.example.bandung_bondowoso.view.transaction.CreateTransactionFragment" + android:label="fragment_transaction_create" + tools:layout="@layout/fragment_transaction_create" > + <action + android:id="@+id/action_newTransactionFragment_to_navigation_transaction" + app:destination="@id/navigation_transaction" /> + </fragment> <fragment - android:id="@+id/navigation_notifications" - android:name="com.example.bandung_bondowoso.ui.notifications.NotificationsFragment" - android:label="@string/title_notifications" - tools:layout="@layout/fragment_notifications" /> + android:id="@+id/navigation_graph" + android:name="com.example.bandung_bondowoso.view.graph.GraphFragment" + android:label="GraphFragment" + tools:layout="@layout/fragment_graph" + /> + <fragment + android:id="@+id/editTransactionFragment" + android:name="com.example.bandung_bondowoso.view.transaction.EditTransactionFragment" + android:label="fragment_transaction_edit" + tools:layout="@layout/fragment_transaction_edit" > + <action + android:id="@+id/action_editTransactionFragment_to_navigation_transaction" + app:destination="@id/navigation_transaction" /> + <argument + android:name="transactionId" + app:argType="integer" /> + </fragment> + <fragment + android:id="@+id/noNetworkFragment" + android:name="com.example.bandung_bondowoso.view.network.NoNetworkFragment" + android:label="NoNetworkFragment" > + <action + android:id="@+id/action_noNetworkFragment_to_fragment_login" + app:destination="@id/fragment_login" + app:popUpTo="@id/mobile_navigation" + app:popUpToInclusive="true" + /> + </fragment> + <fragment + android:id="@+id/navigation_twibbon" + android:name="com.example.bandung_bondowoso.view.twibbon.TwibbonFragment" + android:label="fragment_twibbon" + tools:layout="@layout/fragment_twibbon" /> + + </navigation> \ No newline at end of file diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml new file mode 100644 index 0000000000000000000000000000000000000000..993be82593165eab34c4d40d0f784b060ac47f0b --- /dev/null +++ b/app/src/main/res/values-night/colors.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="md_theme_primary">#2E8CFF</color> + <color name="md_theme_onPrimary">#242B61</color> + <color name="md_theme_primaryContainer">#0819B6</color> + <color name="md_theme_onPrimaryContainer">#DFE0FF</color> + <color name="md_theme_red">#BE0707</color> + <color name="md_theme_green">#44C34A</color> + <color name="md_theme_peach">#F12BFF</color> + <color name="md_theme_light_green">#3B4279</color> + <color name="md_theme_blue">#ADC7FF</color> + <color name="md_theme_secondary">#BCC3FF</color> + <color name="md_theme_onSecondary">#242C61</color> + <color name="md_theme_secondaryContainer">#3B4279</color> + <color name="md_theme_onSecondaryContainer">#DFE0FF</color> + <color name="md_theme_tertiary">#ADC7FF</color> + <color name="md_theme_onTertiary">#0F2F60</color> + <color name="md_theme_tertiaryContainer">#2A4678</color> + <color name="md_theme_onTertiaryContainer">#D8E2FF</color> + <color name="md_theme_error">#FFB4AB</color> + <color name="md_theme_onError">#561E19</color> + <color name="md_theme_errorContainer">#73332D</color> + <color name="md_theme_onErrorContainer">#FFDAD6</color> + <color name="md_theme_background">#131318</color> + <color name="md_theme_onBackground">#E4E1E9</color> + <color name="md_theme_surface">#0D1931</color> + <color name="md_theme_onSurface">#E4E1E9</color> + <color name="md_theme_surfaceVariant">#46464F</color> + <color name="md_theme_onSurfaceVariant">#C7C5D0</color> + <color name="md_theme_outline">#90909A</color> + <color name="md_theme_outlineVariant">#46464F</color> + <color name="md_theme_scrim">#000000</color> + <color name="md_theme_inverseSurface">#E4E1E9</color> + <color name="md_theme_inverseOnSurface">#303036</color> + <color name="md_theme_inversePrimary">#535A92</color> + <color name="md_theme_primaryFixed">#DFE0FF</color> + <color name="md_theme_onPrimaryFixed">#0D154B</color> + <color name="md_theme_primaryFixedDim">#BCC3FF</color> + <color name="md_theme_onPrimaryFixedVariant">#3B4279</color> + <color name="md_theme_secondaryFixed">#DFE0FF</color> + <color name="md_theme_onSecondaryFixed">#0D154B</color> + <color name="md_theme_secondaryFixedDim">#BCC3FF</color> + <color name="md_theme_onSecondaryFixedVariant">#3B4279</color> + <color name="md_theme_tertiaryFixed">#D8E2FF</color> + <color name="md_theme_onTertiaryFixed">#001A41</color> + <color name="md_theme_tertiaryFixedDim">#ADC7FF</color> + <color name="md_theme_onTertiaryFixedVariant">#2A4678</color> + <color name="md_theme_surfaceDim">#131318</color> + <color name="md_theme_surfaceBright">#39393F</color> + <color name="md_theme_surfaceContainerLowest">#0D0E13</color> + <color name="md_theme_surfaceContainerLow">#1B1B21</color> + <color name="md_theme_surfaceContainer">#070C1F</color> + <color name="md_theme_surfaceContainerHigh">#29292F</color> + <color name="md_theme_surfaceContainerHighest">#34343A</color> + <color name="md_theme_primary_mediumContrast">#C1C7FF</color> + <color name="md_theme_onPrimary_mediumContrast">#060F46</color> + <color name="md_theme_primaryContainer_mediumContrast">#858DC8</color> + <color name="md_theme_onPrimaryContainer_mediumContrast">#000000</color> + <color name="md_theme_secondary_mediumContrast">#C1C7FF</color> + <color name="md_theme_onSecondary_mediumContrast">#060F46</color> + <color name="md_theme_secondaryContainer_mediumContrast">#858DC8</color> + <color name="md_theme_onSecondaryContainer_mediumContrast">#000000</color> + <color name="md_theme_tertiary_mediumContrast">#B3CBFF</color> + <color name="md_theme_onTertiary_mediumContrast">#001537</color> + <color name="md_theme_tertiaryContainer_mediumContrast">#7691C7</color> + <color name="md_theme_onTertiaryContainer_mediumContrast">#000000</color> + <color name="md_theme_error_mediumContrast">#FFBAB2</color> + <color name="md_theme_onError_mediumContrast">#330404</color> + <color name="md_theme_errorContainer_mediumContrast">#CC7B72</color> + <color name="md_theme_onErrorContainer_mediumContrast">#000000</color> + <color name="md_theme_background_mediumContrast">#131318</color> + <color name="md_theme_onBackground_mediumContrast">#E4E1E9</color> + <color name="md_theme_surface_mediumContrast">#131318</color> + <color name="md_theme_onSurface_mediumContrast">#FDF9FF</color> + <color name="md_theme_surfaceVariant_mediumContrast">#46464F</color> + <color name="md_theme_onSurfaceVariant_mediumContrast">#CBC9D4</color> + <color name="md_theme_outline_mediumContrast">#A3A2AC</color> + <color name="md_theme_outlineVariant_mediumContrast">#83828C</color> + <color name="md_theme_scrim_mediumContrast">#000000</color> + <color name="md_theme_inverseSurface_mediumContrast">#E4E1E9</color> + <color name="md_theme_inverseOnSurface_mediumContrast">#29292F</color> + <color name="md_theme_inversePrimary_mediumContrast">#3C447A</color> + <color name="md_theme_primaryFixed_mediumContrast">#DFE0FF</color> + <color name="md_theme_onPrimaryFixed_mediumContrast">#010841</color> + <color name="md_theme_primaryFixedDim_mediumContrast">#BCC3FF</color> + <color name="md_theme_onPrimaryFixedVariant_mediumContrast">#2A3167</color> + <color name="md_theme_secondaryFixed_mediumContrast">#DFE0FF</color> + <color name="md_theme_onSecondaryFixed_mediumContrast">#010841</color> + <color name="md_theme_secondaryFixedDim_mediumContrast">#BCC3FF</color> + <color name="md_theme_onSecondaryFixedVariant_mediumContrast">#2A3167</color> + <color name="md_theme_tertiaryFixed_mediumContrast">#D8E2FF</color> + <color name="md_theme_onTertiaryFixed_mediumContrast">#00102D</color> + <color name="md_theme_tertiaryFixedDim_mediumContrast">#ADC7FF</color> + <color name="md_theme_onTertiaryFixedVariant_mediumContrast">#173566</color> + <color name="md_theme_surfaceDim_mediumContrast">#131318</color> + <color name="md_theme_surfaceBright_mediumContrast">#39393F</color> + <color name="md_theme_surfaceContainerLowest_mediumContrast">#0D0E13</color> + <color name="md_theme_surfaceContainerLow_mediumContrast">#1B1B21</color> + <color name="md_theme_surfaceContainer_mediumContrast">#1F1F25</color> + <color name="md_theme_surfaceContainerHigh_mediumContrast">#29292F</color> + <color name="md_theme_surfaceContainerHighest_mediumContrast">#34343A</color> + <color name="md_theme_primary_highContrast">#FDF9FF</color> + <color name="md_theme_onPrimary_highContrast">#000000</color> + <color name="md_theme_primaryContainer_highContrast">#C1C7FF</color> + <color name="md_theme_onPrimaryContainer_highContrast">#000000</color> + <color name="md_theme_secondary_highContrast">#FDF9FF</color> + <color name="md_theme_onSecondary_highContrast">#000000</color> + <color name="md_theme_secondaryContainer_highContrast">#C1C7FF</color> + <color name="md_theme_onSecondaryContainer_highContrast">#000000</color> + <color name="md_theme_tertiary_highContrast">#FBFAFF</color> + <color name="md_theme_onTertiary_highContrast">#000000</color> + <color name="md_theme_tertiaryContainer_highContrast">#B3CBFF</color> + <color name="md_theme_onTertiaryContainer_highContrast">#000000</color> + <color name="md_theme_error_highContrast">#FFF9F9</color> + <color name="md_theme_onError_highContrast">#000000</color> + <color name="md_theme_errorContainer_highContrast">#FFBAB2</color> + <color name="md_theme_onErrorContainer_highContrast">#000000</color> + <color name="md_theme_background_highContrast">#131318</color> + <color name="md_theme_onBackground_highContrast">#E4E1E9</color> + <color name="md_theme_surface_highContrast">#131318</color> + <color name="md_theme_onSurface_highContrast">#FFFFFF</color> + <color name="md_theme_surfaceVariant_highContrast">#46464F</color> + <color name="md_theme_onSurfaceVariant_highContrast">#FDF9FF</color> + <color name="md_theme_outline_highContrast">#CBC9D4</color> + <color name="md_theme_outlineVariant_highContrast">#CBC9D4</color> + <color name="md_theme_scrim_highContrast">#000000</color> + <color name="md_theme_inverseSurface_highContrast">#E4E1E9</color> + <color name="md_theme_inverseOnSurface_highContrast">#000000</color> + <color name="md_theme_inversePrimary_highContrast">#1D255A</color> + <color name="md_theme_primaryFixed_highContrast">#E4E5FF</color> + <color name="md_theme_onPrimaryFixed_highContrast">#000000</color> + <color name="md_theme_primaryFixedDim_highContrast">#C1C7FF</color> + <color name="md_theme_onPrimaryFixedVariant_highContrast">#060F46</color> + <color name="md_theme_secondaryFixed_highContrast">#E4E5FF</color> + <color name="md_theme_onSecondaryFixed_highContrast">#000000</color> + <color name="md_theme_secondaryFixedDim_highContrast">#C1C7FF</color> + <color name="md_theme_onSecondaryFixedVariant_highContrast">#060F46</color> + <color name="md_theme_tertiaryFixed_highContrast">#DEE7FF</color> + <color name="md_theme_onTertiaryFixed_highContrast">#000000</color> + <color name="md_theme_tertiaryFixedDim_highContrast">#B3CBFF</color> + <color name="md_theme_onTertiaryFixedVariant_highContrast">#001537</color> + <color name="md_theme_surfaceDim_highContrast">#131318</color> + <color name="md_theme_surfaceBright_highContrast">#39393F</color> + <color name="md_theme_surfaceContainerLowest_highContrast">#0D0E13</color> + <color name="md_theme_surfaceContainerLow_highContrast">#1B1B21</color> + <color name="md_theme_surfaceContainer_highContrast">#1F1F25</color> + <color name="md_theme_surfaceContainerHigh_highContrast">#29292F</color> + <color name="md_theme_surfaceContainerHighest_highContrast">#34343A</color> + <color name="textColor">#ffffff</color> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 6abbca92cac6b98b8e9445e6ca50c70a55203ad2..a3598177e57cf34155c5eafa2c6da739717667c8 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -1,16 +1,162 @@ <resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> - <style name="Theme.BandungBondowoso" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> - <!-- Primary brand color. --> - <item name="colorPrimary">@color/purple_200</item> - <item name="colorPrimaryVariant">@color/purple_700</item> - <item name="colorOnPrimary">@color/black</item> - <!-- Secondary brand color. --> - <item name="colorSecondary">@color/teal_200</item> - <item name="colorSecondaryVariant">@color/teal_200</item> - <item name="colorOnSecondary">@color/black</item> - <!-- Status bar color. --> - <item name="android:statusBarColor">?attr/colorPrimaryVariant</item> - <!-- Customize your theme here. --> + <style name="Theme.BandungBondowoso" parent="Theme.MaterialComponents.DayNight.NoActionBar"> + <item name="colorPrimary">@color/md_theme_primary</item> + <item name="colorOnPrimary">@color/md_theme_onPrimary</item> + <item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item> + <item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item> + <item name="colorSecondary">@color/md_theme_secondary</item> + <item name="colorOnSecondary">@color/md_theme_onSecondary</item> + <item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item> + <item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item> + <item name="colorTertiary">@color/md_theme_tertiary</item> + <item name="colorOnTertiary">@color/md_theme_onTertiary</item> + <item name="colorTertiaryContainer">@color/md_theme_tertiaryContainer</item> + <item name="colorOnTertiaryContainer">@color/md_theme_onTertiaryContainer</item> + <item name="colorError">@color/md_theme_error</item> + <item name="colorOnError">@color/md_theme_onError</item> + <item name="colorErrorContainer">@color/md_theme_errorContainer</item> + <item name="colorOnErrorContainer">@color/md_theme_onErrorContainer</item> + <item name="android:colorBackground">@color/md_theme_background</item> + <item name="colorOnBackground">@color/md_theme_onBackground</item> + <item name="colorSurface">@color/md_theme_surface</item> + <item name="colorOnSurface">@color/md_theme_onSurface</item> + <item name="colorSurfaceVariant">@color/md_theme_surfaceVariant</item> + <item name="colorOnSurfaceVariant">@color/md_theme_onSurfaceVariant</item> + <item name="colorOutline">@color/md_theme_outline</item> + <item name="colorOutlineVariant">@color/md_theme_outlineVariant</item> + <item name="colorSurfaceInverse">@color/md_theme_inverseSurface</item> + <item name="colorOnSurfaceInverse">@color/md_theme_inverseOnSurface</item> + <item name="colorPrimaryInverse">@color/md_theme_inversePrimary</item> + <item name="colorPrimaryFixed">@color/md_theme_primaryFixed</item> + <item name="colorOnPrimaryFixed">@color/md_theme_onPrimaryFixed</item> + <item name="colorPrimaryFixedDim">@color/md_theme_primaryFixedDim</item> + <item name="colorOnPrimaryFixedVariant">@color/md_theme_onPrimaryFixedVariant</item> + <item name="colorSecondaryFixed">@color/md_theme_secondaryFixed</item> + <item name="colorOnSecondaryFixed">@color/md_theme_onSecondaryFixed</item> + <item name="colorSecondaryFixedDim">@color/md_theme_secondaryFixedDim</item> + <item name="colorOnSecondaryFixedVariant">@color/md_theme_onSecondaryFixedVariant</item> + <item name="colorTertiaryFixed">@color/md_theme_tertiaryFixed</item> + <item name="colorOnTertiaryFixed">@color/md_theme_onTertiaryFixed</item> + <item name="colorTertiaryFixedDim">@color/md_theme_tertiaryFixedDim</item> + <item name="colorOnTertiaryFixedVariant">@color/md_theme_onTertiaryFixedVariant</item> + <item name="colorSurfaceDim">@color/md_theme_surfaceDim</item> + <item name="colorSurfaceBright">@color/md_theme_surfaceBright</item> + <item name="colorSurfaceContainerLowest">@color/md_theme_surfaceContainerLowest</item> + <item name="colorSurfaceContainerLow">@color/md_theme_surfaceContainerLow</item> + <item name="colorSurfaceContainer">@color/md_theme_surfaceContainer</item> + <item name="colorSurfaceContainerHigh">@color/md_theme_surfaceContainerHigh</item> + <item name="colorSurfaceContainerHighest">@color/md_theme_surfaceContainerHighest</item> + </style> + <!-- Display --> + <style name="TextAppearance.DisplayLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">57sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.DisplayMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">45sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.DisplaySmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">36sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <!-- Headline --> + <style name="TextAppearance.HeadlineLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">32sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.HeadlineMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">28sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.HeadlineSmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">24sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <!-- Title --> + <style name="TextAppearance.TitleLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">22sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.TitleMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">16sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.TitleSmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <!-- Label --> + <style name="TextAppearance.LabelLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.LabelMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">12sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.LabelSmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">11sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.LabelLargeBold" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <!-- Body --> + <style name="TextAppearance.BodyLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">16sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.BodyMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.BodySmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">12sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="BottomNavigationViewTextStyle"> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.05</item> + </style> + <!-- Floating Action Button --> + <style name="FloatingActionButtonStyle" parent="Widget.Design.FloatingActionButton"> + <item name="shapeAppearanceOverlay">@style/FABShapeStyleSquare</item> + </style> + <style name="FABShapeStyleSquare" parent="ShapeAppearance.MaterialComponents.SmallComponent"> + <item name="cornerSize">20%</item> + <item name="android:tint">@color/md_theme_primary</item> + <item name="android:backgroundTint">@color/md_theme_surface</item> + </style> + + <style name="buttonStylePrimary" parent="Widget.MaterialComponents.Button"> + <item name="android:background">@drawable/bg_button_primary</item> + </style> + + <style name="buttonStyleShutter" parent="Widget.MaterialComponents.Button"> + <item name="android:background">@drawable/round_button</item> + </style>zz + <style name="buttonStyleDanger" parent="Widget.MaterialComponents.Button"> + <item name="android:background">@drawable/bg_button_danger</item> + <item name="android:textColor">@color/white</item> </style> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f8c6127d327620c93d2b2d00342a68e97b98a48d..14cfa7e8d4d9b1d1306de6b0b3f8195fef03b594 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,10 +1,154 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <color name="purple_200">#FFBB86FC</color> - <color name="purple_500">#FF6200EE</color> - <color name="purple_700">#FF3700B3</color> - <color name="teal_200">#FF03DAC5</color> - <color name="teal_700">#FF018786</color> - <color name="black">#FF000000</color> - <color name="white">#FFFFFFFF</color> + <color name="md_theme_primary">#000E8E</color> + <color name="md_theme_primary_0">#00EFEDF4</color> + <color name="md_theme_primary_50">#33EFEDF4</color> + <color name="md_theme_onPrimary">#FFFFFF</color> + <color name="md_theme_red">#BE0707</color> + <color name="md_theme_green">#44C34A</color> + <color name="md_theme_peach">#FF639A</color> + <color name="md_theme_light_green">#C7ECC1</color> + <color name="md_theme_blue">#ADC7FF</color> + <color name="md_theme_primaryContainer">#DFE0FF</color> + <color name="md_theme_onPrimaryContainer">#0D154B</color> + <color name="md_theme_secondary">#535A92</color> + <color name="md_theme_onSecondary">#FFFFFF</color> + <color name="md_theme_secondaryContainer">#DFE0FF</color> + <color name="md_theme_onSecondaryContainer">#0D154B</color> + <color name="md_theme_tertiary">#435E91</color> + <color name="md_theme_onTertiary">#FFFFFF</color> + <color name="md_theme_tertiaryContainer">#D8E2FF</color> + <color name="md_theme_onTertiaryContainer">#001A41</color> + <color name="md_theme_error">#904A43</color> + <color name="md_theme_onError">#FFFFFF</color> + <color name="md_theme_errorContainer">#FFDAD6</color> + <color name="md_theme_onErrorContainer">#3B0907</color> + <color name="md_theme_background">#FBF8FF</color> + <color name="md_theme_onBackground">#1B1B21</color> + <color name="md_theme_surface">#FBF8FF</color> + <color name="md_theme_onSurface">#373740</color> + <color name="md_theme_surfaceVariant">#E3E1EC</color> + <color name="md_theme_onSurfaceVariant">#46464F</color> + <color name="md_theme_outline">#777680</color> + <color name="md_theme_outlineVariant">#C7C5D0</color> + <color name="md_theme_scrim">#000000</color> + <color name="md_theme_inverseSurface">#303036</color> + <color name="md_theme_inverseOnSurface">#F2EFF7</color> + <color name="md_theme_inversePrimary">#BCC3FF</color> + <color name="md_theme_primaryFixed">#DFE0FF</color> + <color name="md_theme_onPrimaryFixed">#0D154B</color> + <color name="md_theme_primaryFixedDim">#BCC3FF</color> + <color name="md_theme_onPrimaryFixedVariant">#3B4279</color> + <color name="md_theme_secondaryFixed">#DFE0FF</color> + <color name="md_theme_onSecondaryFixed">#0D154B</color> + <color name="md_theme_secondaryFixedDim">#BCC3FF</color> + <color name="md_theme_onSecondaryFixedVariant">#3B4279</color> + <color name="md_theme_tertiaryFixed">#D8E2FF</color> + <color name="md_theme_onTertiaryFixed">#001A41</color> + <color name="md_theme_tertiaryFixedDim">#ADC7FF</color> + <color name="md_theme_onTertiaryFixedVariant">#2A4678</color> + <color name="md_theme_surfaceDim">#DBD9E0</color> + <color name="md_theme_surfaceBright">#FBF8FF</color> + <color name="md_theme_surfaceContainerLowest">#FFFFFF</color> + <color name="md_theme_surfaceContainerLow">#F5F2FA</color> + <color name="md_theme_surfaceContainer">#EFEDF4</color> + <color name="md_theme_surfaceContainerHigh">#E9E7EF</color> + <color name="md_theme_surfaceContainerHighest">#E4E1E9</color> + <color name="md_theme_primary_mediumContrast">#373E74</color> + <color name="md_theme_onPrimary_mediumContrast">#FFFFFF</color> + <color name="md_theme_primaryContainer_mediumContrast">#6970AA</color> + <color name="md_theme_onPrimaryContainer_mediumContrast">#FFFFFF</color> + <color name="md_theme_secondary_mediumContrast">#373E74</color> + <color name="md_theme_onSecondary_mediumContrast">#FFFFFF</color> + <color name="md_theme_secondaryContainer_mediumContrast">#6970AA</color> + <color name="md_theme_onSecondaryContainer_mediumContrast">#FFFFFF</color> + <color name="md_theme_tertiary_mediumContrast">#264273</color> + <color name="md_theme_onTertiary_mediumContrast">#FFFFFF</color> + <color name="md_theme_tertiaryContainer_mediumContrast">#5A74A9</color> + <color name="md_theme_onTertiaryContainer_mediumContrast">#FFFFFF</color> + <color name="md_theme_error_mediumContrast">#6E302A</color> + <color name="md_theme_onError_mediumContrast">#FFFFFF</color> + <color name="md_theme_errorContainer_mediumContrast">#AA6058</color> + <color name="md_theme_onErrorContainer_mediumContrast">#FFFFFF</color> + <color name="md_theme_background_mediumContrast">#FBF8FF</color> + <color name="md_theme_onBackground_mediumContrast">#1B1B21</color> + <color name="md_theme_surface_mediumContrast">#FBF8FF</color> + <color name="md_theme_onSurface_mediumContrast">#1B1B21</color> + <color name="md_theme_surfaceVariant_mediumContrast">#E3E1EC</color> + <color name="md_theme_onSurfaceVariant_mediumContrast">#42424B</color> + <color name="md_theme_outline_mediumContrast">#5E5E67</color> + <color name="md_theme_outlineVariant_mediumContrast">#7A7A83</color> + <color name="md_theme_scrim_mediumContrast">#000000</color> + <color name="md_theme_inverseSurface_mediumContrast">#303036</color> + <color name="md_theme_inverseOnSurface_mediumContrast">#F2EFF7</color> + <color name="md_theme_inversePrimary_mediumContrast">#BCC3FF</color> + <color name="md_theme_primaryFixed_mediumContrast">#6970AA</color> + <color name="md_theme_onPrimaryFixed_mediumContrast">#FFFFFF</color> + <color name="md_theme_primaryFixedDim_mediumContrast">#505890</color> + <color name="md_theme_onPrimaryFixedVariant_mediumContrast">#FFFFFF</color> + <color name="md_theme_secondaryFixed_mediumContrast">#6970AA</color> + <color name="md_theme_onSecondaryFixed_mediumContrast">#FFFFFF</color> + <color name="md_theme_secondaryFixedDim_mediumContrast">#505890</color> + <color name="md_theme_onSecondaryFixedVariant_mediumContrast">#FFFFFF</color> + <color name="md_theme_tertiaryFixed_mediumContrast">#5A74A9</color> + <color name="md_theme_onTertiaryFixed_mediumContrast">#FFFFFF</color> + <color name="md_theme_tertiaryFixedDim_mediumContrast">#415C8E</color> + <color name="md_theme_onTertiaryFixedVariant_mediumContrast">#FFFFFF</color> + <color name="md_theme_surfaceDim_mediumContrast">#DBD9E0</color> + <color name="md_theme_surfaceBright_mediumContrast">#FBF8FF</color> + <color name="md_theme_surfaceContainerLowest_mediumContrast">#FFFFFF</color> + <color name="md_theme_surfaceContainerLow_mediumContrast">#F5F2FA</color> + <color name="md_theme_surfaceContainer_mediumContrast">#EFEDF4</color> + <color name="md_theme_surfaceContainerHigh_mediumContrast">#E9E7EF</color> + <color name="md_theme_surfaceContainerHighest_mediumContrast">#E4E1E9</color> + <color name="md_theme_primary_highContrast">#151C52</color> + <color name="md_theme_onPrimary_highContrast">#FFFFFF</color> + <color name="md_theme_primaryContainer_highContrast">#373E74</color> + <color name="md_theme_onPrimaryContainer_highContrast">#FFFFFF</color> + <color name="md_theme_secondary_highContrast">#141C52</color> + <color name="md_theme_onSecondary_highContrast">#FFFFFF</color> + <color name="md_theme_secondaryContainer_highContrast">#373E74</color> + <color name="md_theme_onSecondaryContainer_highContrast">#FFFFFF</color> + <color name="md_theme_tertiary_highContrast">#00214D</color> + <color name="md_theme_onTertiary_highContrast">#FFFFFF</color> + <color name="md_theme_tertiaryContainer_highContrast">#264273</color> + <color name="md_theme_onTertiaryContainer_highContrast">#FFFFFF</color> + <color name="md_theme_error_highContrast">#44100C</color> + <color name="md_theme_onError_highContrast">#FFFFFF</color> + <color name="md_theme_errorContainer_highContrast">#6E302A</color> + <color name="md_theme_onErrorContainer_highContrast">#FFFFFF</color> + <color name="md_theme_background_highContrast">#FBF8FF</color> + <color name="md_theme_onBackground_highContrast">#1B1B21</color> + <color name="md_theme_surface_highContrast">#FBF8FF</color> + <color name="md_theme_onSurface_highContrast">#000000</color> + <color name="md_theme_surfaceVariant_highContrast">#E3E1EC</color> + <color name="md_theme_onSurfaceVariant_highContrast">#23232B</color> + <color name="md_theme_outline_highContrast">#42424B</color> + <color name="md_theme_outlineVariant_highContrast">#42424B</color> + <color name="md_theme_scrim_highContrast">#000000</color> + <color name="md_theme_inverseSurface_highContrast">#303036</color> + <color name="md_theme_inverseOnSurface_highContrast">#FFFFFF</color> + <color name="md_theme_inversePrimary_highContrast">#EBEAFF</color> + <color name="md_theme_primaryFixed_highContrast">#373E74</color> + <color name="md_theme_onPrimaryFixed_highContrast">#FFFFFF</color> + <color name="md_theme_primaryFixedDim_highContrast">#20285D</color> + <color name="md_theme_onPrimaryFixedVariant_highContrast">#FFFFFF</color> + <color name="md_theme_secondaryFixed_highContrast">#373E74</color> + <color name="md_theme_onSecondaryFixed_highContrast">#FFFFFF</color> + <color name="md_theme_secondaryFixedDim_highContrast">#20285D</color> + <color name="md_theme_onSecondaryFixedVariant_highContrast">#FFFFFF</color> + <color name="md_theme_tertiaryFixed_highContrast">#264273</color> + <color name="md_theme_onTertiaryFixed_highContrast">#FFFFFF</color> + <color name="md_theme_tertiaryFixedDim_highContrast">#092B5C</color> + <color name="md_theme_onTertiaryFixedVariant_highContrast">#FFFFFF</color> + <color name="md_theme_surfaceDim_highContrast">#DBD9E0</color> + <color name="md_theme_surfaceBright_highContrast">#FBF8FF</color> + <color name="md_theme_surfaceContainerLowest_highContrast">#FFFFFF</color> + <color name="md_theme_surfaceContainerLow_highContrast">#F5F2FA</color> + <color name="md_theme_surfaceContainer_highContrast">#EFEDF4</color> + <color name="md_theme_surfaceContainerHigh_highContrast">#E9E7EF</color> + <color name="md_theme_surfaceContainerHighest_highContrast">#E4E1E9</color> + <color name="black">#000000</color> + <color name="white">#FFFFFF</color> + <color name="textColor">#000E8E</color> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index e00c2dd143c595389b3cf8a32d9dc6aff48ec367..65654367f100ded2609deda79cd7f133acb7160b 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,4 +2,9 @@ <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> + <dimen name="title_top_margin">20dp</dimen> + <dimen name="title_start_margin">20dp</dimen> + <dimen name="fragment_horizontal_padding">20dp</dimen> + <dimen name="card_padding">16dp</dimen> + <dimen name="vertical_gap">16dp</dimen> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/font_certs.xml b/app/src/main/res/values/font_certs.xml new file mode 100644 index 0000000000000000000000000000000000000000..d2226ac01c057907ca1fc71f1d3390d3deea9ca1 --- /dev/null +++ b/app/src/main/res/values/font_certs.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <array name="com_google_android_gms_fonts_certs"> + <item>@array/com_google_android_gms_fonts_certs_dev</item> + <item>@array/com_google_android_gms_fonts_certs_prod</item> + </array> + <string-array name="com_google_android_gms_fonts_certs_dev"> + <item> + MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs= + </item> + </string-array> + <string-array name="com_google_android_gms_fonts_certs_prod"> + <item> + MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK + </item> + </string-array> +</resources> diff --git a/app/src/main/res/values/preloaded_fonts.xml b/app/src/main/res/values/preloaded_fonts.xml new file mode 100644 index 0000000000000000000000000000000000000000..3763cf385c71d2ba884584808805a95d57756d37 --- /dev/null +++ b/app/src/main/res/values/preloaded_fonts.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <array name="preloaded_fonts" translatable="false"> + <item>@font/nunito</item> + <item>@font/nunito_bold</item> + <item>@font/nunito_italic</item> + </array> +</resources> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 693caeff7b0fd6acd22064b8ff0bd3dedc4df1fc..db85c79ae5cbb93fc6e52e21fd6867790df01203 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,6 +1,103 @@ <resources> - <string name="app_name">Bandung-Bondowoso</string> + <string name="app_name">Bondoman</string> + <!--Title--> <string name="title_home">Home</string> <string name="title_dashboard">Dashboard</string> - <string name="title_notifications">Notifications</string> + <string name="title_notifications">Notifikasi</string> + <string name="title_transactions">Transaksi</string> + <string name="title_scan">Scan</string> + <string name="title_transaction_new">Transaksi Baru</string> + <string name="title_twibbon">Twibbon</string> + <string name="title_chart">Chart</string> + <string name="title_settings">Pengaturan</string> + <string name="title_edit_transaction">Edit</string> + <string name="title_delete_transaction">Hapus</string> + + <string name="token">Token: %s</string> + <string name="error_message">Error Message: %s</string> + <string name="response_code">Result Code: %d</string> + + <!--Transaction Balance--> + <string name="email">13521111@std.stei.itb.ac.id</string> + <string name="balance">Saldo</string> + <string name="balance_value">IDR %1$s</string> + + <!--Transaction Card--> + <string name="transaction_name">Judul</string> + <string name="transaction_category">Pembelian</string> + <string name="transaction_price">15000</string> + <string name="transaction_date">29/02/2024</string> + <string name="transaction_location">Bandung</string> + + <!--Content Description--> + <string name="cd_transaction_create">Tambah Transaksi</string> + <string name="cd_transaction_modify">Edit/Hapus Transaksi</string> + <string name="cd_transaction_empty">Tidak ada Transaksi</string> + <string name="cd_twibon_soobin">Twibon Soobin</string> + <string name="cd_twibon_faker">Twibon Faker</string> + <!--Label--> + <string name="label_transaction">Judul Transaksi</string> + <string name="label_price">Nominal Transaksi</string> + <string name="label_location">Lokasi Transaksi</string> + <string name="label_category">Kategori</string> + <string name="label_pembelian">Pengeluaran</string> + <string name="label_pemasukan">Pemasukan</string> + <string name="label_mata_uang">IDR</string> + <string name="label_shutter">Shutter</string> + <!--Hint--> + <string name="hint_transaction_new">Nama Transaksi</string> + <string name="hint_transaction_price">Jumlah Nominal</string> + <string name="hint_transaction_location">Nama Lokasi</string> + + <!--Button--> + <string name="btn_submit">Simpan</string> + <string name="btn_cancel">Batal</string> + <string name="btn_open_map">Open Google Map</string> + <!-- TODO: Remove or change this placeholder text --> + <string name="hello_blank_fragment">Hello blank fragment</string> + <string name="dialog_title">Hapus Transaksi</string> + <string name="dialog_message">Apakah Anda yakin ingin menghapus transaksi ini?</string> + <string name="msg_empty_transaction">Belum ada data transaksi</string> + + <string name="dialog_title_edit_transaction">Edit Transaksi: %1$s</string> + <string name="dialog_message_edit_transaction">Apakah Anda yakin ingin membatalkan pembuatan transaksi %1$s?</string> + + <string name="button_ok">OK</string> + <string name="button_cancel">BATAL</string> + <string name="button_delete">HAPUS</string> + <string name="button_random">RANDOM</string> + <string name="button_logout">LOG OUT</string> + + <string name="dialog_title_new_transaction">Transaksi Baru</string> + <string name="dialog_message_new_transaction">Apakah Anda yakin ingin membatalkan pembuatan transaksi baru?</string> + <string name="error_transaction_name_empty">Nama transaksi tidak boleh kosong</string> + <string name="error_transaction_amount_empty">Nominal transaksi tidak boleh kosong</string> + <string name="error_transaction_location_empty">Lokasi transaksi tidak boleh kosong</string> + <string name="error_transaction_category_empty">Kategori transaksi tidak boleh kosong</string> + <string name="login">Masuk</string> + <string name="img_logo_description">Logo Bandung Bondowoso</string> + <string name="hint_password">Password</string> + <string name="hint_email">Email</string> + <string name="login_button_text">Masuk</string> + <string name="no_network">OOPS!</string> + <string name="img_no_network_description">Tidak ada internet\n</string> + <string name="img_twibbon_preview">Hasil Twibbon</string> + <string name="no_network_description">Kamu terputus dari internet. Silahkan cek pengaturan internet kamu</string> + <string name="save_transaction">Simpan Daftar Transaksi</string> + <string name="file_type">.xlsx/.xls</string> + <string name="excel_pic">excel-pic</string> + <string name="simpan">Simpan</string> + <string name="gmail_pic">gmail-pic</string> + <string name="kirim_daftar_transaksi">Kirim Daftar Transaksi</string> + <string name="gmail">Gmail</string> + <string name="kirim">Kirim</string> + <string name="random_transaksi">Randomisasi Transaksi</string> + <string name="okay">Oke</string> + <string name="tv_settings_alert_email_no_network">Tidak ada koneksi internet</string> + <string name="tv_description_settings_email_no_network">Silahkan cek pengaturan internet kamu</string> + <string name="btn_retake">Retake</string> + <string name="scan_image">scan image</string> + <string name="scan_description">Tidak perlu masukin manual! Scan saja!!</string> + <string name="btn_scan">Foto Struk</string> + <string name="btn_scan_gallery">Buka Galeri</string> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 6ba26b860d7cff81b9979d9cd8f8af3f806ccd2e..c7170c8d98b4039e9dfb055cf62706cf8fc4da7f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,16 +1,193 @@ <resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> - <style name="Theme.BandungBondowoso" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> - <!-- Primary brand color. --> - <item name="colorPrimary">@color/purple_500</item> - <item name="colorPrimaryVariant">@color/purple_700</item> - <item name="colorOnPrimary">@color/white</item> - <!-- Secondary brand color. --> - <item name="colorSecondary">@color/teal_200</item> - <item name="colorSecondaryVariant">@color/teal_700</item> - <item name="colorOnSecondary">@color/black</item> - <!-- Status bar color. --> - <item name="android:statusBarColor">?attr/colorPrimaryVariant</item> - <!-- Customize your theme here. --> + <style name="Theme.BandungBondowoso" parent="Theme.MaterialComponents.DayNight.NoActionBar"> + <item name="colorPrimary">@color/md_theme_primary</item> + <item name="colorOnPrimary">@color/md_theme_onPrimary</item> + <item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item> + <item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item> + <item name="colorSecondary">@color/md_theme_secondary</item> + <item name="colorOnSecondary">@color/md_theme_onSecondary</item> + <item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item> + <item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item> + <item name="colorTertiary">@color/md_theme_tertiary</item> + <item name="colorOnTertiary">@color/md_theme_onTertiary</item> + <item name="colorTertiaryContainer">@color/md_theme_tertiaryContainer</item> + <item name="colorOnTertiaryContainer">@color/md_theme_onTertiaryContainer</item> + <item name="colorError">@color/md_theme_error</item> + <item name="colorOnError">@color/md_theme_onError</item> + <item name="colorErrorContainer">@color/md_theme_errorContainer</item> + <item name="colorOnErrorContainer">@color/md_theme_onErrorContainer</item> + <item name="android:colorBackground">@color/md_theme_background</item> + <item name="colorOnBackground">@color/md_theme_onBackground</item> + <item name="colorSurface">@color/md_theme_surface</item> + <item name="colorOnSurface">@color/md_theme_onSurface</item> + <item name="colorSurfaceVariant">@color/md_theme_surfaceVariant</item> + <item name="colorOnSurfaceVariant">@color/md_theme_onSurfaceVariant</item> + <item name="colorOutline">@color/md_theme_outline</item> + <item name="colorOutlineVariant">@color/md_theme_outlineVariant</item> + <item name="colorSurfaceInverse">@color/md_theme_inverseSurface</item> + <item name="colorOnSurfaceInverse">@color/md_theme_inverseOnSurface</item> + <item name="colorPrimaryInverse">@color/md_theme_inversePrimary</item> + <item name="colorPrimaryFixed">@color/md_theme_primaryFixed</item> + <item name="colorOnPrimaryFixed">@color/md_theme_onPrimaryFixed</item> + <item name="colorPrimaryFixedDim">@color/md_theme_primaryFixedDim</item> + <item name="colorOnPrimaryFixedVariant">@color/md_theme_onPrimaryFixedVariant</item> + <item name="colorSecondaryFixed">@color/md_theme_secondaryFixed</item> + <item name="colorOnSecondaryFixed">@color/md_theme_onSecondaryFixed</item> + <item name="colorSecondaryFixedDim">@color/md_theme_secondaryFixedDim</item> + <item name="colorOnSecondaryFixedVariant">@color/md_theme_onSecondaryFixedVariant</item> + <item name="colorTertiaryFixed">@color/md_theme_tertiaryFixed</item> + <item name="colorOnTertiaryFixed">@color/md_theme_onTertiaryFixed</item> + <item name="colorTertiaryFixedDim">@color/md_theme_tertiaryFixedDim</item> + <item name="colorOnTertiaryFixedVariant">@color/md_theme_onTertiaryFixedVariant</item> + <item name="colorSurfaceDim">@color/md_theme_surfaceDim</item> + <item name="colorSurfaceBright">@color/md_theme_surfaceBright</item> + <item name="colorSurfaceContainerLowest">@color/md_theme_surfaceContainerLowest</item> + <item name="colorSurfaceContainerLow">@color/md_theme_surfaceContainerLow</item> + <item name="colorSurfaceContainer">@color/md_theme_surfaceContainer</item> + <item name="colorSurfaceContainerHigh">@color/md_theme_surfaceContainerHigh</item> + <item name="colorSurfaceContainerHighest">@color/md_theme_surfaceContainerHighest</item> + <item name="floatingActionButtonStyle">@style/FloatingActionButtonStyle</item> + <item name="textAppearanceDisplayLarge">@style/TextAppearance.DisplayLarge</item> + <item name="textAppearanceDisplayMedium">@style/TextAppearance.DisplayMedium</item> + <item name="textAppearanceDisplaySmall">@style/TextAppearance.DisplaySmall</item> + <item name="textAppearanceHeadlineLarge">@style/TextAppearance.HeadlineLarge</item> + <item name="textAppearanceHeadlineMedium">@style/TextAppearance.HeadlineMedium</item> + <item name="textAppearanceHeadlineSmall">@style/TextAppearance.HeadlineSmall</item> + <item name="textAppearanceTitleLarge">@style/TextAppearance.TitleLarge</item> + <item name="textAppearanceTitleMedium">@style/TextAppearance.TitleMedium</item> + <item name="textAppearanceTitleSmall">@style/TextAppearance.TitleSmall</item> + <item name="textAppearanceLabelLarge">@style/TextAppearance.LabelLarge</item> + <item name="textAppearanceLabelMedium">@style/TextAppearance.LabelMedium</item> + <item name="textAppearanceLabelSmall">@style/TextAppearance.LabelSmall</item> + <item name="bottomSheetDialogTheme">@style/AppBottomSheetDialogTheme</item> + </style> + + <!-- Display --> + <style name="TextAppearance.DisplayLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">57sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.DisplayMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">45sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.DisplaySmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">36sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <!-- Headline --> + <style name="TextAppearance.HeadlineLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">32sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.HeadlineMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">28sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.HeadlineSmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">24sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <!-- Title --> + <style name="TextAppearance.TitleLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">22sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.TitleMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">16sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.TitleSmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <!-- Label --> + <style name="TextAppearance.LabelLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.LabelMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">12sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.LabelSmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">11sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.LabelLargeBold" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito_bold</item> + <item name="android:typeface">normal</item> + </style> + <!-- Body --> + <style name="TextAppearance.BodyLarge" parent="@android:style/TextAppearance"> + <item name="android:textSize">16sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.BodyMedium" parent="@android:style/TextAppearance"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="TextAppearance.BodySmall" parent="@android:style/TextAppearance"> + <item name="android:textSize">12sp</item> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:typeface">normal</item> + </style> + <style name="BottomNavigationViewTextStyle"> + <item name="android:fontFamily">@font/nunito</item> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.05</item> + </style> + <!-- Floating Action Button --> + <style name="FloatingActionButtonStyle" parent="Widget.Design.FloatingActionButton"> + <item name="shapeAppearanceOverlay">@style/FABShapeStyleSquare</item> + </style> + <style name="FABShapeStyleSquare" parent="ShapeAppearance.MaterialComponents.SmallComponent"> + <item name="cornerSize">20%</item> + <item name="android:tint">@color/md_theme_primary</item> + <item name="android:backgroundTint">@color/md_theme_surface</item> + </style> + + <style name="buttonStylePrimary" parent="Widget.MaterialComponents.Button"> + <item name="android:background">@drawable/bg_button_primary</item> + <item name="android:textColor">@color/white</item> + </style> + <style name="buttonStyleShutter" parent="Widget.MaterialComponents.Button"> + <item name="android:background">@drawable/bg_custom_dialog</item> + </style> + + <style name="buttonStyleDanger" parent="Widget.MaterialComponents.Button"> + <item name="android:background">@drawable/bg_button_danger</item> + <item name="android:textColor">@color/white</item> + </style> + + <style name="LoginTextInputLayoutStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"> + <item name="boxStrokeColor">@color/md_theme_primary</item> + <item name="boxStrokeWidth">2dp</item> + </style> + + <style name="AppBottomSheetDialogTheme" + parent="Theme.Design.Light.BottomSheetDialog"> + <item name="bottomSheetStyle">@style/AppModalStyle</item> + </style> + + <style name="AppModalStyle" + parent="Widget.Design.BottomSheet.Modal"> + <item name="android:background">@drawable/rounded_dialog</item> </style> </resources> \ No newline at end of file diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000000000000000000000000000000000000..af43608a66067f21287b82cb9e157d12403ec328 --- /dev/null +++ b/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<paths xmlns:android="http://schemas.android.com/apk/res/android"> +<!-- <cache-path name="cache" path="." />--> + <cache-path name="cache_files" path="/" /> +</paths> diff --git a/build.gradle.kts b/build.gradle.kts index 53f4a67287fcc572dab6ad907bddc40aa4efbfa6..f5bec5d1786aa5c33c931fd3f7b9412a82f3bb93 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,4 +2,5 @@ plugins { id("com.android.application") version "8.2.2" apply false id("org.jetbrains.kotlin.android") version "1.9.22" apply false + id("com.google.devtools.ksp") version "1.9.22-1.0.16" apply false } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 9aab2d208cd9cef0d57fb570983e386006b41f63..b43ba22e82ab2b7d788fd33c1eeffe67cccea237 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url = uri("https://jitpack.io") } } }