├── .gitignore ├── .idea ├── .gitignore ├── .name ├── compiler.xml ├── deploymentTargetDropDown.xml ├── gradle.xml ├── misc.xml ├── render.experimental.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── rishav │ │ └── buckoid │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── com │ │ │ └── rishav │ │ │ └── buckoid │ │ │ ├── Adapter │ │ │ └── TransactionAdapter.kt │ │ │ ├── Dao │ │ │ └── TransactionDao.kt │ │ │ ├── Database │ │ │ └── TransactionDatabase.kt │ │ │ ├── MainActivity.kt │ │ │ ├── Model │ │ │ ├── Profile.kt │ │ │ └── Transaction.kt │ │ │ ├── Repository │ │ │ └── TransactionRepository.kt │ │ │ ├── UserDetails.kt │ │ │ ├── ViewModel │ │ │ └── TransactionViewModel.kt │ │ │ └── fragments │ │ │ ├── AddTransaction.kt │ │ │ ├── AllTransactions.kt │ │ │ ├── Authentication │ │ │ ├── UserDetails.kt │ │ │ └── UserSignUp.kt │ │ │ ├── BackupDrive.kt │ │ │ ├── Dashboard.kt │ │ │ ├── Profile.kt │ │ │ └── TransactionDetails.kt │ └── res │ │ ├── drawable-v24 │ │ ├── ic_launcher_background.xml │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── bottom_dialog.xml │ │ ├── button_selector_background.xml │ │ ├── ic_baseline_add_24.xml │ │ ├── ic_baseline_arrow_back_ios_24.xml │ │ ├── ic_baseline_assessment_24.xml │ │ ├── ic_baseline_auto_stories_24.xml │ │ ├── ic_baseline_backup_24.xml │ │ ├── ic_baseline_calendar_month_24.xml │ │ ├── ic_baseline_category_24.xml │ │ ├── ic_baseline_currency_rupee_24.xml │ │ ├── ic_baseline_dashboard_24.xml │ │ ├── ic_baseline_delete_outline_24.xml │ │ ├── ic_baseline_directions_transit_24.xml │ │ ├── ic_baseline_edit_24.xml │ │ ├── ic_baseline_fastfood_24.xml │ │ ├── ic_baseline_favorite_24.xml │ │ ├── ic_baseline_fingerprint_24.xml │ │ ├── ic_baseline_info_24.xml │ │ ├── ic_baseline_menu_24.xml │ │ ├── ic_baseline_mode_night_24.xml │ │ ├── ic_baseline_person_24.xml │ │ ├── ic_baseline_share_24.xml │ │ ├── ic_baseline_shopping_cart_24.xml │ │ ├── ic_baseline_star_rate_24.xml │ │ ├── ic_google_icon.xml │ │ ├── ic_negative_transaction.xml │ │ ├── ic_positive_amount.xml │ │ ├── ic_round_add_to_drive_24.xml │ │ ├── logo.xml │ │ ├── logo_round.xml │ │ ├── round.xml │ │ └── splash_screen.xml │ │ ├── font │ │ ├── baloo.xml │ │ ├── baloo_bhaina.xml │ │ ├── poppins.xml │ │ ├── poppins_medium.xml │ │ └── poppins_semibold.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_user_details.xml │ │ ├── dialog_delete.xml │ │ ├── drawer_nav_header.xml │ │ ├── dropdown_item.xml │ │ ├── fragment_add_transaction.xml │ │ ├── fragment_all_transactions.xml │ │ ├── fragment_backup_drive.xml │ │ ├── fragment_dashboard.xml │ │ ├── fragment_profile.xml │ │ ├── fragment_transaction_details.xml │ │ ├── fragment_user_details.xml │ │ ├── fragment_user_sign_up.xml │ │ ├── night_mode_action_layout_switch.xml │ │ ├── transaction_item.xml │ │ └── update_user_details_dialog.xml │ │ ├── menu │ │ ├── bottom_nav.xml │ │ └── menu_drawer.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ ├── app_navigation.xml │ │ └── signup_user_navigation.xml │ │ ├── values-night │ │ └── colors.xml │ │ └── values │ │ ├── colors.xml │ │ ├── font_certs.xml │ │ ├── preloaded_fonts.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── rishav │ └── buckoid │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Track Back -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 83 | 84 | 85 | 86 | 87 | 88 | 90 | -------------------------------------------------------------------------------- /.idea/render.experimental.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-Study-Jams 2 | Buckoid-Android-App 3 | 4 | Problem Statement: 5 | 6 | How do we track our expenses successfully? What about our personal capital? How much we spend we don't keep track and we spend a lot more than our budget. Let's face it — saving money in today's world is not easy. We need a budget manager and expense tracking App which will keep a track record of all our expenditure. 7 | 8 | Proposed Solution : 9 | 10 | This Project proposes an “Expense Tracking App”. Luckily, Buckoid is more than a money tracker, it's also one of the best savings apps to help you with money management. Keep track of your personal expenses and compare them to your monthly income with the budget planner. Keep track of train, cab, movie, event bookings, and more. Keep your monthly budget in mint condition. This app will helpus to become a budgeting masters and we can start saving money with Buckoid. 11 | 12 | sampleimages 13 | 14 | 15 | Playstore App Image 16 | 17 | Functionality & Concepts used : 18 | 19 | The App has a very simple and interactive interface which helps the user to track his Expenses. Following are a few android concepts used to achieve the functionalities in the app : 20 | - Constraint Layout : Most of the activities in the app uses a flexible constraint layout, which is easy to handle for different screen sizes. 21 | - Simple & Easy Views Design : Use of familiar audience EditText with hints and interactive buttons made it easier for users to add or update transactions. It consists of Material Widgits and Components like Card Views, Toggle Component, etc. Apps also uses App Navigation(Jetpack Library Component) to switch between different screens. It has a graphical representation of data. 22 | - Dark Mode/Light Mode: User can change App Theme easily at any time according to their convenience. 23 | - Bottom Navigation: It has bottom navigation to navigate between top screens and gives user a more enhanced UI/Ux interface. 24 | - RecyclerView : To present the list of different transactions done we used the efficient recyclerview. 25 | - LiveData & Room Database : We are using LiveData to store & Update new transactions. 26 | 27 | Application Link & Future Scope : 28 | 29 | The app is currently in the Playstore in production mode (Under Review). 30 | You can access the app: View On Google Play. 31 | Check our Codebase on Github: Code Link. 32 | 33 | Once the app is fully launched and functional we plan to add more features like Backup in Google Drive using Google Drive API so that all the user data remains saved. Then we are planning to add Collect Coins & Badges on certain no of transactions and unlock more features so that the user comes to the app daily and stores his transactions each time. Then we are planning to include Goal saving features so that users can plan for certain goals and achieve them like Vacation trips, Buying a mobile, etc. Also, we are planning to include more visual data representation so that users can have a very clear look and compare and stay within their Budget. 34 | 35 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'kotlin-kapt' 5 | id 'kotlin-parcelize' 6 | } 7 | apply plugin: "androidx.navigation.safeargs.kotlin" 8 | 9 | android { 10 | compileSdk 31 11 | 12 | defaultConfig { 13 | applicationId "com.rishav.buckoid" 14 | minSdk 21 15 | targetSdk 31 16 | versionCode 4 17 | versionName "1.4" 18 | 19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 20 | } 21 | 22 | buildTypes { 23 | release { 24 | minifyEnabled true 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | compileOptions { 29 | sourceCompatibility JavaVersion.VERSION_1_8 30 | targetCompatibility JavaVersion.VERSION_1_8 31 | } 32 | kotlinOptions { 33 | jvmTarget = '1.8' 34 | } 35 | buildFeatures { 36 | viewBinding = true 37 | } 38 | packagingOptions { 39 | exclude 'META-INF/DEPENDENCIES' 40 | } 41 | lintOptions { 42 | checkReleaseBuilds false 43 | } 44 | } 45 | 46 | dependencies { 47 | 48 | implementation 'androidx.core:core-ktx:1.7.0' 49 | implementation 'androidx.appcompat:appcompat:1.4.0' 50 | implementation 'com.google.android.material:material:1.4.0' 51 | implementation 'androidx.constraintlayout:constraintlayout:2.1.2' 52 | implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' 53 | implementation "androidx.fragment:fragment-ktx:1.4.0" 54 | implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' 55 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 56 | testImplementation 'junit:junit:4.+' 57 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 58 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 59 | implementation 'com.github.blackfizz:eazegraph:1.2.5l@aar' 60 | implementation 'com.nineoldandroids:library:2.4.0' 61 | 62 | //Room Database 63 | implementation "androidx.room:room-runtime:2.4.0" 64 | kapt "androidx.room:room-compiler:2.4.0" 65 | implementation "androidx.room:room-ktx:2.4.0" 66 | androidTestImplementation "androidx.room:room-testing:2.4.0" 67 | 68 | 69 | // Lifecycle components 70 | implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" 71 | implementation "androidx.lifecycle:lifecycle-common-java8:2.4.0" 72 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0" 73 | implementation 'androidx.activity:activity-ktx:1.4.0' 74 | 75 | // Kotlin components 76 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10" 77 | 78 | //coroutines 79 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2' 80 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' 81 | 82 | //play 83 | implementation("com.google.android.play:core-ktx:1.8.1") 84 | 85 | implementation 'uk.co.samuelwall:material-tap-target-prompt:3.3.2' 86 | 87 | //google driver api 88 | implementation 'com.google.android.gms:play-services-auth:20.0.1' 89 | implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' 90 | implementation ('com.google.api-client:google-api-client-android:1.26.0') 91 | implementation ('com.google.apis:google-api-services-drive:v3-rev136-1.25.0') 92 | implementation 'com.google.http-client:google-http-client-gson:1.39.2' 93 | 94 | //image uri 95 | implementation 'com.github.bumptech.glide:glide:3.7.0' 96 | } -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | {"installed":{"client_id":"936900394467-e70ft0qbhq9v0ip8kdpqd2fps6ag8sme.apps.googleusercontent.com","project_id":"buckoid","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}} -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep class com.rishav.buckoid.Model.Transaction -------------------------------------------------------------------------------- /app/src/androidTest/java/com/rishav/buckoid/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.example.trackback", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishavchanda/Buckoid-Android-App/c489816f21aeb1250f6751c30b9d6b340af2cdeb/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/Adapter/TransactionAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.Adapter 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.content.Context 6 | import android.content.SharedPreferences 7 | import android.view.LayoutInflater 8 | import android.view.ViewGroup 9 | import androidx.appcompat.app.AppCompatActivity 10 | import androidx.core.content.ContextCompat 11 | import androidx.navigation.Navigation 12 | import androidx.recyclerview.widget.RecyclerView 13 | import com.rishav.buckoid.Model.Transaction 14 | import com.rishav.buckoid.R 15 | import com.rishav.buckoid.databinding.TransactionItemBinding 16 | import com.rishav.buckoid.fragments.* 17 | import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt 18 | import uk.co.samuelwall.materialtaptargetprompt.extras.backgrounds.RectanglePromptBackground 19 | import uk.co.samuelwall.materialtaptargetprompt.extras.focals.RectanglePromptFocal 20 | 21 | class TransactionAdapter(val context: Context, val activity:Activity,val fragment:String, private val transList: List) : RecyclerView.Adapter(){ 22 | 23 | class transactionViewHolder(val binding:TransactionItemBinding) : RecyclerView.ViewHolder(binding.root) 24 | 25 | lateinit var userDetails: SharedPreferences 26 | override fun onCreateViewHolder( 27 | parent: ViewGroup, 28 | viewType: Int 29 | ): transactionViewHolder { 30 | return transactionViewHolder(TransactionItemBinding.inflate(LayoutInflater.from(parent.context),parent,false)) 31 | 32 | } 33 | 34 | @SuppressLint("SetTextI18n") 35 | override fun onBindViewHolder(holder: transactionViewHolder, position: Int) { 36 | val data = transList[position] 37 | holder.binding.title.text = data.title 38 | holder.binding.money.text = "₹"+data.amount.toInt().toString() 39 | holder.binding.date.text = data.date 40 | holder.binding.category.text = data.category 41 | 42 | when(data.category){ 43 | "Food" -> { 44 | holder.binding.cardIcon.setImageResource(R.drawable.ic_baseline_fastfood_24) 45 | holder.binding.cardIcon.setColorFilter(ContextCompat.getColor(context, R.color.yellow)) 46 | holder.binding.category.setTextColor(ContextCompat.getColor(context, R.color.yellow)) 47 | holder.binding.cardImage.setCardBackgroundColor(ContextCompat.getColor(context, R.color.yellow_light)) 48 | } 49 | "Shopping" -> { 50 | holder.binding.cardIcon.setImageResource(R.drawable.ic_baseline_shopping_cart_24) 51 | holder.binding.cardIcon.setColorFilter(ContextCompat.getColor(context, R.color.lightBlue)) 52 | holder.binding.category.setTextColor(ContextCompat.getColor(context, R.color.lightBlue)) 53 | holder.binding.cardImage.setCardBackgroundColor(ContextCompat.getColor(context, R.color.lightBlue_light)) 54 | } 55 | "Transport" -> { 56 | holder.binding.cardIcon.setImageResource(R.drawable.ic_baseline_directions_transit_24) 57 | holder.binding.cardIcon.setColorFilter(ContextCompat.getColor(context, R.color.violet)) 58 | holder.binding.category.setTextColor(ContextCompat.getColor(context, R.color.violet)) 59 | holder.binding.cardImage.setCardBackgroundColor(ContextCompat.getColor(context, R.color.violet_light)) 60 | } 61 | "Health" -> { 62 | holder.binding.cardIcon.setImageResource(R.drawable.ic_baseline_favorite_24) 63 | holder.binding.cardIcon.setColorFilter(ContextCompat.getColor(context, R.color.red)) 64 | holder.binding.category.setTextColor(ContextCompat.getColor(context, R.color.red)) 65 | holder.binding.cardImage.setCardBackgroundColor(ContextCompat.getColor(context, R.color.red_light)) 66 | } 67 | "Other" -> { 68 | holder.binding.cardIcon.setImageResource(R.drawable.ic_baseline_category_24) 69 | holder.binding.cardIcon.setColorFilter(ContextCompat.getColor(context, R.color.lightBrown)) 70 | holder.binding.category.setTextColor(ContextCompat.getColor(context, R.color.lightBrown)) 71 | holder.binding.cardImage.setCardBackgroundColor(ContextCompat.getColor(context, R.color.lightBrown_light)) 72 | } 73 | "Education" -> { 74 | holder.binding.cardIcon.setImageResource(R.drawable.ic_baseline_auto_stories_24) 75 | holder.binding.cardIcon.setColorFilter(ContextCompat.getColor(context, R.color.green)) 76 | holder.binding.category.setTextColor(ContextCompat.getColor(context, R.color.green)) 77 | holder.binding.cardImage.setCardBackgroundColor(ContextCompat.getColor(context, R.color.green_light)) 78 | } 79 | 80 | } 81 | 82 | 83 | holder.binding.root.setOnClickListener { 84 | if(fragment == "Dashboard"){ 85 | val argument = DashboardDirections.goToTransactionDetails(data,fragment) 86 | Navigation.findNavController(it).navigate(argument) 87 | }else if(fragment == "AllTransactions"){ 88 | val argument = AllTransactionsDirections.allTransactionToTransactionDetails(data,fragment) 89 | Navigation.findNavController(it).navigate(argument) 90 | } 91 | 92 | } 93 | 94 | } 95 | 96 | override fun getItemCount() = transList.size 97 | 98 | } 99 | 100 | 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/Dao/TransactionDao.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.Dao 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.room.* 5 | import com.rishav.buckoid.Model.Transaction 6 | 7 | @Dao 8 | interface TransactionDao { 9 | 10 | @Query("SELECT * FROM `Transaction` ORDER BY year DESC,month DESC,day DESC,category DESC") 11 | fun getTransaction(): LiveData> 12 | 13 | @Query("SELECT * FROM `Transaction` WHERE month=:month AND year=:year") 14 | fun getMonthlyTransaction(month: Int,year: Int): LiveData> 15 | 16 | @Query("SELECT * FROM `Transaction` WHERE year=:year") 17 | fun getYearlyTransaction(year: Int): LiveData> 18 | 19 | @Insert(onConflict = OnConflictStrategy.REPLACE) 20 | fun insertTransaction(transaction: Transaction) 21 | 22 | @Query("DELETE FROM `TRANSACTION` WHERE id=:id") 23 | fun deleteTransaction(id: Int) 24 | 25 | @Update(onConflict = OnConflictStrategy.REPLACE) 26 | fun updateTransaction(transaction: Transaction) 27 | 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/Database/TransactionDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.Database 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import com.rishav.buckoid.Dao.TransactionDao 8 | import com.rishav.buckoid.Model.Transaction 9 | 10 | @Database(entities = [Transaction::class], version = 1, exportSchema = false) 11 | abstract class TransactionDatabase : RoomDatabase() { 12 | 13 | abstract fun myTransactionDao(): TransactionDao 14 | 15 | companion object 16 | { 17 | private var INSTANCE: TransactionDatabase?=null 18 | fun getDatabaseInstance(context: Context): TransactionDatabase { 19 | val tempInstance= INSTANCE 20 | if (tempInstance!=null){ 21 | return tempInstance 22 | } 23 | synchronized(this) 24 | { 25 | val roomDatabaseInstance = Room.databaseBuilder(context, 26 | TransactionDatabase::class.java,"Transaction").allowMainThreadQueries().build() 27 | INSTANCE =roomDatabaseInstance 28 | return roomDatabaseInstance 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid 2 | 3 | import android.app.KeyguardManager 4 | import android.content.* 5 | import android.content.pm.PackageManager 6 | import android.hardware.biometrics.BiometricPrompt 7 | import android.net.Uri 8 | import android.os.Build 9 | import android.os.Bundle 10 | import android.os.CancellationSignal 11 | import android.view.MenuItem 12 | import android.view.View 13 | import android.widget.Toast 14 | import androidx.annotation.RequiresApi 15 | import androidx.appcompat.app.AppCompatActivity 16 | import androidx.appcompat.app.AppCompatDelegate 17 | import androidx.appcompat.widget.SwitchCompat 18 | import androidx.core.app.ActivityCompat 19 | import androidx.core.view.GravityCompat 20 | import androidx.navigation.fragment.NavHostFragment 21 | import androidx.navigation.ui.setupWithNavController 22 | import com.google.android.material.navigation.NavigationView 23 | import com.google.android.play.core.appupdate.AppUpdateManager 24 | import com.google.android.play.core.appupdate.AppUpdateManagerFactory 25 | import com.google.android.play.core.install.model.AppUpdateType 26 | import com.google.android.play.core.install.model.UpdateAvailability 27 | import com.rishav.buckoid.databinding.ActivityMainBinding 28 | import java.util.* 29 | 30 | import android.content.Intent 31 | 32 | 33 | class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { 34 | lateinit var binding:ActivityMainBinding 35 | lateinit var mNightModeSwitch: SwitchCompat 36 | lateinit var userDetails:SharedPreferences 37 | private var appUpdate: AppUpdateManager? = null 38 | var isNight:Boolean = false 39 | 40 | //finger print 41 | var isFingerPrintEnabled:Boolean = false 42 | private var cancellationSignal:CancellationSignal?=null 43 | private val authenticationCallback:BiometricPrompt.AuthenticationCallback 44 | get() = 45 | @RequiresApi(Build.VERSION_CODES.P) 46 | object : BiometricPrompt.AuthenticationCallback(){ 47 | override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) { 48 | super.onAuthenticationError(errorCode, errString) 49 | finish() 50 | } 51 | override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult?) { 52 | super.onAuthenticationSucceeded(result) 53 | } 54 | } 55 | @RequiresApi(Build.VERSION_CODES.Q) 56 | override fun onCreate(savedInstanceState: Bundle?) { 57 | super.onCreate(savedInstanceState) 58 | if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { 59 | userDetails = this.getSharedPreferences("UserDetails", MODE_PRIVATE) 60 | isFingerPrintEnabled = userDetails.getBoolean("fingerprint_enabled", false) 61 | if (isFingerPrintEnabled) { 62 | fingerPrintSensor() 63 | } 64 | } 65 | setTheme(R.style.Theme_TrackBack) 66 | binding = ActivityMainBinding.inflate(layoutInflater) 67 | setContentView(binding.root) 68 | nightMode() 69 | inAppUpdater() 70 | binding.navigationView.setNavigationItemSelectedListener(this) 71 | val navHostFragment = 72 | supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment 73 | val navController = navHostFragment.navController 74 | binding.bottomNavigation.setupWithNavController(navController) 75 | 76 | } 77 | 78 | fun nightMode(){ 79 | // Configure night-mode switch 80 | isNight = userDetails.getBoolean("nightMode",true) 81 | val actionLayout:View = binding.navigationView.getMenu().findItem(R.id.dark_mode).getActionView() 82 | mNightModeSwitch = actionLayout.findViewById(R.id.night_switch_compat) 83 | if (isNight) { 84 | mNightModeSwitch.setChecked(true) 85 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) 86 | }else{ 87 | mNightModeSwitch.setChecked(false) 88 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 89 | } 90 | mNightModeSwitch.setOnCheckedChangeListener { buttonView, isChecked -> applyNightMode(isChecked) } 91 | 92 | } 93 | 94 | private fun applyNightMode(checked: Boolean) { 95 | if (checked) { 96 | isNight = true 97 | saveSettingsBoolean("nightMode",true) 98 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) 99 | }else{ 100 | isNight = false 101 | saveSettingsBoolean("nightMode",false) 102 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) 103 | } 104 | //restartActivityInvalidateBackstack(this) 105 | } 106 | private fun saveSettingsBoolean(mode: String, isNight: Boolean) { 107 | val editor: SharedPreferences.Editor = userDetails.edit() 108 | editor.putBoolean(mode, isNight) 109 | editor.apply() 110 | } 111 | 112 | 113 | override fun onNavigationItemSelected(item: MenuItem): Boolean { 114 | val id = item.getItemId() 115 | if(id == R.id.dark_mode){ 116 | mNightModeSwitch.performClick() 117 | }else if(id == R.id.nav_share){ 118 | try { 119 | val intent = Intent(Intent.ACTION_SEND) 120 | intent.type = "text/plain" 121 | intent.putExtra(Intent.EXTRA_SUBJECT, "@string/app_name") 122 | intent.putExtra( 123 | Intent.EXTRA_TEXT, 124 | "https://play.google.com/store/apps/details?id="+ this@MainActivity.getPackageName() 125 | ) 126 | startActivity(Intent.createChooser(intent, "Share With")) 127 | } catch (e: Exception) { 128 | Toast.makeText( 129 | this@MainActivity, 130 | "Unable to share at this moment.." + e.message.toString(), 131 | Toast.LENGTH_SHORT 132 | ).show() 133 | } 134 | }else if(id == R.id.nav_RateUs){ 135 | try { 136 | startActivity( 137 | Intent( 138 | Intent.ACTION_VIEW, 139 | Uri.parse("market://details?id=$packageName") 140 | ) 141 | ) 142 | } catch (e: ActivityNotFoundException) { 143 | startActivity( 144 | Intent( 145 | Intent.ACTION_VIEW, 146 | Uri.parse("https://play.google.com/store/apps/details?id=$packageName") 147 | ) 148 | ) 149 | } 150 | }else if(id == R.id.nav_aboutUs){ 151 | Toast.makeText( 152 | this, 153 | "Working on this wait for update", 154 | Toast.LENGTH_SHORT 155 | ).show() 156 | } 157 | binding.drawerLayout.closeDrawer(GravityCompat.START); 158 | return true 159 | } 160 | 161 | private fun inAppUpdater() { 162 | appUpdate = AppUpdateManagerFactory.create(this) 163 | 164 | appUpdate?.appUpdateInfo?.addOnSuccessListener { updateInfo -> 165 | if(updateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE 166 | && updateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)){ 167 | appUpdate!!.startUpdateFlowForResult(updateInfo,AppUpdateType.IMMEDIATE,this,100) 168 | } 169 | 170 | } 171 | } 172 | 173 | override fun onResume() { 174 | super.onResume() 175 | inProgressUpdate() 176 | } 177 | 178 | private fun inProgressUpdate() { 179 | appUpdate?.appUpdateInfo?.addOnSuccessListener { updateInfo -> 180 | if(updateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS){ 181 | appUpdate!!.startUpdateFlowForResult(updateInfo,AppUpdateType.IMMEDIATE,this,100) 182 | } 183 | 184 | } 185 | } 186 | 187 | 188 | 189 | @RequiresApi(Build.VERSION_CODES.Q) 190 | private fun fingerPrintSensor() { 191 | checkBiometricSupport() 192 | val biometricPrompt = BiometricPrompt.Builder(this) 193 | .setDeviceCredentialAllowed(true) 194 | .setTitle("Authentication Required") 195 | .setDescription("Please enter your PIN / password to continue") 196 | .build() 197 | 198 | biometricPrompt.authenticate(getCancellationSignal(),mainExecutor,authenticationCallback) 199 | 200 | 201 | } 202 | 203 | private fun getCancellationSignal(): CancellationSignal{ 204 | cancellationSignal = CancellationSignal() 205 | cancellationSignal?.setOnCancelListener { 206 | notifyUser("Authentication was cancelled by the user") 207 | 208 | } 209 | return cancellationSignal as CancellationSignal 210 | } 211 | 212 | private fun checkBiometricSupport(): Boolean { 213 | val keyguardManager : KeyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager 214 | 215 | if (!keyguardManager.isKeyguardSecure){ 216 | notifyUser("Finger print not enabled in settings") 217 | return false 218 | } 219 | 220 | if (ActivityCompat.checkSelfPermission(this,android.Manifest.permission.USE_BIOMETRIC)!= PackageManager.PERMISSION_GRANTED){ 221 | notifyUser("Fingerprint authentication permission is not enabled") 222 | return false 223 | } 224 | 225 | return if (packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)){ 226 | true 227 | }else true 228 | 229 | } 230 | 231 | private fun notifyUser(message: String) { 232 | Toast.makeText(this,message,Toast.LENGTH_SHORT).show() 233 | } 234 | 235 | 236 | 237 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/Model/Profile.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.Model 2 | 3 | import android.content.Context 4 | import com.google.android.gms.auth.api.signin.GoogleSignIn 5 | import com.google.android.gms.auth.api.signin.GoogleSignInAccount 6 | 7 | class Profile(context:Context){ 8 | val mContext:Context = context 9 | val name = getData()?.displayName.toString() 10 | val profilePic = getData()?.photoUrl 11 | val email = getData()?.email 12 | val account = getData() 13 | 14 | fun getData(): GoogleSignInAccount? { 15 | val acct = GoogleSignIn.getLastSignedInAccount(mContext) 16 | return acct 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/Model/Transaction.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.Model 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import kotlinx.parcelize.Parcelize 7 | 8 | @Entity(tableName = "Transaction") 9 | @Parcelize 10 | data class Transaction ( 11 | 12 | @PrimaryKey(autoGenerate = true) 13 | var id:Int? = null, 14 | 15 | var type: String, 16 | var category: String, 17 | var title: String, 18 | var amount: Double, 19 | var date: String, 20 | var day:Int, 21 | var month:Int, 22 | var year:Int, 23 | var note: String 24 | 25 | ) : Parcelable -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/Repository/TransactionRepository.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.Repository 2 | 3 | import androidx.lifecycle.LiveData 4 | import com.rishav.buckoid.Dao.TransactionDao 5 | import com.rishav.buckoid.Model.Transaction 6 | 7 | class TransactionRepository(val dao: TransactionDao) { 8 | 9 | fun getAllTransaction(): LiveData> { 10 | return dao.getTransaction() 11 | } 12 | 13 | fun getMonthlyTransaction(month:Int,Year:Int): LiveData>{ 14 | return dao.getMonthlyTransaction(month,Year) 15 | } 16 | 17 | fun getYearlyTransaction(year:Int): LiveData>{ 18 | return dao.getYearlyTransaction(year) 19 | } 20 | 21 | fun insertTransaction(transaction: Transaction){ 22 | dao.insertTransaction(transaction) 23 | } 24 | 25 | fun deleteTransaction(id:Int){ 26 | dao.deleteTransaction(id) 27 | } 28 | 29 | fun updateTransaction(transaction: Transaction){ 30 | dao.updateTransaction(transaction) 31 | } 32 | 33 | 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/UserDetails.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid 2 | 3 | import android.content.Intent 4 | import android.content.SharedPreferences 5 | import androidx.appcompat.app.AppCompatActivity 6 | import android.os.Bundle 7 | import androidx.appcompat.app.AppCompatDelegate 8 | import com.rishav.buckoid.databinding.ActivityUserDetailsBinding 9 | 10 | class UserDetails : AppCompatActivity() { 11 | lateinit var binding:ActivityUserDetailsBinding 12 | lateinit var userDetails: SharedPreferences 13 | var isFirstTime:Boolean = false 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | setData() 16 | setTheme(R.style.Theme_TrackBack) 17 | super.onCreate(savedInstanceState) 18 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) 19 | binding = ActivityUserDetailsBinding.inflate(layoutInflater) 20 | setContentView(binding.root) 21 | 22 | } 23 | 24 | private fun setData() { 25 | userDetails = this.getSharedPreferences("UserDetails", AppCompatActivity.MODE_PRIVATE) 26 | isFirstTime = userDetails.getBoolean("isFirstTime",true) 27 | if (!isFirstTime){ 28 | goToNextScreen() 29 | finish() 30 | } 31 | } 32 | 33 | private fun goToNextScreen() { 34 | val intent = Intent(this, MainActivity::class.java) 35 | startActivity(intent) 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/ViewModel/TransactionViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.ViewModel 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.AndroidViewModel 5 | import androidx.lifecycle.LiveData 6 | import com.rishav.buckoid.Database.TransactionDatabase 7 | import com.rishav.buckoid.Model.Transaction 8 | import com.rishav.buckoid.Repository.TransactionRepository 9 | 10 | 11 | class TransactionViewModel(application: Application): AndroidViewModel(application) { 12 | 13 | val repository: TransactionRepository 14 | 15 | init{ 16 | val dao = TransactionDatabase.getDatabaseInstance(application).myTransactionDao() 17 | repository= TransactionRepository(dao) 18 | } 19 | 20 | fun addTransaction(transaction: Transaction){ 21 | repository.insertTransaction(transaction) 22 | } 23 | 24 | fun getTransaction(): LiveData> = repository.getAllTransaction() 25 | 26 | fun getMonthlyTransaction(month:Int,Year:Int): LiveData> = repository.getMonthlyTransaction(month,Year) 27 | 28 | fun getYearlyTransaction(year: Int): LiveData> = repository.getYearlyTransaction(year) 29 | 30 | fun deleteTransaction(id:Int){ 31 | repository.deleteTransaction(id) 32 | } 33 | 34 | fun updateTransaction(transaction: Transaction){ 35 | repository.updateTransaction(transaction) 36 | } 37 | 38 | 39 | 40 | 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/fragments/Authentication/UserDetails.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.fragments.Authentication 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Intent 5 | import android.content.SharedPreferences 6 | import android.os.Bundle 7 | import androidx.fragment.app.Fragment 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.widget.Toast 12 | import androidx.appcompat.app.AppCompatActivity 13 | import androidx.core.content.ContextCompat 14 | import com.google.android.gms.auth.api.signin.GoogleSignIn 15 | import com.rishav.buckoid.MainActivity 16 | import com.rishav.buckoid.R 17 | import com.rishav.buckoid.databinding.FragmentUserDetailsBinding 18 | 19 | class UserDetails : Fragment() { 20 | 21 | lateinit var binding:FragmentUserDetailsBinding 22 | lateinit var userDetails: SharedPreferences 23 | override fun onCreateView( 24 | inflater: LayoutInflater, container: ViewGroup?, 25 | savedInstanceState: Bundle? 26 | ): View{ 27 | // Inflate the layout for this fragment 28 | getActivity()?.getWindow()?.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.background)) 29 | binding= FragmentUserDetailsBinding.inflate(inflater, container, false) 30 | setData() 31 | return binding.root 32 | } 33 | 34 | @SuppressLint("SetTextI18n") 35 | private fun setData() { 36 | val googleSignInAccount = GoogleSignIn.getLastSignedInAccount(requireActivity()) 37 | val name=googleSignInAccount?.displayName.toString().split(" ") 38 | binding.text1.text = "Good to go \n${name[0]} !!" 39 | userDetails = requireActivity().getSharedPreferences("UserDetails", AppCompatActivity.MODE_PRIVATE) 40 | binding.next.setOnClickListener { 41 | saveUserData() 42 | } 43 | } 44 | 45 | private fun goToNextScreen() { 46 | val intent = Intent(requireActivity(), MainActivity::class.java) 47 | startActivity(intent) 48 | } 49 | 50 | private fun saveUserData() { 51 | val monthly_budget = binding.editMoney.text.toString() 52 | val yearly_budget = binding.editYearMoney 53 | if(monthly_budget.equals("") || yearly_budget.text.toString().equals("")) { 54 | Toast.makeText(requireActivity(), "Enter all details to continue...", Toast.LENGTH_SHORT).show() 55 | }else{ 56 | val editor: SharedPreferences.Editor = userDetails.edit() 57 | editor.putBoolean("isFirstTime", false) 58 | editor.putString("MonthlyBudget", monthly_budget) 59 | editor.putString("YearlyBudget", yearly_budget.text.toString()) 60 | editor.apply() 61 | goToNextScreen() 62 | } 63 | } 64 | 65 | 66 | 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/fragments/Authentication/UserSignUp.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.fragments.Authentication 2 | 3 | import android.R.attr 4 | import android.app.Activity 5 | import android.content.Intent 6 | import android.os.Bundle 7 | import android.util.Log 8 | import androidx.fragment.app.Fragment 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import androidx.activity.result.contract.ActivityResultContracts 13 | import com.google.android.gms.auth.api.signin.GoogleSignIn 14 | import com.google.android.gms.auth.api.signin.GoogleSignInAccount 15 | import com.google.android.gms.auth.api.signin.GoogleSignInClient 16 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions 17 | import com.google.android.gms.common.Scopes 18 | import com.google.android.gms.common.api.ApiException 19 | import com.google.android.gms.common.api.Scope 20 | import com.google.android.gms.tasks.Task 21 | import com.google.api.client.extensions.android.http.AndroidHttp 22 | import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential 23 | import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException 24 | import com.google.api.client.http.FileContent 25 | import com.google.api.client.json.gson.GsonFactory 26 | import com.google.api.services.drive.Drive 27 | import com.google.api.services.drive.DriveScopes 28 | import com.rishav.buckoid.databinding.FragmentUserSignUpBinding 29 | import java.util.* 30 | import com.google.api.services.drive.model.FileList 31 | import java.io.File 32 | import java.io.FileOutputStream 33 | import java.io.IOException 34 | import java.io.OutputStream 35 | import android.R.attr.data 36 | import android.widget.Toast 37 | import androidx.core.content.ContextCompat 38 | import androidx.navigation.NavOptions 39 | import androidx.navigation.Navigation 40 | import androidx.navigation.Navigation.findNavController 41 | import com.rishav.buckoid.R 42 | 43 | 44 | class UserSignUp : Fragment() { 45 | lateinit var binding:FragmentUserSignUpBinding 46 | lateinit var client: GoogleSignInClient 47 | override fun onCreateView( 48 | inflater: LayoutInflater, container: ViewGroup?, 49 | savedInstanceState: Bundle? 50 | ): View? { 51 | // Inflate the layout for this fragment 52 | getActivity()?.getWindow()?.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.background)) 53 | binding= FragmentUserSignUpBinding.inflate(inflater, container, false) 54 | 55 | setUpSignUp() 56 | binding.googleSignUp.setOnClickListener{ 57 | signIn() 58 | } 59 | return binding.root 60 | } 61 | 62 | private fun setUpSignUp() { 63 | val account = GoogleSignIn.getLastSignedInAccount(requireActivity()) 64 | if (account!=null){ 65 | goToNextPage() 66 | } 67 | googleCall() 68 | } 69 | fun googleCall(){ 70 | val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 71 | .requestEmail() 72 | .requestScopes(Scope(DriveScopes.DRIVE_FILE)) 73 | .build() 74 | client = GoogleSignIn.getClient(requireActivity(), gso) 75 | } 76 | private fun signIn() { 77 | val signInIntent: Intent = client.signInIntent 78 | getResult.launch(signInIntent) 79 | } 80 | private val getResult = 81 | registerForActivityResult( 82 | ActivityResultContracts.StartActivityForResult() 83 | ) { 84 | if (it.resultCode == Activity.RESULT_OK) { 85 | goToNextPage() 86 | }else{ 87 | notifyUser("Check Your Network Connection and Try again") 88 | } 89 | } 90 | 91 | private fun notifyUser(message: String) { 92 | Toast.makeText(requireContext(),message, Toast.LENGTH_SHORT).show() 93 | } 94 | 95 | private fun goToNextPage() { 96 | findNavController(requireActivity(),R.id.fragmentContainerView2) 97 | .navigate(R.id.goToUserDetails, 98 | null, 99 | NavOptions.Builder() 100 | .setPopUpTo(R.id.userSignUp, 101 | true).build() 102 | ) 103 | } 104 | 105 | /* 106 | private fun handleSignInResult(completedTask: Task) { 107 | try { 108 | val account = completedTask.getResult(ApiException::class.java) 109 | } catch (e: ApiException) { 110 | } 111 | } 112 | 113 | private fun handle(){ 114 | val googleSignInAccount = GoogleSignIn.getLastSignedInAccount(requireActivity()) 115 | val credential = 116 | GoogleAccountCredential.usingOAuth2(requireContext(), Collections.singleton(Scopes.DRIVE_FILE)) 117 | credential.selectedAccount = googleSignInAccount!!.account 118 | val googleDriveService = Drive.Builder( 119 | AndroidHttp.newCompatibleTransport(), 120 | GsonFactory(), 121 | credential 122 | ) 123 | .setApplicationName(getString(com.rishav.buckoid.R.string.app_name)) 124 | .build() 125 | Thread { 126 | Download(googleDriveService) 127 | }.start() 128 | 129 | 130 | } 131 | 132 | private fun handleSignInIntent(data: Intent?) { 133 | 134 | GoogleSignIn.getSignedInAccountFromIntent(data) 135 | .addOnSuccessListener { 136 | val credential: GoogleAccountCredential = GoogleAccountCredential 137 | .usingOAuth2(requireActivity(), Collections.singleton(DriveScopes.DRIVE_FILE)) 138 | credential.setSelectedAccount(it.account) 139 | val googleDriveDevices: Drive = Drive.Builder( 140 | AndroidHttp.newCompatibleTransport(), 141 | GsonFactory(), 142 | credential) 143 | .setApplicationName("Buckoid") 144 | .build() 145 | 146 | Thread(Runnable { 147 | Download(googleDriveDevices) 148 | }).start() 149 | } 150 | .addOnFailureListener{ 151 | 152 | } 153 | 154 | } 155 | 156 | private fun upload(googleDriveDevices:Drive){ 157 | var storageFile:com.google.api.services.drive.model.File? = null 158 | storageFile?.setParents(Collections.singletonList("appDataFolder")) 159 | storageFile?.setName("Buckoid_Backup_Transaction") 160 | 161 | val filePath:java.io.File = java.io.File(dbPath) 162 | val mediaContent:FileContent = FileContent("",filePath) 163 | try { 164 | val file: com.google.api.services.drive.model.File? = googleDriveDevices.files().create(storageFile,mediaContent).execute(); 165 | if (file != null) { 166 | Log.w("@@@","Filename: %s File ID: %s ${file.getName()}, ${file.getId()}") 167 | } 168 | } 169 | catch(e: UserRecoverableAuthIOException){ 170 | Log.w("@@@","errorAuthIO:"+e.message.toString()) 171 | } 172 | catch (e:Exception) { 173 | Log.w("@@@","error:"+e.message.toString()) 174 | } 175 | } 176 | 177 | private fun Download(googleDriveService:Drive) { 178 | try { 179 | val dir = File("/data/data/com.rishav.buckoid/databases") 180 | if (dir.isDirectory) { 181 | val children = dir.list() 182 | for (i in children.indices) { 183 | File(dir, children[i]).delete() 184 | } 185 | } 186 | val files: FileList = googleDriveService.files().list() 187 | .setSpaces("appDataFolder") 188 | .setFields("nextPageToken, files(id, name, createdTime)") 189 | .setPageSize(10) 190 | .execute() 191 | if (files.files.size == 0) Log.e("@@@", "No DB file exists in Drive") 192 | for (file in files.files) { 193 | Log.e("@@@", "Found file: ${file.name}, ${file.id}, ${file.createdTime}") 194 | if (file.name.equals("Buckoid_Backup_Transaction")) { 195 | val outputStream: OutputStream = FileOutputStream(dbPath) 196 | googleDriveService.files().get(file.id).executeMediaAndDownloadTo(outputStream) 197 | } 198 | } 199 | } catch (e: IOException) { 200 | Log.w("@@@","error:"+e.message.toString()) 201 | } 202 | }*/ 203 | 204 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/fragments/BackupDrive.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.fragments 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import androidx.fragment.app.Fragment 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.Toast 10 | import androidx.navigation.Navigation 11 | import com.google.android.gms.common.Scopes 12 | import com.google.android.material.bottomnavigation.BottomNavigationView 13 | import com.google.api.client.extensions.android.http.AndroidHttp 14 | import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential 15 | import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException 16 | import com.google.api.client.http.FileContent 17 | import com.google.api.client.json.gson.GsonFactory 18 | import com.google.api.services.drive.Drive 19 | import com.google.api.services.drive.model.FileList 20 | import com.rishav.buckoid.R 21 | import com.rishav.buckoid.databinding.FragmentBackupDriveBinding 22 | import com.rishav.buckoid.Model.Profile 23 | import java.io.FileOutputStream 24 | import java.io.IOException 25 | import java.io.OutputStream 26 | import java.util.* 27 | 28 | class BackupDrive : Fragment() { 29 | 30 | lateinit var binding:FragmentBackupDriveBinding 31 | lateinit var profileModel:Profile 32 | private val dbPath = "/data/data/com.rishav.buckoid/databases/Transaction" 33 | private val dbPathWal = "/data/data/com.rishav.buckoid/databases/Transaction-wal" 34 | private val dbPathShm = "/data/data/com.rishav.buckoid/databases/Transaction-shm" 35 | override fun onCreateView( 36 | inflater: LayoutInflater, container: ViewGroup?, 37 | savedInstanceState: Bundle? 38 | ): View{ 39 | // Inflate the layout for this fragment 40 | binding = FragmentBackupDriveBinding.inflate(inflater, container, false) 41 | val bottomNav: BottomNavigationView = requireActivity().findViewById(R.id.bottomNavigation) 42 | bottomNav.visibility = View.GONE 43 | 44 | setData() 45 | return binding.root 46 | } 47 | 48 | private fun setData() { 49 | binding.back.setOnClickListener { 50 | Navigation.findNavController(binding.root).navigate(R.id.action_backupDrive_to_profile) 51 | } 52 | 53 | binding.backupBtn.setOnClickListener{ 54 | //backupdata() 55 | Toast.makeText(requireActivity(),"Coming Soon wait for an Update.", Toast.LENGTH_SHORT).show() 56 | //notifyUser("Coming Soon wait for an Update.") 57 | } 58 | } 59 | 60 | private fun notifyUser(message: String) { 61 | Toast.makeText(requireActivity(),message, Toast.LENGTH_SHORT).show() 62 | } 63 | 64 | private fun backupdata() { 65 | profileModel = Profile(requireContext()) 66 | val googleSignInAccount = profileModel.account 67 | val credential = 68 | GoogleAccountCredential.usingOAuth2(requireContext(), Collections.singleton(Scopes.DRIVE_FILE)) 69 | credential.selectedAccount = googleSignInAccount!!.account 70 | val googleDriveService = Drive.Builder( 71 | AndroidHttp.newCompatibleTransport(), 72 | GsonFactory(), 73 | credential 74 | ) 75 | .setApplicationName(getString(com.rishav.buckoid.R.string.app_name)) 76 | .build() 77 | Thread { 78 | upload(googleDriveService) 79 | }.start() 80 | } 81 | 82 | private fun upload(googleDriveDevices:Drive){ 83 | val storageFile:com.google.api.services.drive.model.File =com.google.api.services.drive.model.File() 84 | //storageFile.setParents(Collections.singletonList("appDataFolder")) 85 | storageFile.setName("Transaction") 86 | 87 | val storageFileShm:com.google.api.services.drive.model.File = com.google.api.services.drive.model.File() 88 | //storageFile.setParents(Collections.singletonList("appDataFolder")) 89 | storageFile.setName("Transaction-shm") 90 | 91 | val storageFileWal:com.google.api.services.drive.model.File = com.google.api.services.drive.model.File() 92 | //storageFile.setParents(Collections.singletonList("appDataFolder")) 93 | storageFile.setName("Transaction-wal") 94 | 95 | val filePath:java.io.File = java.io.File(dbPath) 96 | //val filePathShm:java.io.File = java.io.File(dbPathShm) 97 | //val filePathWal:java.io.File = java.io.File(dbPathWal) 98 | val mediaContent:FileContent = FileContent("",filePath) 99 | //val mediaContentShm:FileContent = FileContent("",filePathShm) 100 | //val mediaContentWal:FileContent = FileContent("",filePathWal) 101 | try { 102 | val file: com.google.api.services.drive.model.File? = googleDriveDevices.files().create(storageFile,mediaContent).execute(); 103 | if (file != null) { 104 | Log.w("@@@","Filename: %s File ID: %s ${file.getName()}, ${file.getId()}") 105 | } 106 | 107 | /*val fileWal: com.google.api.services.drive.model.File? = googleDriveDevices.files().create(storageFile,mediaContentWal).execute(); 108 | if (fileWal != null) { 109 | Log.w("@@@","Filename: %s File ID: %s ${fileWal.getName()}, ${fileWal.getId()}") 110 | } 111 | val fileShm: com.google.api.services.drive.model.File? = googleDriveDevices.files().create(storageFileShm,mediaContentShm).execute(); 112 | if (fileShm != null) { 113 | Log.w("@@@","Filename: %s File ID: %s ${fileShm.getName()}, ${fileShm.getId()}") 114 | }*/ 115 | 116 | } 117 | catch(e: UserRecoverableAuthIOException){ 118 | Log.w("@@@","errorAuthIO:"+e.message.toString()) 119 | } 120 | catch (e:Exception) { 121 | Log.w("@@@","error:"+e.message.toString()) 122 | } 123 | } 124 | 125 | 126 | private fun Download(googleDriveService:Drive) { 127 | try { 128 | val dir = java.io.File("/data/data/com.rishav.buckoid/databases") 129 | if (dir.isDirectory) { 130 | val children = dir.list() 131 | for (i in children.indices) { 132 | Log.e("@@@", "Found file: ${children[i]}") 133 | java.io.File(dir, children[i]).delete() 134 | } 135 | //Log.e("@@@", "Found file: ${children}") 136 | 137 | val files: FileList = googleDriveService.files().list() 138 | //.setSpaces("appDataFolder") 139 | .setFields("nextPageToken, files(id, name, createdTime, size)") 140 | .setPageSize(10) 141 | .execute() 142 | if (files.files.size == 0) Log.e("@@@", "No DB file exists in Drive") 143 | for (file in files.files) { 144 | Log.e("@@@", "Found file: ${file.name}, ${file.id}, ${file.createdTime}, ${file.size}") 145 | if (file.name.equals("Transaction")) { 146 | val outputStream: OutputStream = FileOutputStream(dbPath) 147 | googleDriveService.files().get(file.id).executeMediaAndDownloadTo(outputStream) 148 | }else if(file.getName().equals("Transaction-shm")){ 149 | val outputStream: OutputStream = FileOutputStream(dbPathShm) 150 | googleDriveService.files().get(file.id).executeMediaAndDownloadTo(outputStream) 151 | } 152 | else if(file.getName().equals("Transaction-wal")){ 153 | val outputStream: OutputStream = FileOutputStream(dbPathWal) 154 | googleDriveService.files().get(file.id).executeMediaAndDownloadTo(outputStream) 155 | } 156 | } 157 | Log.e("@@@", "Found file: ${children}") 158 | } 159 | } catch (e: IOException) { 160 | Log.w("@@@","error:"+e.message.toString()) 161 | } 162 | } 163 | 164 | 165 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/fragments/Dashboard.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.fragments 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.SharedPreferences 5 | import android.os.Bundle 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import androidx.activity.OnBackPressedCallback 10 | import androidx.appcompat.app.AppCompatActivity 11 | import androidx.core.content.ContextCompat 12 | import androidx.fragment.app.Fragment 13 | import androidx.fragment.app.viewModels 14 | import androidx.navigation.Navigation 15 | import androidx.recyclerview.widget.LinearLayoutManager 16 | import com.rishav.buckoid.Adapter.TransactionAdapter 17 | import com.rishav.buckoid.Model.Transaction 18 | import com.rishav.buckoid.R 19 | import com.rishav.buckoid.ViewModel.TransactionViewModel 20 | import com.rishav.buckoid.databinding.FragmentDashboardBinding 21 | import com.google.android.material.bottomnavigation.BottomNavigationView 22 | import org.eazegraph.lib.models.PieModel 23 | import java.text.SimpleDateFormat 24 | import java.util.* 25 | import androidx.core.view.GravityCompat 26 | import androidx.drawerlayout.widget.DrawerLayout 27 | import com.bumptech.glide.Glide 28 | import com.google.android.material.navigation.NavigationView 29 | import com.rishav.buckoid.Model.Profile 30 | import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt 31 | 32 | class Dashboard : Fragment() { 33 | 34 | lateinit var binding:FragmentDashboardBinding 35 | private val viewModel: TransactionViewModel by viewModels() 36 | private var totalExpense = 0.0 37 | private var totalGoal = 5000.0f 38 | private var totalFood = 0.0f 39 | private var totalShopping = 0.0f 40 | private var totalTransport=0.0f 41 | private var totalHealth = 0.0f 42 | private var totalOthers = 0.0f 43 | private var totalAcademics = 0.0f 44 | lateinit var drawerLayout:DrawerLayout 45 | lateinit var navigationView:NavigationView 46 | lateinit var userDetails: SharedPreferences 47 | lateinit var profileModel: Profile 48 | 49 | override fun onCreateView( 50 | inflater: LayoutInflater, container: ViewGroup?, 51 | savedInstanceState: Bundle? 52 | ): View { 53 | // Inflate the layout for this fragment 54 | getActivity()?.getWindow()?.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.background)) 55 | binding = FragmentDashboardBinding.inflate(inflater, container, false) 56 | val bottomNav: BottomNavigationView = requireActivity().findViewById(R.id.bottomNavigation) 57 | drawerLayout = requireActivity().findViewById(R.id.drawer_layout) 58 | navigationView = requireActivity().findViewById(R.id.navigationView) 59 | bottomNav.visibility = View.VISIBLE 60 | navigationDrawer() 61 | getData() 62 | val arg = DashboardDirections.actionDashboard2ToAddTransaction(Transaction(null,"","","",0.0,"",0,0,0,""),false) 63 | binding.addNew.setOnClickListener{Navigation.findNavController(binding.root).navigate(arg)} 64 | return binding.root 65 | } 66 | 67 | 68 | //calling data from room database using livedata view model 69 | @SuppressLint("SetTextI18n", "SimpleDateFormat") 70 | private fun getData() { 71 | var format = SimpleDateFormat("MM") 72 | val currentMonth = format.format(Calendar.getInstance().getTime()) 73 | format = SimpleDateFormat("yyyy") 74 | val currentYear = format.format(Calendar.getInstance().getTime()) 75 | format = SimpleDateFormat("MMMM") 76 | binding.date.text = "${format.format(Calendar.getInstance().getTime())} ${currentYear}" 77 | 78 | userDetails = requireActivity().getSharedPreferences("UserDetails", AppCompatActivity.MODE_PRIVATE) 79 | profileModel = Profile(requireContext()) 80 | val name=profileModel.name.split(" ") 81 | binding.name.text = "Hi ${name[0]} !!" 82 | Glide.with(requireActivity()).load(profileModel.profilePic).into(binding.profilePic) 83 | 84 | if(!userDetails.getBoolean("ShowedOnboardingDashboard",false)){ 85 | showOnBoarding() 86 | } 87 | 88 | totalExpense = 0.0 89 | totalGoal = userDetails.getString("MonthlyBudget","0")?.toFloat()!! 90 | totalFood = 0.0f 91 | totalShopping = 0.0f 92 | totalTransport=0.0f 93 | totalHealth = 0.0f 94 | totalOthers = 0.0f 95 | totalAcademics = 0.0f 96 | viewModel.getMonthlyTransaction(currentMonth.toInt(),currentYear.toInt()).observe(viewLifecycleOwner,{ transactionList -> 97 | if(transactionList.isEmpty()){ 98 | binding.noTransactionsDoneText.text = "Add Your First Transaction of ${format.format(Calendar.getInstance().getTime())} $currentYear \n Click On + to add Transactions" 99 | binding.noTransactionsDoneText.visibility = View.VISIBLE 100 | binding.transactionRecyclerView.visibility = View.GONE 101 | binding.text1.visibility = View.GONE 102 | } 103 | else { 104 | binding.text1.visibility = View.VISIBLE 105 | binding.noTransactionsDoneText.visibility = View.GONE 106 | binding.transactionRecyclerView.visibility = View.VISIBLE 107 | } 108 | binding.transactionRecyclerView.layoutManager = 109 | LinearLayoutManager(requireContext()) 110 | binding.transactionRecyclerView.adapter = 111 | TransactionAdapter(requireContext(),requireActivity(), "Dashboard", transactionList.reversed()) 112 | 113 | for (i in transactionList) { 114 | totalExpense += i.amount 115 | when (i.category) { 116 | "Food" -> { 117 | totalFood += (i.amount.toFloat()) 118 | } 119 | "Shopping" -> { 120 | totalShopping += (i.amount.toFloat()) 121 | } 122 | "Transport" -> { 123 | totalTransport += (i.amount.toFloat()) 124 | } 125 | 126 | "Health" -> { 127 | totalHealth += (i.amount.toFloat()) 128 | } 129 | "Other" -> { 130 | totalOthers += (i.amount.toFloat()) 131 | } 132 | "Education" -> { 133 | totalAcademics += (i.amount.toFloat()) 134 | } 135 | } 136 | } 137 | binding.expense.text = "₹${totalExpense.toInt()}" 138 | binding.budget.text = "₹${totalGoal.toInt()}" 139 | if (totalExpense > totalGoal) { 140 | binding.indicator.setImageResource(R.drawable.ic_negative_transaction) 141 | binding.expense.setTextColor( 142 | ContextCompat.getColor( 143 | requireContext(), 144 | R.color.red 145 | ) 146 | ) 147 | } else { 148 | binding.indicator.setImageResource(R.drawable.ic_positive_amount) 149 | } 150 | showPiChart() 151 | 152 | }) 153 | 154 | } 155 | 156 | //To show PiChart to main card to users 157 | private fun showPiChart() { 158 | val mPieChart = binding.piechart 159 | 160 | mPieChart.addPieSlice(PieModel("Food", totalFood, ContextCompat.getColor(requireContext(), R.color.yellow))) 161 | mPieChart.addPieSlice(PieModel("Shopping", totalShopping, ContextCompat.getColor(requireContext(), R.color.lightBlue))) 162 | mPieChart.addPieSlice(PieModel("Health", totalHealth, ContextCompat.getColor(requireContext(), R.color.red))) 163 | mPieChart.addPieSlice(PieModel("Others", totalOthers, ContextCompat.getColor(requireContext(), R.color.lightBrown))) 164 | mPieChart.addPieSlice(PieModel("Transport", totalTransport, ContextCompat.getColor(requireContext(), R.color.violet))) 165 | mPieChart.addPieSlice(PieModel("Academics", totalAcademics, ContextCompat.getColor(requireContext(), R.color.green))) 166 | 167 | if (totalGoal>totalExpense){ 168 | mPieChart.addPieSlice(PieModel("Left",totalGoal-(totalExpense.toFloat()) , ContextCompat.getColor(requireContext(), R.color.background_deep))) 169 | } 170 | 171 | mPieChart.startAnimation() 172 | 173 | } 174 | 175 | 176 | //navigationDrawer 177 | private fun navigationDrawer() { 178 | navigationView.bringToFront() 179 | binding.drawerMenu.setOnClickListener{ 180 | if (drawerLayout.isDrawerVisible(GravityCompat.START)) { 181 | drawerLayout.closeDrawer(GravityCompat.START) 182 | } else { 183 | drawerLayout.openDrawer(GravityCompat.START) 184 | } 185 | } 186 | 187 | requireActivity() 188 | .onBackPressedDispatcher 189 | .addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) { 190 | override fun handleOnBackPressed() { 191 | if (drawerLayout.isDrawerVisible(GravityCompat.START)) { 192 | drawerLayout.closeDrawer(GravityCompat.START) 193 | }else { 194 | requireActivity().finish() 195 | } 196 | } 197 | } 198 | ) 199 | 200 | } 201 | 202 | fun showOnBoarding(){ 203 | MaterialTapTargetPrompt.Builder(requireActivity()) 204 | .setTarget(binding.addNew) 205 | .setPrimaryText("Hey Click Me!!") 206 | .setFocalRadius(100.0f) 207 | .setSecondaryText("Good to go... Add your first Transaction by Clicking on this Add Button") 208 | .setBackButtonDismissEnabled(true) 209 | .setPromptStateChangeListener{prompt, state -> 210 | if(state == MaterialTapTargetPrompt.STATE_FOCAL_PRESSED || state == MaterialTapTargetPrompt.STATE_NON_FOCAL_PRESSED){ 211 | val editor: SharedPreferences.Editor = userDetails.edit() 212 | editor.putBoolean("ShowedOnboardingDashboard", true) 213 | editor.apply() 214 | } 215 | } 216 | .show() 217 | 218 | } 219 | 220 | 221 | 222 | } 223 | 224 | 225 | -------------------------------------------------------------------------------- /app/src/main/java/com/rishav/buckoid/fragments/TransactionDetails.kt: -------------------------------------------------------------------------------- 1 | package com.rishav.buckoid.fragments 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import androidx.fragment.app.Fragment 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.Button 10 | import androidx.activity.OnBackPressedCallback 11 | import androidx.core.content.ContextCompat 12 | import androidx.fragment.app.viewModels 13 | import androidx.navigation.Navigation 14 | import androidx.navigation.fragment.navArgs 15 | import com.rishav.buckoid.R 16 | import com.rishav.buckoid.ViewModel.TransactionViewModel 17 | import com.rishav.buckoid.databinding.FragmentTransactionDetailsBinding 18 | import com.google.android.material.bottomnavigation.BottomNavigationView 19 | import com.google.android.material.bottomsheet.BottomSheetDialog 20 | 21 | class TransactionDetails : Fragment() { 22 | 23 | val transaction by navArgs() 24 | private val viewModel: TransactionViewModel by viewModels() 25 | lateinit var binding: FragmentTransactionDetailsBinding 26 | @SuppressLint("SetTextI18n") 27 | override fun onCreateView( 28 | inflater: LayoutInflater, container: ViewGroup?, 29 | savedInstanceState: Bundle? 30 | ): View { 31 | // Inflate the layout for this fragment 32 | activity?.window?.statusBarColor = ContextCompat.getColor(requireActivity(), R.color.background) 33 | binding = FragmentTransactionDetailsBinding.inflate(inflater, container, false) 34 | 35 | val bottomNav: BottomNavigationView = requireActivity().findViewById(R.id.bottomNavigation) 36 | bottomNav.visibility = View.GONE 37 | 38 | binding.title.text = transaction.data.title 39 | binding.amount.text= "₹${transaction.data.amount}" 40 | binding.category.text = transaction.data.category 41 | binding.date.text = transaction.data.date 42 | binding.note.text = transaction.data.note 43 | 44 | binding.back.setOnClickListener { 45 | if(transaction.fragment == "Dashboard"){ 46 | Navigation.findNavController(binding.root).navigate(R.id.action_transactionDetails_to_dashboard2) 47 | }else if(transaction.fragment == "AllTransactions"){ 48 | Navigation.findNavController(binding.root).navigate(R.id.action_transactionDetails_to_transactions) 49 | }else{ 50 | Navigation.findNavController(binding.root).navigate(R.id.action_transactionDetails_to_dashboard2) 51 | } 52 | } 53 | requireActivity() 54 | .onBackPressedDispatcher 55 | .addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) { 56 | override fun handleOnBackPressed() { 57 | if(transaction.fragment == "Dashboard"){ 58 | Navigation.findNavController(binding.root).navigate(R.id.action_transactionDetails_to_dashboard2) 59 | }else if(transaction.fragment == "AllTransactions"){ 60 | Navigation.findNavController(binding.root).navigate(R.id.action_transactionDetails_to_transactions) 61 | }else{ 62 | Navigation.findNavController(binding.root).navigate(R.id.action_transactionDetails_to_dashboard2) 63 | } 64 | } 65 | } 66 | ) 67 | 68 | binding.edit.setOnClickListener { 69 | val argument = TransactionDetailsDirections.actionTransactionDetailsToAddTransaction(transaction.data,true) 70 | Navigation.findNavController(binding.root).navigate(argument) 71 | } 72 | binding.delete.setOnClickListener { deleteTransaction() } 73 | return binding.root 74 | } 75 | 76 | private fun deleteTransaction() { 77 | val bottomDialog: BottomSheetDialog = BottomSheetDialog(requireContext(),R.style.bottom_dialog) 78 | bottomDialog.setContentView(R.layout.dialog_delete) 79 | 80 | val delete=bottomDialog.findViewById