├── .gitignore ├── .idea ├── assetWizardSettings.xml ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── SRS-ExpenseManager ├── Sreenshots ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png └── 6.png ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── shashank │ │ └── expensemanager │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ │ └── com │ │ │ └── shashank │ │ │ └── expensemanager │ │ │ ├── activities │ │ │ ├── AddExpenseActivity.java │ │ │ ├── MainActivity.java │ │ │ └── SplashScreen.java │ │ │ ├── adapters │ │ │ ├── CustomAdapter.java │ │ │ └── SectionsPageAdapter.java │ │ │ ├── fragments │ │ │ ├── BalanceFragment.java │ │ │ ├── CustomBottomSheetDialogFragment.java │ │ │ └── ExpenseFragment.java │ │ │ ├── transactionDb │ │ │ ├── AppDatabase.java │ │ │ ├── AppExecutors.java │ │ │ ├── DateConverter.java │ │ │ ├── TransactionDao.java │ │ │ ├── TransactionEntry.java │ │ │ └── TransactionViewModel.java │ │ │ └── utils │ │ │ ├── Constants.java │ │ │ └── ExpenseList.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_account_balance_wallet_white_24dp.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── splash_background.xml │ │ └── splashlogo.xml │ │ ├── layout │ │ ├── activity_add_expense.xml │ │ ├── activity_main.xml │ │ ├── bottom_sheet_fragment.xml │ │ ├── fragment_balance.xml │ │ ├── fragment_expense.xml │ │ └── list_item.xml │ │ ├── menu │ │ ├── add_expense_activty_menu.xml │ │ └── menu_main.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 │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── shashank │ └── expensemanager │ └── ExampleUnitTest.java ├── 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/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.idea/assetWizardSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 98 | 99 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Expense-Manager 2 | What is Expense Manager? 3 | 4 | An app which will make you keep track of your cash transactions systematically. 5 | 6 | Features: 7 | 1. Add your expense/income the next time you spend/earn cash and save category of expense. 8 | 2. View your cash transactions at any time systematically. 9 | 3. Sort transactions by month and week. 10 | 4. No internet connection required , the app works completely offline. 11 | 12 | P.S. We don't save your location( or any other metadata) ; this app is for your convenience only. 13 | 14 | Start with this app to inculcate a systematic approach in your life. 15 | 16 | # Some ScreenShots: 17 | 18 | 19 | 20 | 24 |
25 |
26 |
27 | 31 | -------------------------------------------------------------------------------- /SRS-ExpenseManager: -------------------------------------------------------------------------------- 1 | TABLE OF CONTENT 2 | 3 | 1) Introduction 4 | 1.1) Purpose 5 | 1.2) Document Convention 6 | 1.3) Intended Audience 7 | 8 | 2) Overall Description 9 | 2.1) Product Perspective 10 | 2.2) User Classes and Characteristics 11 | 2.3) Operating Environment 12 | 2.4) Design 13 | 14 | 3) Functionality 15 | 3.1) Activity1 16 | 3.2) Activity2 17 | 18 | 4) External Interface Requirement 19 | 4.1) User Interfaces 20 | 4.2) Hardware Interfaces 21 | 22 | 5) Security 23 | 24 | 25 | 26 | 27 | 28 | 29 | 1 INTRODUCTION 30 | 31 | 1.1 Purpose 32 | Purpose of this document is to build an expense management 33 | system for general people to keep a record of their expenses in a 34 | systematic manner . 35 | 36 | 37 | 1.2 Document Convention 38 | app Android application 39 | 40 | 41 | 1.3 Intended Audience 42 | Anyone who struggles with keeping track of expenditures. 43 | Particularly college students and working professionals. 44 | 45 | 46 | 47 | 2 OVERALL DESCRIPTION 48 | 49 | 2.1 Product Perspective 50 | The app stores each transaction done by the user . 51 | The user has to manually enter each traction . 52 | Each transaction has 3 characteristics : 53 | a) Amount 54 | b) Income/Expenditure 55 | c) Category 56 | 57 | * 2.2 User Classes and Characteristics 58 | 59 | 60 | 2.3 Operating Environment 61 | Application 62 | Android Studio 3.1 63 | Android Studio 3.2 64 | Operating System 65 | Ubuntu 18.04 66 | Windows 10 67 | Intended for 68 | Android API 26 and above 69 | 70 | 2.4 Design 71 | Concepts used 72 | Recycler View 73 | Fragments 74 | Tabbed Layout 75 | Material Design 76 | Card view 77 | Layout [ Linear , Constraint ] 78 | Date picker 79 | Calendar 80 | Architecture Components [ Room , Entiity , LiveData 81 | ViewModel ] 82 | SQLite database 83 | 84 | 85 | Dependencies 86 | MPChartLibrary [ for PieChart ] 87 | Material Design 88 | Card View 89 | App Compat 90 | 91 | 92 | 93 | 94 | 3 FUNCTIONALITY 95 | 96 | 3.1 Activity 1 [ Main Activity ] 97 | This is the activity that the user is greeted with . 98 | It has 2 fragments : Expenses and Balance 99 | 100 | Balance : 101 | Spinner gives options : all(default) , week or month and 102 | defines timeframe . 103 | Income textField displays the total income by querying the 104 | database . 105 | Similarly Expense testField total expenditure with defined 106 | timeframe . 107 | Effective balance is calculated as total income - total expense 108 | and displayed in another textfield . It supports negative values. 109 | All transactions occur only in non-negative integers . 110 | A 3rd party library MPChart is used to display all data in 111 | a Pie-chart format . 112 | 113 | Expense : A recycler view has been utilised which generates 114 | multiple card views . Each card view displays 1 transaction 115 | including details : amount , date , category and comment . 116 | The transaction details are fetched from the SQLite database 117 | stored locally . It is displayed in decreasing date-wise order 118 | ie: most recent to oldest . 119 | There is a floating Action Button which on clicking pulls up an 120 | Bottom Sheet Layout . It gives option between "Add Expense" and 121 | "Add Income" . On selecting either option , Activity 2 is opened . 122 | Includes feature to swipe-right to delete a transaction . 123 | Correspondingly , it deletes transaction from the SQLite database. 124 | On tapping on any of the card view , you can edit any transaction 125 | after having created it . 126 | 127 | 128 | 3.2 Activity 2 129 | If "Add Income" is opted for then , 130 | It asks for 131 | Amount 132 | Date 133 | Description 134 | Category is disabled. 135 | 136 | If "Add Expense" is opted for then , 137 | IT asks for 138 | Amount 139 | Date 140 | Description 141 | Category 142 | Category is a spinner and provides options : 143 | [Food,Travel,Clothes,Movies,Health,Grocery,Other] 144 | 145 | Each field is mandatory 146 | 147 | Date uses a date-picker 148 | 149 | Amount and Description fields are a combination of 150 | TextView and EditText in a TextInput Layout[ material design ] 151 | 152 | 153 | 154 | 155 | 4 EXTERNAL INTERFACE REQUIREMENTS 156 | 157 | 4.1 User Interfaces 158 | Front-end : XML 159 | Back-end : SQLite 160 | 161 | 4.2 Hardware Interfaces 162 | AndroidOS Oreo and above 163 | 164 | 165 | 166 | 167 | 5 SECURITY 168 | Since this application uses local storage for data 169 | and it does not communicate with any network , it is inherently 170 | secure . It is not susceptible to any MITM(Man In The Middle Attacks) 171 | It is only susceptible to remote code execution . 172 | -------------------------------------------------------------------------------- /Sreenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/Sreenshots/1.png -------------------------------------------------------------------------------- /Sreenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/Sreenshots/2.png -------------------------------------------------------------------------------- /Sreenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/Sreenshots/3.png -------------------------------------------------------------------------------- /Sreenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/Sreenshots/4.png -------------------------------------------------------------------------------- /Sreenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/Sreenshots/5.png -------------------------------------------------------------------------------- /Sreenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/Sreenshots/6.png -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "com.shashank.expensemanager" 7 | minSdkVersion 23 8 | targetSdkVersion 27 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:27.1.1' 24 | implementation 'com.android.support:design:27.1.1' 25 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 26 | implementation 'com.android.support:support-v4:27.1.1' 27 | testImplementation 'junit:junit:4.12' 28 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 29 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 30 | implementation 'com.android.support:cardview-v7:27.1.1' 31 | 32 | implementation "android.arch.persistence.room:runtime:1.1.1" 33 | annotationProcessor "android.arch.persistence.room:compiler:1.1.1" 34 | 35 | implementation "android.arch.lifecycle:extensions:1.1.1" 36 | annotationProcessor "android.arch.lifecycle:compiler:1.1.1" 37 | implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3' 38 | } 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/shashank/expensemanager/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.shashank.expensemanager", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shashankchandak/Expense-Manager/4555b6e8d03092ab48b0c780edfa914bae2e18c9/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/activities/AddExpenseActivity.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.activities; 2 | 3 | import android.app.DatePickerDialog; 4 | import android.arch.lifecycle.ViewModelProviders; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.os.Build; 8 | import android.os.Bundle; 9 | import android.os.Handler; 10 | import android.support.design.widget.Snackbar; 11 | import android.support.design.widget.TextInputEditText; 12 | import android.support.design.widget.TextInputLayout; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.view.Menu; 15 | import android.view.MenuInflater; 16 | import android.view.MenuItem; 17 | import android.view.View; 18 | import android.view.inputmethod.InputMethodManager; 19 | import android.widget.ArrayAdapter; 20 | import android.widget.DatePicker; 21 | import android.widget.LinearLayout; 22 | import android.widget.Spinner; 23 | import android.widget.TextView; 24 | 25 | import com.shashank.expensemanager.R; 26 | import com.shashank.expensemanager.transactionDb.AppDatabase; 27 | import com.shashank.expensemanager.transactionDb.AppExecutors; 28 | import com.shashank.expensemanager.transactionDb.TransactionEntry; 29 | import com.shashank.expensemanager.transactionDb.TransactionViewModel; 30 | import com.shashank.expensemanager.utils.Constants; 31 | 32 | import java.text.ParseException; 33 | import java.text.SimpleDateFormat; 34 | import java.util.ArrayList; 35 | import java.util.Calendar; 36 | import java.util.Date; 37 | 38 | public class AddExpenseActivity extends AppCompatActivity { 39 | 40 | 41 | TextInputEditText amountTextInputEditText; 42 | TextInputEditText descriptionTextInputEditText; 43 | TextInputLayout amountTextInputLayout; 44 | TextInputLayout descriptionTextInputLayout; 45 | TextView dateTextView; 46 | LinearLayout dateLinearLayout; 47 | Spinner categorySpinner; 48 | ArrayList categories; 49 | Calendar myCalendar; 50 | 51 | String description; 52 | Date dateOfExpense; 53 | 54 | private DatePickerDialog datePickerDialog; 55 | private static AppDatabase appDatabase; 56 | 57 | 58 | private static final String LOG_TAG = AddExpenseActivity.class.getSimpleName(); 59 | 60 | 61 | //These variables contain data which will be stored permanently on hitting save button 62 | int amount; 63 | String categoryOfExpense; //This parameter is to decide category in a transaction 64 | String categoryOfTransaction; //This parameter to decide whether it is income and expense 65 | 66 | //Variable to keep track from where it came to this activity 67 | String intentFrom; 68 | 69 | TransactionViewModel transactionViewModel; 70 | 71 | int transactionid; 72 | 73 | @Override 74 | protected void onCreate(Bundle savedInstanceState) { 75 | super.onCreate(savedInstanceState); 76 | setContentView(R.layout.activity_add_expense); 77 | 78 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 79 | 80 | amountTextInputEditText = findViewById(R.id.amountTextInputEditText); 81 | descriptionTextInputEditText = findViewById(R.id.descriptionTextInputEditText); 82 | amountTextInputLayout = findViewById(R.id.amountTextInputLayout); 83 | descriptionTextInputLayout = findViewById(R.id.descriptionTextInputLayout); 84 | dateTextView = findViewById(R.id.dateTextView); 85 | dateLinearLayout = findViewById(R.id.dateLinerLayout); 86 | categorySpinner = findViewById(R.id.categorySpinner); 87 | 88 | appDatabase = AppDatabase.getInstance(getApplicationContext()); 89 | 90 | 91 | transactionViewModel = ViewModelProviders.of(this) 92 | .get(TransactionViewModel.class); 93 | 94 | categories = new ArrayList<>(); 95 | 96 | myCalendar = Calendar.getInstance(); 97 | setDateToTextView(); 98 | 99 | //First task here is to determine from where this activity is launched from the 4 possibilities 100 | 101 | Intent intent = getIntent(); 102 | 103 | intentFrom = intent.getStringExtra("from"); 104 | 105 | if (intentFrom.equals(Constants.addIncomeString)) { 106 | categoryOfTransaction = Constants.incomeCategory; 107 | setTitle("Add Income"); 108 | categories.add("Income"); 109 | categorySpinner.setClickable(false); 110 | categorySpinner.setEnabled(false); 111 | categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this, android.R.layout.simple_list_item_1, categories)); 112 | 113 | } else if (intentFrom.equals(Constants.addExpenseString)) { 114 | categoryOfTransaction = Constants.expenseCategory; 115 | setTitle("Add Expense"); 116 | categories.add("Food"); 117 | categories.add("Travel"); 118 | categories.add("Clothes"); 119 | categories.add("Movies"); 120 | categories.add("Health"); 121 | categories.add("Grocery"); 122 | categories.add("Other"); 123 | categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this, 124 | android.R.layout.simple_list_item_1, categories)); 125 | 126 | } else if (intentFrom.equals(Constants.editIncomeString)) { 127 | setTitle("Edit Income"); 128 | 129 | amountTextInputEditText.setText(String.valueOf(intent.getIntExtra("amount", 0))); 130 | amountTextInputEditText.setSelection(amountTextInputEditText.getText().length()); 131 | descriptionTextInputEditText.setText(intent.getStringExtra("description")); 132 | descriptionTextInputEditText.setSelection(descriptionTextInputEditText.getText().length()); 133 | transactionid=intent.getIntExtra("id",-1); 134 | 135 | SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 136 | try { 137 | Date date = sdf.parse(intent.getStringExtra("date")); 138 | myCalendar.setTime(date); 139 | } catch (ParseException e) { 140 | e.printStackTrace(); 141 | } 142 | dateTextView.setText(intent.getStringExtra("date")); 143 | 144 | categoryOfTransaction = Constants.incomeCategory; 145 | categories.add("Income"); 146 | categorySpinner.setClickable(false); 147 | categorySpinner.setEnabled(false); 148 | categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this, android.R.layout.simple_list_item_1, categories)); 149 | 150 | } else if (intentFrom.equals(Constants.editExpenseString)) { 151 | categoryOfTransaction = Constants.expenseCategory; 152 | setTitle("Edit Expense"); 153 | amountTextInputEditText.setText(String.valueOf(intent.getIntExtra("amount", 0))); 154 | amountTextInputEditText.setSelection(amountTextInputEditText.getText().length()); 155 | descriptionTextInputEditText.setText(intent.getStringExtra("description")); 156 | descriptionTextInputEditText.setSelection(descriptionTextInputEditText.getText().length()); 157 | dateTextView.setText(intent.getStringExtra("date")); 158 | transactionid=intent.getIntExtra("id",-1); 159 | 160 | 161 | SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 162 | try { 163 | Date date = sdf.parse(intent.getStringExtra("date")); 164 | myCalendar.setTime(date); 165 | } catch (ParseException e) { 166 | e.printStackTrace(); 167 | } 168 | 169 | categories.add("Food"); 170 | categories.add("Travel"); 171 | categories.add("Clothes"); 172 | categories.add("Movies"); 173 | categories.add("Health"); 174 | categories.add("Grocery"); 175 | categories.add("Other"); 176 | categorySpinner.setAdapter(new ArrayAdapter<>(AddExpenseActivity.this, android.R.layout.simple_list_item_1, categories)); 177 | categorySpinner.setSelection(categories.indexOf(intent.getStringExtra("category"))); 178 | } 179 | 180 | dateLinearLayout.setOnClickListener(new View.OnClickListener() { 181 | @Override 182 | public void onClick(View v) { 183 | showDatePicker(); 184 | } 185 | }); 186 | 187 | } 188 | 189 | 190 | public void showDatePicker() { 191 | 192 | 193 | DatePickerDialog.OnDateSetListener dateSetListener=new DatePickerDialog.OnDateSetListener() { 194 | @Override 195 | public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { 196 | myCalendar.set(Calendar.YEAR, year); 197 | myCalendar.set(Calendar.MONTH, month); 198 | myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); 199 | setDateToTextView(); 200 | } 201 | }; 202 | 203 | DatePickerDialog datePickerDialog=new DatePickerDialog(AddExpenseActivity.this,dateSetListener, 204 | myCalendar.get(Calendar.YEAR), myCalendar.get(Calendar.MONTH), myCalendar.get(Calendar.DAY_OF_MONTH)); 205 | 206 | datePickerDialog.getDatePicker().setMaxDate(System.currentTimeMillis()); 207 | datePickerDialog.show(); 208 | 209 | //In this method not able to set max date 210 | /*new DatePickerDialog(AddExpenseActivity.this, new DatePickerDialog.OnDateSetListener() { 211 | @Override 212 | public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { 213 | myCalendar.set(Calendar.YEAR, year); 214 | myCalendar.set(Calendar.MONTH, month); 215 | myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); 216 | setDateToTextView(); 217 | } 218 | }, myCalendar.get(Calendar.YEAR), myCalendar.get(Calendar.MONTH), myCalendar.get(Calendar.DAY_OF_MONTH) 219 | ).show();*/ 220 | 221 | //This methode requires android n 222 | /* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 223 | datePickerDialog = new DatePickerDialog(AddExpenseActivity.this); 224 | 225 | datePickerDialog.setOnDateSetListener(new DatePickerDialog.OnDateSetListener() { 226 | @Override 227 | public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { 228 | myCalendar.set(Calendar.YEAR, year); 229 | myCalendar.set(Calendar.MONTH, month); 230 | myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); 231 | setDateToTextView(); 232 | } 233 | }); 234 | 235 | datePickerDialog.getDatePicker().setMaxDate(System.currentTimeMillis()); 236 | datePickerDialog.show(); 237 | }*/ 238 | 239 | } 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | public void setDateToTextView() { 249 | Date date = myCalendar.getTime(); 250 | SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 251 | String dateToBeSet = sdf.format(date); 252 | dateTextView.setText(dateToBeSet); 253 | } 254 | 255 | @Override 256 | public boolean onCreateOptionsMenu(Menu menu) { 257 | 258 | MenuInflater menuInflater = getMenuInflater(); 259 | menuInflater.inflate(R.menu.add_expense_activty_menu, menu); 260 | return super.onCreateOptionsMenu(menu); 261 | } 262 | 263 | @Override 264 | public boolean onOptionsItemSelected(MenuItem item) { 265 | 266 | switch (item.getItemId()) { 267 | case android.R.id.home: 268 | finish(); 269 | break; 270 | case R.id.saveButton: 271 | // COMPLETED: 10-09-2018 1.Retrieve and Save data to database and also update the recycler view 272 | 273 | 274 | if (amountTextInputEditText.getText().toString().isEmpty() 275 | || descriptionTextInputEditText.getText().toString().isEmpty()) { 276 | 277 | if (amountTextInputEditText.getText().toString().isEmpty()) 278 | amountTextInputEditText.setError("Amount cannot be empty"); 279 | if (descriptionTextInputEditText.getText().toString().isEmpty()) 280 | descriptionTextInputEditText.setError("Please write some description"); 281 | 282 | } else { 283 | amount = Integer.parseInt(amountTextInputEditText.getText().toString()); 284 | description = descriptionTextInputEditText.getText().toString(); 285 | dateOfExpense = myCalendar.getTime(); 286 | 287 | if (intentFrom.equals(Constants.addIncomeString) 288 | || intentFrom.equals(Constants.editIncomeString)) 289 | categoryOfExpense = "Income"; 290 | else 291 | categoryOfExpense = categories.get(categorySpinner.getSelectedItemPosition()); 292 | 293 | final TransactionEntry mTransactionEntry = new TransactionEntry(amount, 294 | categoryOfExpense, 295 | description, 296 | dateOfExpense, 297 | categoryOfTransaction 298 | ); 299 | 300 | if(intentFrom.equals(Constants.addIncomeString)||intentFrom.equals(Constants.addExpenseString)) { 301 | 302 | 303 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 304 | @Override 305 | public void run() { 306 | appDatabase.transactionDao().insertExpense(mTransactionEntry); 307 | } 308 | }); 309 | 310 | InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 311 | inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); 312 | 313 | Snackbar.make(getCurrentFocus(),"Transaction Added",Snackbar.LENGTH_LONG).show(); 314 | } 315 | else{ 316 | mTransactionEntry.setId(transactionid); 317 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 318 | @Override 319 | public void run() { 320 | appDatabase.transactionDao().updateExpenseDetails(mTransactionEntry); 321 | 322 | } 323 | }); 324 | 325 | InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 326 | inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); 327 | 328 | Snackbar.make(getCurrentFocus(),"Transaction Updated",Snackbar.LENGTH_LONG).show(); 329 | 330 | } 331 | new Handler().postDelayed(new Runnable() { 332 | @Override 333 | public void run() { 334 | finish(); 335 | } 336 | }, 1000); 337 | 338 | } 339 | break; 340 | } 341 | return true; 342 | 343 | 344 | } 345 | 346 | 347 | } 348 | 349 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/activities/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.activities; 2 | 3 | import android.support.design.widget.TabLayout; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.Toolbar; 8 | 9 | import android.support.v4.app.Fragment; 10 | import android.support.v4.app.FragmentManager; 11 | import android.support.v4.app.FragmentPagerAdapter; 12 | import android.support.v4.view.ViewPager; 13 | import android.os.Bundle; 14 | import android.view.LayoutInflater; 15 | import android.view.Menu; 16 | import android.view.MenuItem; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | 20 | import android.widget.TextView; 21 | 22 | import com.shashank.expensemanager.R; 23 | import com.shashank.expensemanager.adapters.SectionsPageAdapter; 24 | import com.shashank.expensemanager.fragments.BalanceFragment; 25 | import com.shashank.expensemanager.fragments.CustomBottomSheetDialogFragment; 26 | import com.shashank.expensemanager.fragments.ExpenseFragment; 27 | 28 | public class MainActivity extends AppCompatActivity { 29 | 30 | private ViewPager mViewPager; 31 | 32 | public static FloatingActionButton fab; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_main); 38 | 39 | 40 | mViewPager=findViewById(R.id.container); 41 | setupViewPager(mViewPager); 42 | 43 | TabLayout tabLayout=findViewById(R.id.tabs); 44 | tabLayout.setupWithViewPager(mViewPager); 45 | 46 | 47 | fab = (FloatingActionButton) findViewById(R.id.fab); 48 | fab.setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View view) { 51 | new CustomBottomSheetDialogFragment().show(getSupportFragmentManager(), "Dialog"); 52 | 53 | } 54 | }); 55 | 56 | } 57 | 58 | 59 | 60 | 61 | private void setupViewPager(ViewPager viewPager){ 62 | SectionsPageAdapter adapter=new SectionsPageAdapter(getSupportFragmentManager()); 63 | adapter.addFragment(new ExpenseFragment(),"Expenses"); 64 | adapter.addFragment(new BalanceFragment(),"Balance"); 65 | viewPager.setAdapter(adapter); 66 | } 67 | 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/activities/SplashScreen.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.activities; 2 | 3 | import android.content.Intent; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | 7 | public class SplashScreen extends AppCompatActivity { 8 | 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | startActivity(new Intent(SplashScreen.this, MainActivity.class)); 13 | // close splash activity 14 | finish(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/adapters/CustomAdapter.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.adapters; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.graphics.Color; 7 | import android.support.annotation.NonNull; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.TextView; 13 | 14 | import com.shashank.expensemanager.R; 15 | import com.shashank.expensemanager.activities.AddExpenseActivity; 16 | import com.shashank.expensemanager.transactionDb.AppDatabase; 17 | import com.shashank.expensemanager.transactionDb.AppExecutors; 18 | import com.shashank.expensemanager.transactionDb.TransactionEntry; 19 | import com.shashank.expensemanager.utils.Constants; 20 | 21 | import java.text.SimpleDateFormat; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class CustomAdapter extends RecyclerView.Adapter { 26 | 27 | 28 | Context context; 29 | private List transactionEntries; 30 | private AppDatabase appDatabase; 31 | 32 | public CustomAdapter(Context context, List transactionEntries){ 33 | this.context=context; 34 | this.transactionEntries=transactionEntries; 35 | } 36 | 37 | @NonNull 38 | @Override 39 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 40 | 41 | View view = LayoutInflater.from(context).inflate(R.layout.list_item,parent,false); 42 | return new ViewHolder(view); 43 | } 44 | 45 | @Override 46 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 47 | String amount; 48 | holder.categoryTextViewrv.setText(transactionEntries.get(position).getCategory()); 49 | if(transactionEntries.get(position).getTransactionType().equals(Constants.incomeCategory)) { 50 | amount="+"+transactionEntries.get(position).getAmount(); 51 | holder.amountTextViewrv.setText(amount); 52 | holder.amountTextViewrv.setTextColor(Color.parseColor("#aeea00")); 53 | } 54 | else { 55 | amount="-"+transactionEntries.get(position).getAmount(); 56 | holder.amountTextViewrv.setText(amount); 57 | holder.amountTextViewrv.setTextColor(Color.parseColor("#ff5722")); 58 | } 59 | 60 | SimpleDateFormat sdf=new SimpleDateFormat("dd-MM-yyyy"); 61 | String dateToBeSet=sdf.format(transactionEntries.get(position).getDate()); 62 | holder.dateTextViewrv.setText(dateToBeSet); 63 | holder.descriptionTextViewrv.setText(transactionEntries.get(position).getDescription()); 64 | } 65 | 66 | @Override 67 | public int getItemCount() { 68 | if (transactionEntries == null || transactionEntries.size() == 0){ 69 | return 0; 70 | } else { 71 | return transactionEntries.size(); 72 | } 73 | } 74 | 75 | public List getTransactionEntries() { 76 | return transactionEntries; 77 | } 78 | 79 | public class ViewHolder extends RecyclerView.ViewHolder { 80 | 81 | TextView categoryTextViewrv; 82 | TextView amountTextViewrv; 83 | TextView descriptionTextViewrv; 84 | TextView dateTextViewrv; 85 | 86 | public ViewHolder(View itemView) { 87 | super(itemView); 88 | 89 | categoryTextViewrv=itemView.findViewById(R.id.categoryTextViewrv); 90 | amountTextViewrv=itemView.findViewById(R.id.amountTextViewrv); 91 | descriptionTextViewrv=itemView.findViewById(R.id.descriptionTextViewrv); 92 | dateTextViewrv=itemView.findViewById(R.id.dateTextViewrv); 93 | 94 | appDatabase = AppDatabase.getInstance(context); 95 | 96 | itemView.setOnClickListener(new View.OnClickListener() { 97 | @Override 98 | public void onClick(View v) { 99 | Intent intent=new Intent(context,AddExpenseActivity.class); 100 | 101 | SimpleDateFormat sdf=new SimpleDateFormat("dd-MM-yyyy"); 102 | String date=sdf.format(transactionEntries.get(getAdapterPosition()).getDate()); 103 | 104 | if (transactionEntries.get(getAdapterPosition()).getTransactionType().equals(Constants.incomeCategory)) { 105 | intent.putExtra("from", Constants.editIncomeString); 106 | intent.putExtra("amount",transactionEntries.get(getAdapterPosition()).getAmount()); 107 | intent.putExtra("description",transactionEntries.get(getAdapterPosition()).getDescription()); 108 | intent.putExtra("date",date); 109 | intent.putExtra("id",transactionEntries.get(getAdapterPosition()).getId()); 110 | } 111 | else { 112 | intent.putExtra("from", Constants.editExpenseString); 113 | intent.putExtra("amount",transactionEntries.get(getAdapterPosition()).getAmount()); 114 | intent.putExtra("description",transactionEntries.get(getAdapterPosition()).getDescription()); 115 | intent.putExtra("date",date); 116 | intent.putExtra("category",transactionEntries.get(getAdapterPosition()).getCategory()); 117 | intent.putExtra("id",transactionEntries.get(getAdapterPosition()).getId()); 118 | } 119 | 120 | 121 | //Updated on 19/8/2018 no need of this now as added update function properly 122 | /*AppExecutors.getInstance().diskIO().execute(new Runnable() { 123 | @Override 124 | public void run() { 125 | appDatabase.transactionDao().removeExpense(transactionEntries.get(getAdapterPosition())); 126 | } 127 | });*/ 128 | 129 | context.startActivity(intent); 130 | } 131 | }); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/adapters/SectionsPageAdapter.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.adapters; 2 | 3 | import android.support.annotation.Nullable; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentPagerAdapter; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class SectionsPageAdapter extends FragmentPagerAdapter { 12 | 13 | private final List FragmentList=new ArrayList<>(); 14 | private final List FragmentTitleList=new ArrayList<>(); 15 | 16 | public void addFragment(Fragment fragment,String title){ 17 | FragmentList.add(fragment); 18 | FragmentTitleList.add(title); 19 | } 20 | 21 | 22 | 23 | public SectionsPageAdapter(FragmentManager fm) { 24 | super(fm); 25 | } 26 | 27 | @Nullable 28 | @Override 29 | public CharSequence getPageTitle(int position) { 30 | return FragmentTitleList.get(position); 31 | } 32 | 33 | @Override 34 | public Fragment getItem(int position) { 35 | return FragmentList.get(position); 36 | } 37 | 38 | @Override 39 | public int getCount() { 40 | return FragmentList.size(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/fragments/BalanceFragment.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.fragments; 2 | 3 | import android.app.DatePickerDialog; 4 | import android.arch.lifecycle.ViewModelProviders; 5 | import android.content.Context; 6 | import android.content.pm.PackageManager; 7 | import android.graphics.Color; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.support.annotation.NonNull; 11 | import android.support.annotation.Nullable; 12 | import android.support.design.widget.FloatingActionButton; 13 | import android.support.v4.app.Fragment; 14 | import android.util.Log; 15 | import android.view.LayoutInflater; 16 | import android.view.View; 17 | import android.view.ViewGroup; 18 | import android.widget.AdapterView; 19 | import android.widget.ArrayAdapter; 20 | import android.widget.Spinner; 21 | import android.widget.TextView; 22 | import android.widget.Toast; 23 | 24 | import com.github.mikephil.charting.charts.PieChart; 25 | import com.github.mikephil.charting.components.Legend; 26 | import com.github.mikephil.charting.data.PieData; 27 | import com.github.mikephil.charting.data.PieDataSet; 28 | import com.github.mikephil.charting.data.PieEntry; 29 | import com.github.mikephil.charting.formatter.PercentFormatter; 30 | import com.github.mikephil.charting.utils.ColorTemplate; 31 | import com.shashank.expensemanager.R; 32 | import com.shashank.expensemanager.activities.MainActivity; 33 | import com.shashank.expensemanager.transactionDb.AppDatabase; 34 | import com.shashank.expensemanager.transactionDb.AppExecutors; 35 | import com.shashank.expensemanager.transactionDb.TransactionViewModel; 36 | import com.shashank.expensemanager.utils.Constants; 37 | import com.shashank.expensemanager.utils.ExpenseList; 38 | 39 | import java.text.DateFormat; 40 | import java.text.ParseException; 41 | import java.text.SimpleDateFormat; 42 | import java.util.ArrayList; 43 | import java.util.Calendar; 44 | import java.util.Date; 45 | import java.util.HashMap; 46 | import java.util.List; 47 | import java.util.Locale; 48 | import java.util.Map; 49 | 50 | import static com.shashank.expensemanager.activities.MainActivity.fab; 51 | 52 | 53 | public class BalanceFragment extends Fragment implements AdapterView.OnItemSelectedListener{ 54 | 55 | 56 | private AppDatabase mAppDb; 57 | PieChart pieChart; 58 | Spinner spinner; 59 | 60 | private TextView balanceTv,incomeTv,expenseTv; 61 | private TextView dateTv; 62 | 63 | private int balanceAmount,incomeAmount,expenseAmount; 64 | private int foodExpense,travelExpense,clothesExpense,moviesExpense,heathExpense,groceryExpense,otherExpense; 65 | 66 | long firstDate; 67 | 68 | ArrayList expenseList; 69 | @Nullable 70 | @Override 71 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 72 | View view=inflater.inflate(R.layout.fragment_balance,container,false); 73 | 74 | pieChart= view.findViewById(R.id.balancePieChart); 75 | spinner = view.findViewById(R.id.spinner); 76 | spinner.setOnItemSelectedListener(this); 77 | 78 | mAppDb = AppDatabase.getInstance(getContext()); 79 | 80 | balanceTv = view.findViewById(R.id.totalAmountTextView); 81 | expenseTv = view.findViewById(R.id.amountForExpenseTextView); 82 | incomeTv = view.findViewById(R.id.amountForIncomeTextView); 83 | 84 | dateTv = view.findViewById(R.id.dateTextView); 85 | expenseList=new ArrayList<>(); 86 | getAllBalanceAmount(); 87 | setupPieChart(); 88 | return view; 89 | 90 | //TODO 1.Change constraint to linear and change entire layout 91 | //TODO 2.Align piechart properly with label 92 | //TODO 3.See if can opytimize queries and spinner state and read about fragment lifecycle 93 | 94 | } 95 | 96 | private void setupSpinner() { 97 | ArrayAdapter arrayAdapter = ArrayAdapter.createFromResource(getContext(), 98 | R.array.date_array, 99 | android.R.layout.simple_spinner_item); 100 | arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 101 | spinner.setAdapter(arrayAdapter); 102 | } 103 | 104 | @Override 105 | public void setUserVisibleHint(boolean isVisibleToUser) { 106 | super.setUserVisibleHint(isVisibleToUser); 107 | Log.i("fragment", String.valueOf(isVisibleToUser)); 108 | if (isVisibleToUser){ 109 | setupSpinner(); 110 | fab.setVisibility(View.GONE); 111 | } else{ 112 | fab.setVisibility(View.VISIBLE); 113 | } 114 | } 115 | 116 | private void setupPieChart() { 117 | 118 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 119 | @Override 120 | public void run() { 121 | if(spinner.getSelectedItemPosition()==0) 122 | getAllPieValues(); 123 | else if(spinner.getSelectedItemPosition()==1) { 124 | try { 125 | getWeekPieValues(); 126 | } catch (ParseException e) { 127 | e.printStackTrace(); 128 | } 129 | } 130 | else if(spinner.getSelectedItemPosition()==2){ 131 | try { 132 | getMonthPieValues(); 133 | } catch (ParseException e) { 134 | e.printStackTrace(); 135 | } 136 | } 137 | 138 | expenseList.clear(); 139 | if(foodExpense!=0) 140 | expenseList.add(new ExpenseList("Food",foodExpense)); 141 | if(travelExpense!=0) 142 | expenseList.add(new ExpenseList("Travel",travelExpense)); 143 | if(clothesExpense!=0) 144 | expenseList.add(new ExpenseList("Clothes",clothesExpense)); 145 | if(moviesExpense!=0) 146 | expenseList.add(new ExpenseList("Movies",moviesExpense)); 147 | if(heathExpense!=0) 148 | expenseList.add(new ExpenseList("Health",heathExpense)); 149 | if(groceryExpense!=0) 150 | expenseList.add(new ExpenseList("Grocery",groceryExpense)); 151 | if(otherExpense!=0) 152 | expenseList.add(new ExpenseList("Other",otherExpense)); 153 | } 154 | }); 155 | 156 | 157 | AppExecutors.getInstance().mainThread().execute(new Runnable() { 158 | @Override 159 | public void run() { 160 | 161 | List pieEntries = new ArrayList<>(); 162 | for(int i = 0 ; i adapterView, View view, int i, long l) { 192 | 193 | if(adapterView.getSelectedItemPosition()==0){ 194 | getAllBalanceAmount(); 195 | setupPieChart(); 196 | } 197 | 198 | else if (adapterView.getSelectedItemPosition() == 1){ 199 | //This week 200 | try { 201 | getWeekBalanceAmount(); 202 | setupPieChart(); 203 | } 204 | catch (ParseException e) { 205 | e.printStackTrace(); 206 | } 207 | } 208 | else if(adapterView.getSelectedItemPosition()==2){ 209 | //This month 210 | try { 211 | getMonthBalanceAmount(); 212 | setupPieChart(); 213 | } catch (ParseException e) { 214 | e.printStackTrace(); 215 | } 216 | } 217 | 218 | } 219 | 220 | @Override 221 | public void onNothingSelected(AdapterView adapterView) { 222 | } 223 | 224 | 225 | private void getAllPieValues(){ 226 | foodExpense =mAppDb.transactionDao().getSumExpenseByCategory("Food"); 227 | travelExpense=mAppDb.transactionDao().getSumExpenseByCategory("Travel"); 228 | clothesExpense=mAppDb.transactionDao().getSumExpenseByCategory("Clothes"); 229 | moviesExpense=mAppDb.transactionDao().getSumExpenseByCategory("Movies"); 230 | heathExpense=mAppDb.transactionDao().getSumExpenseByCategory("Health"); 231 | groceryExpense=mAppDb.transactionDao().getSumExpenseByCategory("Grocery"); 232 | otherExpense=mAppDb.transactionDao().getSumExpenseByCategory("Other"); 233 | } 234 | 235 | private void getWeekPieValues() throws ParseException { 236 | Calendar calendar; 237 | calendar=Calendar.getInstance(); 238 | 239 | DateFormat df = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); 240 | String startDate = "", endDate = ""; 241 | // Set the calendar to sunday of the current week 242 | calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); 243 | startDate = df.format(calendar.getTime()); 244 | Date sDate=df.parse(startDate); 245 | final long sdate=sDate.getTime(); 246 | 247 | calendar.add(Calendar.DATE, 6); 248 | endDate = df.format(calendar.getTime()); 249 | Date eDate=df.parse(endDate); 250 | final long edate=eDate.getTime(); 251 | 252 | foodExpense =mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Food",sdate,edate); 253 | travelExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Travel",sdate,edate); 254 | clothesExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Clothes",sdate,edate); 255 | moviesExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Movies",sdate,edate); 256 | heathExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Health",sdate,edate); 257 | groceryExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Grocery",sdate,edate); 258 | otherExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Other",sdate,edate); 259 | } 260 | 261 | private void getMonthPieValues() throws ParseException{ 262 | 263 | Calendar calendar; 264 | calendar=Calendar.getInstance(); 265 | 266 | DateFormat df = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); 267 | String startDate = "", endDate = ""; 268 | 269 | calendar.set(Calendar.DAY_OF_MONTH,1); 270 | startDate = df.format(calendar.getTime()); 271 | Date sDate=df.parse(startDate); 272 | final long sdate=sDate.getTime(); 273 | 274 | calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 275 | endDate = df.format(calendar.getTime()); 276 | Date eDate=df.parse(endDate); 277 | final long edate=eDate.getTime(); 278 | 279 | foodExpense =mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Food",sdate,edate); 280 | travelExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Travel",sdate,edate); 281 | clothesExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Clothes",sdate,edate); 282 | moviesExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Movies",sdate,edate); 283 | heathExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Health",sdate,edate); 284 | groceryExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Grocery",sdate,edate); 285 | otherExpense=mAppDb.transactionDao().getSumExpenseByCategoryCustomDate("Other",sdate,edate); 286 | } 287 | 288 | private void getAllBalanceAmount(){ 289 | 290 | //get date when first transaction date and todays date 291 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 292 | @Override 293 | public void run() { 294 | firstDate=mAppDb.transactionDao().getFirstDate(); 295 | } 296 | }); 297 | 298 | SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy"); 299 | String first = df.format(new Date(firstDate)); 300 | Date today=Calendar.getInstance().getTime(); 301 | String todaysDate=df.format(today); 302 | String Date=first+" - "+todaysDate; 303 | dateTv.setText(Date); 304 | 305 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 306 | @Override 307 | public void run() { 308 | int income = mAppDb.transactionDao().getAmountByTransactionType(Constants.incomeCategory); 309 | incomeAmount = income; 310 | int expense = mAppDb.transactionDao().getAmountByTransactionType(Constants.expenseCategory); 311 | expenseAmount = expense; 312 | int balance = income - expense; 313 | balanceAmount = balance; 314 | } 315 | }); 316 | AppExecutors.getInstance().mainThread().execute(new Runnable() { 317 | @Override 318 | public void run() { 319 | balanceTv.setText(String.valueOf(balanceAmount)+" \u20B9"); 320 | incomeTv.setText(String.valueOf(incomeAmount)+" \u20B9"); 321 | expenseTv.setText(String.valueOf(expenseAmount)+" \u20B9"); 322 | } 323 | }); 324 | 325 | 326 | } 327 | 328 | private void getWeekBalanceAmount() throws ParseException { 329 | Calendar calendar; 330 | calendar=Calendar.getInstance(); 331 | 332 | DateFormat df = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); 333 | String startDate = "", endDate = ""; 334 | // Set the calendar to sunday of the current week 335 | calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); 336 | startDate = df.format(calendar.getTime()); 337 | Date sDate=df.parse(startDate); 338 | final long sdate=sDate.getTime(); 339 | 340 | calendar.add(Calendar.DATE, 6); 341 | endDate = df.format(calendar.getTime()); 342 | Date eDate=df.parse(endDate); 343 | final long edate=eDate.getTime(); 344 | 345 | String dateString = startDate + " - " + endDate; 346 | dateTv.setText(dateString); 347 | 348 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 349 | @Override 350 | public void run() { 351 | int income = mAppDb.transactionDao().getAmountbyCustomDates(Constants.incomeCategory,sdate,edate); 352 | incomeAmount = income; 353 | int expense = mAppDb.transactionDao().getAmountbyCustomDates(Constants.expenseCategory,sdate,edate); 354 | expenseAmount = expense; 355 | int balance = income - expense; 356 | balanceAmount = balance; 357 | 358 | } 359 | }); 360 | AppExecutors.getInstance().mainThread().execute(new Runnable() { 361 | @Override 362 | public void run() { 363 | balanceTv.setText(String.valueOf(balanceAmount)+" \u20B9"); 364 | incomeTv.setText(String.valueOf(incomeAmount)+" \u20B9"); 365 | expenseTv.setText(String.valueOf(expenseAmount)+" \u20B9"); 366 | } 367 | }); 368 | } 369 | 370 | 371 | private void getMonthBalanceAmount() throws ParseException { 372 | Calendar calendar; 373 | calendar=Calendar.getInstance(); 374 | 375 | DateFormat df = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); 376 | String startDate = "", endDate = ""; 377 | 378 | calendar.set(Calendar.DAY_OF_MONTH,1); 379 | startDate = df.format(calendar.getTime()); 380 | Date sDate=df.parse(startDate); 381 | final long sdate=sDate.getTime(); 382 | 383 | calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 384 | endDate = df.format(calendar.getTime()); 385 | Date eDate=df.parse(endDate); 386 | final long edate=eDate.getTime(); 387 | 388 | String dateString = startDate + " - " + endDate; 389 | dateTv.setText(dateString); 390 | 391 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 392 | @Override 393 | public void run() { 394 | int income = mAppDb.transactionDao().getAmountbyCustomDates(Constants.incomeCategory,sdate,edate); 395 | incomeAmount = income; 396 | int expense = mAppDb.transactionDao().getAmountbyCustomDates(Constants.expenseCategory,sdate,edate); 397 | expenseAmount = expense; 398 | int balance = income - expense; 399 | balanceAmount = balance; 400 | 401 | } 402 | }); 403 | AppExecutors.getInstance().mainThread().execute(new Runnable() { 404 | @Override 405 | public void run() { 406 | balanceTv.setText(String.valueOf(balanceAmount)+" \u20B9"); 407 | incomeTv.setText(String.valueOf(incomeAmount)+" \u20B9"); 408 | expenseTv.setText(String.valueOf(expenseAmount)+" \u20B9"); 409 | } 410 | }); 411 | } 412 | } 413 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/fragments/CustomBottomSheetDialogFragment.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.fragments; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.design.widget.BottomSheetDialogFragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Button; 10 | import android.widget.Toast; 11 | 12 | import com.shashank.expensemanager.R; 13 | import com.shashank.expensemanager.activities.AddExpenseActivity; 14 | import com.shashank.expensemanager.utils.Constants; 15 | 16 | public class CustomBottomSheetDialogFragment extends BottomSheetDialogFragment { 17 | 18 | Button addIncomeButton; 19 | Button addExpenseButton; 20 | 21 | @Override 22 | public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 23 | View v = inflater.inflate(R.layout.bottom_sheet_fragment, container, false); 24 | 25 | addIncomeButton=v.findViewById(R.id.bottom_sheet_income_btn); 26 | addExpenseButton=v.findViewById(R.id.bottom_sheet_expense_btn); 27 | 28 | addIncomeButton.setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View v) { 31 | dismiss(); 32 | Intent intent =new Intent(getActivity(), AddExpenseActivity.class); 33 | intent.putExtra("from", Constants.addIncomeString); 34 | startActivity(intent); 35 | } 36 | }); 37 | 38 | addExpenseButton.setOnClickListener(new View.OnClickListener() { 39 | @Override 40 | public void onClick(View v) { 41 | dismiss(); 42 | Intent intent =new Intent(getActivity(), AddExpenseActivity.class); 43 | intent.putExtra("from", Constants.addExpenseString); 44 | startActivity(intent); 45 | 46 | } 47 | }); 48 | 49 | 50 | return v; 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/fragments/ExpenseFragment.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.fragments; 2 | 3 | import android.arch.lifecycle.LiveData; 4 | import android.arch.lifecycle.Observer; 5 | import android.arch.lifecycle.ViewModelProviders; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.support.design.widget.Snackbar; 10 | import android.support.v4.app.Fragment; 11 | import android.support.v7.widget.LinearLayoutManager; 12 | import android.support.v7.widget.RecyclerView; 13 | import android.support.v7.widget.helper.ItemTouchHelper; 14 | import android.util.Log; 15 | import android.view.LayoutInflater; 16 | import android.view.View; 17 | import android.view.ViewGroup; 18 | 19 | import com.shashank.expensemanager.R; 20 | import com.shashank.expensemanager.adapters.CustomAdapter; 21 | import com.shashank.expensemanager.transactionDb.AppDatabase; 22 | import com.shashank.expensemanager.transactionDb.AppExecutors; 23 | import com.shashank.expensemanager.transactionDb.TransactionEntry; 24 | import com.shashank.expensemanager.transactionDb.TransactionViewModel; 25 | import com.shashank.expensemanager.utils.Constants; 26 | 27 | import java.util.ArrayList; 28 | import java.util.Calendar; 29 | import java.util.List; 30 | 31 | 32 | public class ExpenseFragment extends Fragment { 33 | 34 | private static final String LOG_TAG = ExpenseFragment.class.getSimpleName(); 35 | 36 | private RecyclerView rv; 37 | private List transactionEntries; 38 | private CustomAdapter customAdapter; 39 | 40 | public TransactionViewModel transactionViewModel; 41 | 42 | private AppDatabase mAppDb; 43 | 44 | @Nullable 45 | @Override 46 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 47 | final View view=inflater.inflate(R.layout.fragment_expense,container,false); 48 | rv=view.findViewById(R.id.transactionRecyclerView); 49 | rv.setHasFixedSize(true); 50 | transactionEntries = new ArrayList<>(); 51 | rv.setLayoutManager(new LinearLayoutManager(getActivity())); 52 | 53 | mAppDb = AppDatabase.getInstance(getContext()); 54 | 55 | 56 | 57 | new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) { 58 | @Override 59 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 60 | return false; 61 | } 62 | 63 | // Called when a user swipes right on a ViewHolder 64 | @Override 65 | public void onSwiped(final RecyclerView.ViewHolder viewHolder, int swipeDir) { 66 | // Here is where you'll implement swipe to delete 67 | // COMPLETED (1) Get the diskIO Executor from the instance of AppExecutors and 68 | // call the diskIO execute method with a new Runnable and implement its run method 69 | AppExecutors.getInstance().diskIO().execute(new Runnable() { 70 | @Override 71 | public void run() { 72 | int position = viewHolder.getAdapterPosition(); 73 | 74 | List transactionEntries = customAdapter.getTransactionEntries(); 75 | mAppDb.transactionDao().removeExpense(transactionEntries.get(position)); 76 | 77 | } 78 | }); 79 | 80 | Snackbar.make(view,"Transaction Deleted",Snackbar.LENGTH_LONG).show(); 81 | } 82 | }).attachToRecyclerView(rv); 83 | 84 | setupViewModel(); 85 | 86 | 87 | return view; 88 | } 89 | 90 | public void setupViewModel(){ 91 | transactionViewModel = ViewModelProviders.of(this) 92 | .get(TransactionViewModel.class); 93 | 94 | transactionViewModel.getExpenseList() 95 | .observe(this, new Observer>() { 96 | @Override 97 | public void onChanged(@Nullable List transactionEntriesFromDb) { 98 | Log.i(LOG_TAG,"Actively retrieving from DB"); 99 | 100 | 101 | transactionEntries = transactionEntriesFromDb; 102 | // Logging to check DB values 103 | for (int i =0 ; i < transactionEntries.size() ; i++){ 104 | String description = transactionEntries.get(i).getDescription(); 105 | int amount = transactionEntries.get(i).getAmount(); 106 | //Log.i("DESCRIPTION AMOUNT",description + String.valueOf(amount)); 107 | } 108 | 109 | // Setting Adapter 110 | customAdapter=new CustomAdapter(getActivity(),transactionEntries); 111 | rv.setAdapter(customAdapter); 112 | } 113 | }); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/transactionDb/AppDatabase.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.transactionDb; 2 | 3 | import android.arch.persistence.db.SupportSQLiteDatabase; 4 | import android.arch.persistence.room.Database; 5 | import android.arch.persistence.room.Room; 6 | import android.arch.persistence.room.RoomDatabase; 7 | import android.arch.persistence.room.TypeConverters; 8 | import android.arch.persistence.room.migration.Migration; 9 | import android.content.Context; 10 | import android.support.annotation.NonNull; 11 | import android.util.Log; 12 | 13 | @Database(entities = TransactionEntry.class,version = 1,exportSchema = false) 14 | @TypeConverters(DateConverter.class) 15 | public abstract class AppDatabase extends RoomDatabase { 16 | 17 | private static final String LOG_TAG = AppDatabase.class.getSimpleName(); 18 | private static final Object LOCK = new Object(); 19 | private static final String DATABASE_NAME = "TransactionDb"; 20 | 21 | private static AppDatabase sInstance; 22 | 23 | 24 | public static AppDatabase getInstance(Context context){ 25 | 26 | if (sInstance == null){ 27 | synchronized (LOCK){ 28 | Log.d(LOG_TAG,"Creating new database instance"); 29 | 30 | sInstance = Room.databaseBuilder(context.getApplicationContext(), 31 | AppDatabase.class,AppDatabase.DATABASE_NAME) 32 | // .fallbackToDestructiveMigration() 33 | .build(); 34 | } 35 | } 36 | Log.d(LOG_TAG,"Getting the database instance"); 37 | return sInstance; 38 | } 39 | 40 | public abstract TransactionDao transactionDao(); 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/transactionDb/AppExecutors.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.transactionDb; 2 | 3 | /* 4 | * Copyright (C) 2017 The Android Open Source Project 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.os.Handler; 20 | import android.os.Looper; 21 | import android.support.annotation.NonNull; 22 | 23 | import java.util.concurrent.Executor; 24 | import java.util.concurrent.Executors; 25 | 26 | /** 27 | * Global executor pools for the whole application. 28 | *

29 | * Grouping tasks like this avoids the effects of task starvation (e.g. disk reads don't wait behind 30 | * webservice requests). 31 | */ 32 | public class AppExecutors { 33 | 34 | // For Singleton instantiation 35 | private static final Object LOCK = new Object(); 36 | private static AppExecutors sInstance; 37 | private final Executor diskIO; 38 | private final Executor mainThread; 39 | private final Executor networkIO; 40 | 41 | private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) { 42 | this.diskIO = diskIO; 43 | this.networkIO = networkIO; 44 | this.mainThread = mainThread; 45 | } 46 | 47 | public static AppExecutors getInstance() { 48 | if (sInstance == null) { 49 | synchronized (LOCK) { 50 | sInstance = new AppExecutors(Executors.newSingleThreadExecutor(), 51 | Executors.newFixedThreadPool(3), 52 | new MainThreadExecutor()); 53 | } 54 | } 55 | return sInstance; 56 | } 57 | 58 | public Executor diskIO() { 59 | return diskIO; 60 | } 61 | 62 | public Executor mainThread() { 63 | return mainThread; 64 | } 65 | 66 | public Executor networkIO() { 67 | return networkIO; 68 | } 69 | 70 | private static class MainThreadExecutor implements Executor { 71 | private Handler mainThreadHandler = new Handler(Looper.getMainLooper()); 72 | 73 | @Override 74 | public void execute(@NonNull Runnable command) { 75 | mainThreadHandler.post(command); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/transactionDb/DateConverter.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.transactionDb; 2 | 3 | import android.arch.persistence.room.TypeConverter; 4 | 5 | import java.util.Date; 6 | 7 | public class DateConverter { 8 | @TypeConverter 9 | public static Date toDate(Long timestamp) { 10 | return timestamp == null ? null : new Date(timestamp); 11 | } 12 | 13 | @TypeConverter 14 | public static Long toTimestamp(Date date) { 15 | return date == null ? null : date.getTime(); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/transactionDb/TransactionDao.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.transactionDb; 2 | 3 | import android.arch.lifecycle.LiveData; 4 | import android.arch.persistence.room.Dao; 5 | import android.arch.persistence.room.Delete; 6 | import android.arch.persistence.room.Insert; 7 | import android.arch.persistence.room.OnConflictStrategy; 8 | import android.arch.persistence.room.Query; 9 | import android.arch.persistence.room.Update; 10 | 11 | 12 | import java.util.ArrayList; 13 | import java.util.Date; 14 | import java.util.List; 15 | 16 | @Dao 17 | public interface TransactionDao { 18 | 19 | @Query("select * from transactionTable order by date DESC") 20 | LiveData> loadAllTransactions(); 21 | 22 | @Query("select * from transactionTable where id = :id") 23 | LiveData loadExpenseById(int id); 24 | 25 | @Query("select sum(amount) from transactionTable where transactionType =:transactionType") 26 | int getAmountByTransactionType(String transactionType); 27 | 28 | @Query("select sum(amount) from transactionTable where transactionType =:transactionType and date between :startDate and :endDate") 29 | int getAmountbyCustomDates(String transactionType,long startDate,long endDate); 30 | 31 | @Query("select sum(amount) from transactionTable where category=:category") 32 | int getSumExpenseByCategory(String category); 33 | 34 | @Query("select sum(amount) from transactionTable where category=:category and date between :startDate and :endDate") 35 | int getSumExpenseByCategoryCustomDate(String category,long startDate, long endDate); 36 | 37 | @Query("select min(date) from transactionTable ") 38 | long getFirstDate(); 39 | 40 | @Insert(onConflict = OnConflictStrategy.REPLACE) 41 | void insertExpense(TransactionEntry transactionEntry); 42 | 43 | @Delete 44 | void removeExpense(TransactionEntry transactionEntry); 45 | 46 | @Update(onConflict = OnConflictStrategy.REPLACE) 47 | void updateExpenseDetails(TransactionEntry transactionEntry); 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/transactionDb/TransactionEntry.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.transactionDb; 2 | 3 | import android.arch.persistence.room.Entity; 4 | import android.arch.persistence.room.Ignore; 5 | import android.arch.persistence.room.PrimaryKey; 6 | 7 | import java.util.Date; 8 | 9 | @Entity(tableName = "transactionTable") 10 | public class TransactionEntry { 11 | 12 | @PrimaryKey(autoGenerate = true) 13 | private int id; 14 | 15 | private int amount; 16 | private String category; 17 | private String description; 18 | private Date date; // COMPLETED: 13-09-2018 Add appropriate type converter 19 | private String transactionType; //to decide whether income or expense 20 | 21 | @Ignore 22 | public TransactionEntry(int amount,String category,String description,Date date,String transactionType){ 23 | this.amount = amount; 24 | this.category = category; 25 | this.description = description; 26 | this.date = date; 27 | this.transactionType=transactionType; 28 | } 29 | 30 | 31 | public TransactionEntry(int id,int amount,String category,String description,Date date,String transactionType){ 32 | this.id = id; 33 | this.amount = amount; 34 | this.category = category; 35 | this.description = description; 36 | this.date = date; 37 | this.transactionType=transactionType; 38 | } 39 | 40 | 41 | 42 | public int getAmount() { 43 | return amount; 44 | } 45 | 46 | public void setAmount(int amount) { 47 | this.amount = amount; 48 | } 49 | 50 | public String getCategory() { 51 | return category; 52 | } 53 | 54 | public void setCategory(String category) { 55 | this.category = category; 56 | } 57 | 58 | public String getDescription() { 59 | return description; 60 | } 61 | 62 | public void setDescription(String description) { 63 | this.description = description; 64 | } 65 | 66 | 67 | public Date getDate() { 68 | return date; 69 | } 70 | 71 | public void setDate(Date date) { 72 | this.date = date; 73 | } 74 | 75 | 76 | public int getId() { 77 | return id; 78 | } 79 | 80 | public void setId(int id) { 81 | this.id = id; 82 | } 83 | 84 | public String getTransactionType() { 85 | return transactionType; 86 | } 87 | 88 | public void setTransactionType(String transactionType) { 89 | this.transactionType = transactionType; 90 | } 91 | } -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/transactionDb/TransactionViewModel.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.transactionDb; 2 | 3 | import android.app.Application; 4 | import android.arch.lifecycle.AndroidViewModel; 5 | import android.arch.lifecycle.LiveData; 6 | import android.os.AsyncTask; 7 | import android.support.annotation.NonNull; 8 | 9 | import com.shashank.expensemanager.utils.Constants; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class TransactionViewModel extends AndroidViewModel { 15 | 16 | public final LiveData> expenseList; 17 | private AppDatabase appDatabase; 18 | 19 | 20 | public TransactionViewModel(@NonNull Application application) { 21 | super(application); 22 | 23 | appDatabase = AppDatabase.getInstance(this.getApplication()); 24 | 25 | expenseList = appDatabase.transactionDao().loadAllTransactions(); 26 | 27 | } 28 | 29 | 30 | public LiveData> getExpenseList() { 31 | return expenseList; 32 | } 33 | 34 | // The code below can be ignored 35 | 36 | public void updateTransaction(TransactionEntry transactionEntry){ 37 | new updateTransactionDetails(appDatabase).execute(transactionEntry); 38 | } 39 | 40 | private static class updateTransactionDetails extends AsyncTask{ 41 | 42 | private AppDatabase mdb; 43 | 44 | public updateTransactionDetails(AppDatabase appDatabase){ 45 | mdb = appDatabase; 46 | } 47 | @Override 48 | protected Void doInBackground(TransactionEntry... transactionEntries) { 49 | mdb.transactionDao().updateExpenseDetails(transactionEntries[0]); 50 | return null; 51 | } 52 | } 53 | 54 | 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/utils/Constants.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.utils; 2 | 3 | public class Constants { 4 | 5 | //Since the AddExpense activity can be reached from 4 different routes , 2 by adding a new income or new expense and other 2 by 6 | //editing the existing expenses and incomes on rv so to differentiate from where it came these constants are required. 7 | public static final String addIncomeString="addIncome"; 8 | public static final String addExpenseString="addExpense"; 9 | public static final String editIncomeString="editIncome"; 10 | public static final String editExpenseString="editExpense"; 11 | public static final String incomeCategory="Income"; 12 | public static final String expenseCategory="Expense"; 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/shashank/expensemanager/utils/ExpenseList.java: -------------------------------------------------------------------------------- 1 | package com.shashank.expensemanager.utils; 2 | 3 | public class ExpenseList { 4 | 5 | String category; 6 | int amount; 7 | 8 | public ExpenseList(String category, int amount) { 9 | this.category = category; 10 | this.amount = amount; 11 | } 12 | 13 | public String getCategory() { 14 | return category; 15 | } 16 | 17 | public void setCategory(String category) { 18 | this.category = category; 19 | } 20 | 21 | public int getAmount() { 22 | return amount; 23 | } 24 | 25 | public void setAmount(int amount) { 26 | this.amount = amount; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_account_balance_wallet_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/splash_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/splashlogo.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_expense.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 28 | 29 | 30 | 31 | 36 | 37 | 42 | 50 | 62 | 63 | 64 | 69 | 78 | 79 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 99 | 100 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | 37 | 42 | 43 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/bottom_sheet_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 17 | 18 | 23 | 24 |