├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── .travis.yml ├── Contributing.md ├── LICENSE.md ├── README.md ├── app ├── .gitignore ├── app-release.apk ├── app.iml ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── avjindersinghsekhon │ │ └── minimaltodo │ │ ├── ApplicationTest.java │ │ ├── TestStoreRetrieveData.java │ │ └── TestTodoItem.java │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── fonts │ │ └── Aller_Regular.ttf │ ├── java │ └── com │ │ └── example │ │ └── avjindersinghsekhon │ │ └── minimaltodo │ │ ├── AboutActivity.java │ │ ├── AddToDoActivity.java │ │ ├── AnalyticsApplication.java │ │ ├── CustomRecyclerScrollViewListener.java │ │ ├── CustomTextInputLayout.java │ │ ├── DeleteNotificationService.java │ │ ├── ItemTouchHelperClass.java │ │ ├── MainActivity.java │ │ ├── PreferenceKeys.java │ │ ├── RecyclerViewEmptySupport.java │ │ ├── ReminderActivity.java │ │ ├── ScrollingFABBehaviour.java │ │ ├── SettingsActivity.java │ │ ├── SettingsFragment.java │ │ ├── StoreRetrieveData.java │ │ ├── ToDoItem.java │ │ ├── TodoNotificationService.java │ │ └── Utils.java │ └── res │ ├── drawable-hdpi │ ├── check.png │ ├── empty_view_bg.png │ ├── ic_access_time_black_18dp.png │ ├── ic_add_alarm_grey_200_24dp.png │ ├── ic_add_white_24dp.png │ ├── ic_alarm_add_white_24dp.png │ ├── ic_alarm_black_18dp.png │ ├── ic_clear_white_24dp.png │ ├── ic_color_lens_white_24dp.png │ ├── ic_done_white_24dp.png │ ├── ic_menu_overflow_light.png │ ├── ic_reorder_grey_600_18dp.png │ ├── ic_send_white_18dp.png │ ├── ic_snooze_black_24dp.png │ └── ic_snooze_white_24dp.png │ ├── drawable-ldpi │ ├── check.png │ └── empty_view_bg.png │ ├── drawable-mdpi │ ├── check.png │ ├── empty_view_bg.png │ ├── ic_access_time_black_18dp.png │ ├── ic_add_alarm_grey_200_24dp.png │ ├── ic_add_white_24dp.png │ ├── ic_alarm_add_white_24dp.png │ ├── ic_alarm_black_18dp.png │ ├── ic_clear_white_24dp.png │ ├── ic_color_lens_white_24dp.png │ ├── ic_done_white_24dp.png │ ├── ic_menu_overflow_light.png │ ├── ic_reorder_grey_600_18dp.png │ ├── ic_send_white_18dp.png │ ├── ic_snooze_black_24dp.png │ └── ic_snooze_white_24dp.png │ ├── drawable-xhdpi │ ├── check.png │ ├── empty_view_bg.png │ ├── ic_access_time_black_18dp.png │ ├── ic_add_alarm_grey_200_24dp.png │ ├── ic_add_white_24dp.png │ ├── ic_alarm_add_white_24dp.png │ ├── ic_alarm_black_18dp.png │ ├── ic_clear_white_24dp.png │ ├── ic_color_lens_white_24dp.png │ ├── ic_done_white_24dp.png │ ├── ic_menu_overflow_light.png │ ├── ic_reorder_grey_600_18dp.png │ ├── ic_send_white_18dp.png │ ├── ic_snooze_black_24dp.png │ └── ic_snooze_white_24dp.png │ ├── drawable-xxhdpi │ ├── check.png │ ├── empty_view_bg.png │ ├── ic_access_time_black_18dp.png │ ├── ic_add_alarm_grey_200_24dp.png │ ├── ic_add_white_24dp.png │ ├── ic_alarm_add_white_24dp.png │ ├── ic_alarm_black_18dp.png │ ├── ic_clear_white_24dp.png │ ├── ic_color_lens_white_24dp.png │ ├── ic_done_white_24dp.png │ ├── ic_menu_overflow_light.png │ ├── ic_reorder_grey_600_18dp.png │ ├── ic_send_white_18dp.png │ ├── ic_snooze_black_24dp.png │ └── ic_snooze_white_24dp.png │ ├── drawable-xxxhdpi │ ├── check.png │ ├── empty_view_bg.png │ └── ic_menu_overflow_light.png │ ├── drawable │ ├── button_pressed_background.xml │ ├── dropdown_text_background_color.xml │ └── dropdown_text_color.xml │ ├── layout │ ├── about_layout.xml │ ├── activity_add_to_do.xml │ ├── activity_main.xml │ ├── activity_settings.xml │ ├── activity_todo_test.xml │ ├── base_toolbar.xml │ ├── date_dropdown_item.xml │ ├── date_spinner_item.xml │ ├── list_circle_try.xml │ ├── list_item_view_future.xml │ ├── reminder_layout.xml │ ├── spinner_dropdown_item.xml │ └── spinner_text_view.xml │ ├── menu │ ├── menu_main.xml │ └── menu_reminder.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-de │ └── strings.xml │ ├── values-es │ └── strings.xml │ ├── values-fi │ └── strings.xml │ ├── values-ml │ └── strings.xml │ ├── values-pl │ └── strings.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values │ ├── colors.xml │ ├── dimens.xml │ ├── donottranslate.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── global_tracker.xml │ └── preferences_layout.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── add_todo_dark.png ├── add_todo_light.png ├── app_icon.png ├── main_empty_dark.png ├── main_empty_light.png ├── main_full_dark.png ├── main_full_light.png ├── screenshot_notification.png ├── screenshot_reminder_date.png ├── screenshot_reminder_time.png ├── screenshot_todo_snooze.png ├── todo_date_dark.png └── todo_time_dark.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | #.gradle 2 | #/local.properties 3 | #/.idea/workspace.xml 4 | #/.idea/libraries 5 | #.DS_Store 6 | #/build 7 | #/captures 8 | #/.idea 9 | 10 | # Created by https://www.gitignore.io 11 | 12 | ### Android ### 13 | 14 | # Files for the Dalvik VM 15 | *.dex 16 | 17 | # Java class files 18 | *.class 19 | 20 | # Generated files 21 | bin/ 22 | gen/ 23 | 24 | # Gradle files 25 | .gradle/ 26 | build/ 27 | 28 | # Local configuration file (sdk path, etc) 29 | local.properties 30 | 31 | # Proguard folder generated by Eclipse 32 | proguard/ 33 | 34 | # Log Files 35 | *.log 36 | 37 | 38 | ### Intellij ### 39 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 40 | 41 | *.iml 42 | 43 | ## Directory-based project format: 44 | .idea/ 45 | # if you remove the above rule, at least ignore the following: 46 | 47 | # User-specific stuff: 48 | # .idea/workspace.xml 49 | # .idea/tasks.xml 50 | # .idea/dictionaries 51 | 52 | # Sensitive or high-churn files: 53 | # .idea/dataSources.ids 54 | # .idea/dataSources.xml 55 | # .idea/sqlDataSources.xml 56 | # .idea/dynamic.xml 57 | # .idea/uiDesigner.xml 58 | 59 | # Gradle: 60 | # .idea/gradle.xml 61 | # .idea/libraries 62 | 63 | # Mongo Explorer plugin: 64 | # .idea/mongoSettings.xml 65 | 66 | ## File-based project format: 67 | *.ipr 68 | *.iws 69 | 70 | ## Plugin-specific files: 71 | 72 | # IntelliJ 73 | out/ 74 | 75 | # mpeltonen/sbt-idea plugin 76 | .idea_modules/ 77 | 78 | # JIRA plugin 79 | atlassian-ide-plugin.xml 80 | 81 | # Crashlytics plugin (for Android Studio and IntelliJ) 82 | com_crashlytics_export_strings.xml 83 | 84 | # Ignore Gradle GUI config 85 | gradle-app.setting 86 | 87 | # Mobile Tools for Java (J2ME) 88 | .mtj.tmp/ 89 | 90 | # Package Files # 91 | *.war 92 | *.ear 93 | 94 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 95 | hs_err_pid* 96 | 97 | *.DS_Store 98 | Status API Training Shop Blog About Pricing 99 | © 2015 GitHub, Inc. Terms Privacy Security Contact Help -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Minimal -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | android: 3 | components: 4 | - platform-tools 5 | - tools 6 | 7 | - build-tools-23.0.1 8 | 9 | - android-23 10 | 11 | - extra-google-google_play_services 12 | - extra-google-m2repository 13 | - extra-android-m2repository 14 | 15 | before_script: 16 | - chmod +x gradlew 17 | 18 | script: "./gradlew build" 19 | 20 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | [Minimal-Todo](https://github.com/avjinder/Minimal-Todo) - Material To-Do App 2 | ================================================== 3 | 4 | Welcome, so you are thinking about contributing to Minimal-Todo? Awesome, this is a great place to start. 5 | 6 | Get in Touch 7 | ------------ 8 | 9 | If you are a first time contributor and want some help getting started feel free to send a private email to any of the following maintainers: 10 | 11 | * Avjinder (avisekhon@gmail.com) 12 | 13 | Help Wanted 14 | ---------------- 15 | 16 | #### If you have an error or support request 17 | 18 | - Read the error message and documentation. 19 | - Search [existing issues](https://github.com/avjinder/Minimal-Todo/issues), [closed issues](https://github.com/avjinder/Minimal-Todo/issues?page=1&state=closed), and [the internet](https://google.com) first. 20 | - If the issue is with a dependency of this project, post on the dependency's repo. 21 | - If you can fix the issue, submit a PR :+1: :dancer: :dancer: :rocket:. 22 | - If the issue persists, post on the issue tracker. Include any information that could help others reproduce and fix. 23 | 24 | #### If you have a feature proposal or want to contribute 25 | 26 | - Post your proposal on the issue tracker so we can review it together. Some proposals may not be a good fit for the project. 27 | - Contribute a PR. 28 | - Respond to code review. 29 | - Watch the PR be merged, and bathe in a job well done :icecream: :+1: :horse: :v: :palm_tree:. 30 | 31 | Every piece of software is a work in progress. This project is the result of many hours of work contributed freely by myself and the many people that build the projects it depends on. 32 | 33 | Please respect our time, effort, and good will. Issues with a demanding or entitled tone will be closed until reworded. 34 | 35 | Git Essentials 36 | -------------------------------------- 37 | 38 | Workflows can vary, but here is a very simple workflow for contributing a bug fix: 39 | 40 | $ git clone git@github.com:myfork/Minimal-Todo.git 41 | $ git remote add Minimal-Todo https://github.com/Minimal-Todo/Minimal-Todo.git 42 | $ git checkout -b 121-issue-keyword master 43 | $ git commit -m "(#121) - Description of what I had changed" 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Avjinder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minimal [![Build Status](https://travis-ci.org/avjinder/Minimal-Todo.svg?branch=master)](https://travis-ci.org/avjinder/Minimal-Todo) 2 | 3 |
4 | A fully Material ToDo app with minimal features, just enough to be useful. 5 | 6 | 7 | #Screenshots: 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ##Download 22 | 23 | Get it on Google Play 25 | 26 | 27 | 28 | ##App Icon 29 | Designed by [Christopher Gundersen](cgundersen2020@gmail.com) 30 | ##Translations 31 | * Spanish by [nanopc](https://github.com/nanopc)
32 | * German by [kaiwinter](https://github.com/kaiwinter)
33 | * Polish by [piotrek1543](https://github.com/piotrek1543)
34 | * Finnish by [Miikka Andersson](https://github.com/miikande)
35 | 36 | ##Contributing 37 | Looking to contribute something to Minimal? [Here's how you can help](/Contributing.md). 38 | 39 | 40 | #License: 41 | The MIT License (MIT) 42 | 43 | Copyright (c) 2015 Avjinder 44 | 45 | Permission is hereby granted, free of charge, to any person obtaining a copy 46 | of this software and associated documentation files (the "Software"), to deal 47 | in the Software without restriction, including without limitation the rights 48 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 49 | copies of the Software, and to permit persons to whom the Software is 50 | furnished to do so, subject to the following conditions: 51 | 52 | The above copyright notice and this permission notice shall be included in all 53 | copies or substantial portions of the Software. 54 | 55 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 56 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 57 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 58 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 59 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 60 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 61 | SOFTWARE. 62 | 63 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | #/google-services.json 2 | /build 3 | 4 | #.gradle 5 | #/local.properties 6 | #/.idea/workspace.xml 7 | #/.idea/libraries 8 | #.DS_Store 9 | #/build 10 | #/captures 11 | #/.idea 12 | 13 | # Created by https://www.gitignore.io 14 | 15 | ### Android ### 16 | 17 | # Files for the Dalvik VM 18 | *.dex 19 | 20 | # Java class files 21 | *.class 22 | 23 | # Generated files 24 | bin/ 25 | gen/ 26 | 27 | # Gradle files 28 | .gradle/ 29 | build/ 30 | 31 | # Local configuration file (sdk path, etc) 32 | local.properties 33 | 34 | # Proguard folder generated by Eclipse 35 | proguard/ 36 | 37 | # Log Files 38 | *.log 39 | 40 | 41 | ### Intellij ### 42 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 43 | 44 | *.iml 45 | 46 | ## Directory-based project format: 47 | .idea/ 48 | # if you remove the above rule, at least ignore the following: 49 | 50 | # User-specific stuff: 51 | # .idea/workspace.xml 52 | # .idea/tasks.xml 53 | # .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | # .idea/dataSources.ids 57 | # .idea/dataSources.xml 58 | # .idea/sqlDataSources.xml 59 | # .idea/dynamic.xml 60 | # .idea/uiDesigner.xml 61 | 62 | # Gradle: 63 | # .idea/gradle.xml 64 | # .idea/libraries 65 | 66 | # Mongo Explorer plugin: 67 | # .idea/mongoSettings.xml 68 | 69 | ## File-based project format: 70 | *.ipr 71 | *.iws 72 | 73 | ## Plugin-specific files: 74 | 75 | # IntelliJ 76 | out/ 77 | 78 | # mpeltonen/sbt-idea plugin 79 | .idea_modules/ 80 | 81 | # JIRA plugin 82 | atlassian-ide-plugin.xml 83 | 84 | # Crashlytics plugin (for Android Studio and IntelliJ) 85 | com_crashlytics_export_strings.xml 86 | 87 | # Ignore Gradle GUI config 88 | gradle-app.setting 89 | 90 | # Mobile Tools for Java (J2ME) 91 | .mtj.tmp/ 92 | 93 | # Package Files # 94 | *.war 95 | *.ear 96 | 97 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 98 | hs_err_pid* 99 | 100 | *.DS_Store 101 | Status API Training Shop Blog About Pricing 102 | © 103 | 104 | src/main/res/xml/app_tracker.xml -------------------------------------------------------------------------------- /app/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenroy/Minimal-Todo/6b6383d44c95697d59b2ab35f24f042ef537b898/app/app-release.apk -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.google.gms.google-services' 3 | 4 | android { 5 | signingConfigs { 6 | release { 7 | keyAlias '' 8 | keyPassword '' 9 | storeFile file('/Users/avjindersinghsekhon/androidapps.jks') 10 | storePassword '' 11 | } 12 | } 13 | compileSdkVersion 23 14 | buildToolsVersion "23.0.1" 15 | defaultConfig { 16 | applicationId "com.avjindersinghsekhon.minimaltodo" 17 | minSdkVersion 16 18 | targetSdkVersion 23 19 | versionCode 3 20 | versionName "1.2" 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled true 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | sourceSets { main { assets.srcDirs = ['src/main/assets', 'src/main/assets/'] } } 29 | lintOptions { 30 | abortOnError false 31 | } 32 | } 33 | 34 | dependencies { 35 | compile fileTree(dir: 'libs', include: ['*.jar']) 36 | compile 'com.google.android.gms:play-services-analytics:7.8.0' 37 | compile 'uk.co.chrisjenx:calligraphy:2.1.0' 38 | compile 'com.github.ganfra:material-spinner:1.1.0' 39 | compile 'com.wdullaer:materialdatetimepicker:1.5.1' 40 | compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' 41 | compile 'com.github.ganfra:material-spinner:1.1.0' 42 | compile 'com.android.support:recyclerview-v7:23.1.0' 43 | compile 'com.android.support:design:23.1.0' 44 | compile 'com.android.support:appcompat-v7:23.1.0' 45 | compile 'com.android.support:support-v13:23.1.0' 46 | } 47 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | {"project_info":{"project_id":"minimal-e817","project_number":"155600168514","name":"Minimal"},"client":[{"client_info":{"client_id":"android:com.avjindersekhon.minimal","client_type":1,"android_client_info":{"package_name":"com.avjindersekhon.minimal"}},"oauth_client":[],"api_key":[],"services":{"analytics_service":{"status":1},"cloud_messaging_service":{"status":1,"apns_config":[]},"appinvite_service":{"status":1,"other_platform_oauth_client":[]},"google_signin_service":{"status":1},"ads_service":{"status":1}}},{"client_info":{"client_id":"android:com.avjindersekhon.minimaltodo","client_type":1,"android_client_info":{"package_name":"com.avjindersekhon.minimaltodo"}},"oauth_client":[],"api_key":[],"services":{"analytics_service":{"status":2,"analytics_property":{"tracking_id":"UA-00000000-0"}},"cloud_messaging_service":{"status":1,"apns_config":[]},"appinvite_service":{"status":1,"other_platform_oauth_client":[]},"google_signin_service":{"status":1},"ads_service":{"status":1}}}],"client_info":[],"ARTIFACT_VERSION":"1"} -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/avjindersinghsekhon/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | -keep public class com.google.** {*;} 20 | -keep public class com.google.android.gms.* { public *; } 21 | -dontwarn com.google.android.gms.** 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/avjindersinghsekhon/minimaltodo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/avjindersinghsekhon/minimaltodo/TestStoreRetrieveData.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 Miikka Andersson 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 8 | * associated documentation files (the "Software"), to deal in the Software without restriction, 9 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 10 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 17 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | */ 23 | 24 | package com.example.avjindersinghsekhon.minimaltodo; 25 | 26 | import android.content.Context; 27 | import android.test.ActivityUnitTestCase; 28 | 29 | import org.json.JSONArray; 30 | 31 | import java.util.ArrayList; 32 | import java.util.Date; 33 | 34 | /** 35 | * Test cases for StoreRetrieveData class 36 | */ 37 | public class TestStoreRetrieveData extends ActivityUnitTestCase { 38 | 39 | private MainActivity mMainActivity; 40 | private ArrayList mOriginalData; 41 | ArrayList mTestData; 42 | 43 | public TestStoreRetrieveData() { 44 | super(MainActivity.class); 45 | 46 | // Create some test data 47 | mTestData = new ArrayList<>(); 48 | for (int i = 1; i < 11; i++) { 49 | mTestData.add(new ToDoItem( 50 | "item" + i, 51 | false, 52 | new Date())); 53 | } 54 | } 55 | 56 | @Override 57 | protected void setUp() throws Exception { 58 | super.setUp(); 59 | mMainActivity = getActivity(); 60 | mOriginalData = new ArrayList<>(); 61 | 62 | // Save the original data and wipe out the storage 63 | StoreRetrieveData dataStorage = getDataStorage(); 64 | try { 65 | ArrayList items = dataStorage.loadFromFile(); 66 | 67 | if (items.size() > 0) { 68 | mOriginalData.clear(); 69 | mOriginalData.addAll(items); 70 | 71 | items.clear(); 72 | dataStorage.saveToFile(items); 73 | } 74 | 75 | } catch (Exception e) { 76 | fail("Couldn't store data: " + e.getMessage()); 77 | } 78 | } 79 | 80 | @Override 81 | protected void tearDown() throws Exception { 82 | super.tearDown(); 83 | 84 | // Let's restore the data we might have wiped out during setUp()... 85 | StoreRetrieveData dataStorage = getDataStorage(); 86 | dataStorage.saveToFile(mOriginalData); 87 | } 88 | 89 | /** 90 | * We should have an empty data storage at hand for the starters 91 | */ 92 | public void testPreconditions() { 93 | StoreRetrieveData dataStorage = getDataStorage(); 94 | 95 | ArrayList items = null; 96 | try { 97 | items = dataStorage.loadFromFile(); 98 | } catch (Exception e) { 99 | fail("Couldn't read from data storage: " + e.getMessage()); 100 | } 101 | 102 | assertEquals(0, items.size()); 103 | } 104 | 105 | /** 106 | * Write items to data storage and ensure those same items can be retrieved from the storage. 107 | */ 108 | public void testWritingToAndReadingFromTheDataStorage() { 109 | StoreRetrieveData dataStorage = getDataStorage(); 110 | ArrayList retrievedItems = new ArrayList<>(); 111 | 112 | // Persist the test data 113 | try { 114 | dataStorage.saveToFile(mTestData); 115 | } catch (Exception e) { 116 | fail("Couldn't store data: " + e.getMessage()); 117 | } 118 | 119 | // Read from storage 120 | try { 121 | retrievedItems = dataStorage.loadFromFile(); 122 | } catch (Exception e) { 123 | fail("Couldn't read from data storage: " + e.getMessage()); 124 | } 125 | 126 | // We should have equal amount of items than what we just stored 127 | assertEquals(mTestData.size(), retrievedItems.size()); 128 | 129 | // The content should be same as well... 130 | for (ToDoItem retrievedItem : retrievedItems) { 131 | // We want to be sure every single item in data storage can also be found from 132 | // our test data collection 133 | boolean found = false; 134 | for (ToDoItem testItem : mTestData) { 135 | 136 | // Check the items are same 137 | if (retrievedItem.getIdentifier().equals(testItem.getIdentifier()) && 138 | retrievedItem.getToDoText().equals(testItem.getToDoText()) && 139 | retrievedItem.hasReminder() == testItem.hasReminder() && 140 | retrievedItem.getToDoDate().equals(testItem.getToDoDate())) { 141 | 142 | found = true; 143 | break; 144 | } 145 | } 146 | 147 | if (!found) { 148 | fail("Content mis-match between test data and data retrieved from the storage!"); 149 | } 150 | } 151 | } 152 | 153 | /** 154 | * Ensure JSONArray conversion works as intended 155 | */ 156 | public void testArrayListToJsonArrayConversion() { 157 | try { 158 | JSONArray array = StoreRetrieveData.toJSONArray(mTestData); 159 | assertEquals(mTestData.size(), array.length()); 160 | } catch (Exception e) { 161 | fail("Exception thrown when converting to JSONArray: " + e.getMessage()); 162 | } 163 | } 164 | 165 | private StoreRetrieveData getDataStorage() { 166 | Context context = getInstrumentation().getTargetContext(); 167 | return new StoreRetrieveData(context, MainActivity.FILENAME); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/avjindersinghsekhon/minimaltodo/TestTodoItem.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 Miikka Andersson 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 8 | * associated documentation files (the "Software"), to deal in the Software without restriction, 9 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 10 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all copies or 14 | * substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 17 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | */ 23 | 24 | package com.example.avjindersinghsekhon.minimaltodo; 25 | 26 | import junit.framework.TestCase; 27 | 28 | import org.json.JSONException; 29 | import org.json.JSONObject; 30 | 31 | import java.util.Date; 32 | 33 | /** 34 | * JUnit tests to verify functionality of ToDoItem class. 35 | */ 36 | public class TestTodoItem extends TestCase { 37 | private final Date CURRENT_DATE = new Date(); 38 | private final String TEXT_BODY = "This is some text"; 39 | private final boolean REMINDER_OFF = false; 40 | private final boolean REMINDER_ON = true; 41 | 42 | /** 43 | * Check we can construct a ToDoItem object using the three parameter constructor 44 | */ 45 | public void testThreeParameterConstructor() { 46 | ToDoItem toDoItem = getToDoItem(REMINDER_OFF); 47 | assertEquals(TEXT_BODY, toDoItem.getToDoText()); 48 | assertEquals(REMINDER_OFF, toDoItem.hasReminder()); 49 | assertEquals(CURRENT_DATE, toDoItem.getToDoDate()); 50 | } 51 | 52 | /** 53 | * Ensure we can marshall ToDoItem objects to Json 54 | */ 55 | public void testObjectMarshallingToJson() { 56 | ToDoItem toDoItem = getToDoItem(REMINDER_ON); 57 | 58 | try { 59 | JSONObject json = toDoItem.toJSON(); 60 | assertEquals(TEXT_BODY, json.getString("todotext")); 61 | assertEquals(REMINDER_ON, json.getBoolean("todoreminder")); 62 | assertEquals(String.valueOf(CURRENT_DATE.getTime()), json.getString("tododate")); 63 | } catch (JSONException e) { 64 | fail("Exception thrown during test execution: " + e.getMessage()); 65 | } 66 | } 67 | 68 | /** 69 | * Ensure we can create ToDoItem objects from Json data by using the json constructor 70 | */ 71 | public void testObjectUnmarshallingFromJson() { 72 | ToDoItem originalItem = getToDoItem(REMINDER_OFF); 73 | 74 | try { 75 | JSONObject json = originalItem.toJSON(); 76 | ToDoItem itemFromJson = new ToDoItem(json); 77 | 78 | assertEquals(originalItem.getToDoText(), itemFromJson.getToDoText()); 79 | assertEquals(originalItem.getToDoDate(), itemFromJson.getToDoDate()); 80 | assertEquals(originalItem.hasReminder(), itemFromJson.hasReminder()); 81 | assertEquals(originalItem.getIdentifier(), itemFromJson.getIdentifier()); 82 | 83 | } catch (JSONException e) { 84 | fail("Exception thrown during test execution: " + e.getMessage()); 85 | } 86 | } 87 | 88 | private ToDoItem getToDoItem(boolean hasReminder) { 89 | return new ToDoItem(TEXT_BODY, hasReminder, CURRENT_DATE); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 12 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 40 | 41 | 44 | 45 | 47 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Aller_Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenroy/Minimal-Todo/6b6383d44c95697d59b2ab35f24f042ef537b898/app/src/main/assets/fonts/Aller_Regular.ttf -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.content.Intent; 4 | import android.content.pm.PackageInfo; 5 | import android.graphics.Color; 6 | import android.graphics.PorterDuff; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Bundle; 9 | import android.support.v4.app.NavUtils; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.support.v7.widget.Toolbar; 12 | import android.util.Log; 13 | import android.view.MenuItem; 14 | import android.view.View; 15 | import android.widget.TextView; 16 | 17 | public class AboutActivity extends AppCompatActivity { 18 | private TextView mVersionTextView; 19 | private String appVersion = "0.1"; 20 | private Toolbar toolbar; 21 | private TextView contactMe; 22 | String theme; 23 | // private UUID mId; 24 | private AnalyticsApplication app; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | app = (AnalyticsApplication)getApplication(); 29 | app.send(this); 30 | 31 | theme = getSharedPreferences(MainActivity.THEME_PREFERENCES, MODE_PRIVATE).getString(MainActivity.THEME_SAVED, MainActivity.LIGHTTHEME); 32 | if(theme.equals(MainActivity.DARKTHEME)){ 33 | Log.d("OskarSchindler", "One"); 34 | setTheme(R.style.CustomStyle_DarkTheme); 35 | } 36 | else{ 37 | Log.d("OskarSchindler", "One"); 38 | setTheme(R.style.CustomStyle_LightTheme); 39 | } 40 | 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.about_layout); 43 | 44 | Intent i = getIntent(); 45 | // mId = (UUID)i.getSerializableExtra(TodoNotificationService.TODOUUID); 46 | 47 | final Drawable backArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha); 48 | if(backArrow!=null){ 49 | backArrow.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP); 50 | 51 | } 52 | try{ 53 | PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0); 54 | appVersion = info.versionName; 55 | } 56 | catch (Exception e){ 57 | e.printStackTrace(); 58 | } 59 | 60 | 61 | mVersionTextView = (TextView)findViewById(R.id.aboutVersionTextView); 62 | mVersionTextView.setText(String.format(getResources().getString(R.string.app_version), appVersion)); 63 | toolbar = (Toolbar)findViewById(R.id.toolbar); 64 | contactMe = (TextView)findViewById(R.id.aboutContactMe); 65 | 66 | contactMe.setOnClickListener(new View.OnClickListener() { 67 | @Override 68 | public void onClick(View v) { 69 | app.send(this, "Action", "Feedback"); 70 | } 71 | }); 72 | 73 | 74 | setSupportActionBar(toolbar); 75 | if(getSupportActionBar()!=null){ 76 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 77 | getSupportActionBar().setHomeAsUpIndicator(backArrow); 78 | } 79 | } 80 | 81 | @Override 82 | public boolean onOptionsItemSelected(MenuItem item) { 83 | switch (item.getItemId()){ 84 | case android.R.id.home: 85 | if(NavUtils.getParentActivityName(this)!=null){ 86 | NavUtils.navigateUpFromSameTask(this); 87 | } 88 | return true; 89 | default: 90 | return super.onOptionsItemSelected(item); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/AddToDoActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.animation.Animator; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.graphics.PorterDuff; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Bundle; 9 | import android.support.design.widget.FloatingActionButton; 10 | import android.support.v4.app.NavUtils; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.support.v7.widget.SwitchCompat; 13 | import android.support.v7.widget.Toolbar; 14 | import android.text.Editable; 15 | import android.text.TextWatcher; 16 | import android.text.format.DateFormat; 17 | import android.util.Log; 18 | import android.view.MenuItem; 19 | import android.view.View; 20 | import android.view.inputmethod.InputMethodManager; 21 | import android.widget.Button; 22 | import android.widget.CompoundButton; 23 | import android.widget.EditText; 24 | import android.widget.ImageButton; 25 | import android.widget.LinearLayout; 26 | import android.widget.TextView; 27 | import android.widget.Toast; 28 | 29 | import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; 30 | import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout; 31 | import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; 32 | 33 | import java.text.SimpleDateFormat; 34 | import java.util.Calendar; 35 | import java.util.Date; 36 | 37 | public class AddToDoActivity extends AppCompatActivity implements DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener{ 38 | private Date mLastEdited; 39 | private EditText mToDoTextBodyEditText; 40 | private SwitchCompat mToDoDateSwitch; 41 | // private TextView mLastSeenTextView; 42 | private LinearLayout mUserDateSpinnerContainingLinearLayout; 43 | private TextView mReminderTextView; 44 | 45 | private EditText mDateEditText; 46 | private EditText mTimeEditText; 47 | private String mDefaultTimeOptions12H[]; 48 | private String mDefaultTimeOptions24H[]; 49 | 50 | private Button mChooseDateButton; 51 | private Button mChooseTimeButton; 52 | private ToDoItem mUserToDoItem; 53 | private FloatingActionButton mToDoSendFloatingActionButton; 54 | public static final String DATE_FORMAT = "MMM d, yyyy"; 55 | public static final String DATE_FORMAT_MONTH_DAY = "MMM d"; 56 | public static final String DATE_FORMAT_TIME = "H:m"; 57 | 58 | private String mUserEnteredText; 59 | private boolean mUserHasReminder; 60 | private Toolbar mToolbar; 61 | private Date mUserReminderDate; 62 | private int mUserColor; 63 | private boolean setDateButtonClickedOnce = false; 64 | private boolean setTimeButtonClickedOnce = false; 65 | private LinearLayout mContainerLayout; 66 | private String theme; 67 | AnalyticsApplication app; 68 | 69 | @Override 70 | protected void onResume() { 71 | super.onResume(); 72 | app.send(this); 73 | } 74 | 75 | @SuppressWarnings("deprecation") 76 | @Override 77 | protected void onCreate(Bundle savedInstanceState) { 78 | app = (AnalyticsApplication)getApplication(); 79 | // setContentView(R.layout.new_to_do_layout); 80 | //Need references to these to change them during light/dark mode 81 | ImageButton reminderIconImageButton; 82 | TextView reminderRemindMeTextView; 83 | 84 | 85 | theme = getSharedPreferences(MainActivity.THEME_PREFERENCES, MODE_PRIVATE).getString(MainActivity.THEME_SAVED, MainActivity.LIGHTTHEME); 86 | if(theme.equals(MainActivity.LIGHTTHEME)){ 87 | setTheme(R.style.CustomStyle_LightTheme); 88 | Log.d("OskarSchindler", "Light Theme"); 89 | } 90 | else{ 91 | setTheme(R.style.CustomStyle_DarkTheme); 92 | } 93 | 94 | super.onCreate(savedInstanceState); 95 | // setContentView(R.layout.activity_add_to_do); 96 | //Testing out a new layout 97 | setContentView(R.layout.activity_todo_test); 98 | 99 | //Show an X in place of <- 100 | final Drawable cross = getResources().getDrawable(R.drawable.ic_clear_white_24dp); 101 | if(cross !=null){ 102 | cross.setColorFilter(getResources().getColor(R.color.icons), PorterDuff.Mode.SRC_ATOP); 103 | } 104 | 105 | mToolbar = (Toolbar)findViewById(R.id.toolbar); 106 | setSupportActionBar(mToolbar); 107 | 108 | if(getSupportActionBar()!=null){ 109 | getSupportActionBar().setElevation(0); 110 | getSupportActionBar().setDisplayShowTitleEnabled(false); 111 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 112 | getSupportActionBar().setHomeAsUpIndicator(cross ); 113 | 114 | } 115 | 116 | 117 | mUserToDoItem = (ToDoItem)getIntent().getSerializableExtra(MainActivity.TODOITEM); 118 | 119 | mUserEnteredText = mUserToDoItem.getToDoText(); 120 | mUserHasReminder = mUserToDoItem.hasReminder(); 121 | mUserReminderDate = mUserToDoItem.getToDoDate(); 122 | mUserColor = mUserToDoItem.getTodoColor(); 123 | 124 | 125 | // if(mUserToDoItem.getLastEdited()==null) { 126 | // mLastEdited = new Date(); 127 | // } 128 | // else{ 129 | // mLastEdited = mUserToDoItem.getLastEdited(); 130 | // } 131 | 132 | 133 | reminderIconImageButton = (ImageButton)findViewById(R.id.userToDoReminderIconImageButton); 134 | reminderRemindMeTextView = (TextView)findViewById(R.id.userToDoRemindMeTextView); 135 | if(theme.equals(MainActivity.DARKTHEME)){ 136 | reminderIconImageButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_alarm_add_white_24dp)); 137 | reminderRemindMeTextView.setTextColor(Color.WHITE); 138 | } 139 | 140 | 141 | mContainerLayout = (LinearLayout)findViewById(R.id.todoReminderAndDateContainerLayout); 142 | mUserDateSpinnerContainingLinearLayout = (LinearLayout)findViewById(R.id.toDoEnterDateLinearLayout); 143 | mToDoTextBodyEditText = (EditText)findViewById(R.id.userToDoEditText); 144 | mToDoDateSwitch = (SwitchCompat)findViewById(R.id.toDoHasDateSwitchCompat); 145 | // mLastSeenTextView = (TextView)findViewById(R.id.toDoLastEditedTextView); 146 | mToDoSendFloatingActionButton = (FloatingActionButton)findViewById(R.id.makeToDoFloatingActionButton); 147 | mReminderTextView = (TextView)findViewById(R.id.newToDoDateTimeReminderTextView); 148 | 149 | 150 | mContainerLayout.setOnClickListener(new View.OnClickListener() { 151 | @Override 152 | public void onClick(View v) { 153 | hideKeyboard(mToDoTextBodyEditText); 154 | } 155 | }); 156 | 157 | 158 | if(mUserHasReminder && (mUserReminderDate!=null)){ 159 | // mUserDateSpinnerContainingLinearLayout.setVisibility(View.VISIBLE); 160 | setReminderTextView(); 161 | setEnterDateLayoutVisibleWithAnimations(true); 162 | } 163 | if(mUserReminderDate==null){ 164 | mToDoDateSwitch.setChecked(false); 165 | mReminderTextView.setVisibility(View.INVISIBLE); 166 | } 167 | 168 | // TextInputLayout til = (TextInputLayout)findViewById(R.id.toDoCustomTextInput); 169 | // til.requestFocus(); 170 | mToDoTextBodyEditText.requestFocus(); 171 | mToDoTextBodyEditText.setText(mUserEnteredText); 172 | InputMethodManager imm = (InputMethodManager)this.getSystemService(INPUT_METHOD_SERVICE); 173 | // imm.showSoftInput(mToDoTextBodyEditText, InputMethodManager.SHOW_IMPLICIT); 174 | imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); 175 | mToDoTextBodyEditText.setSelection(mToDoTextBodyEditText.length()); 176 | 177 | 178 | mToDoTextBodyEditText.addTextChangedListener(new TextWatcher() { 179 | @Override 180 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 181 | 182 | } 183 | 184 | @Override 185 | public void onTextChanged(CharSequence s, int start, int before, int count) { 186 | mUserEnteredText = s.toString(); 187 | 188 | } 189 | 190 | @Override 191 | public void afterTextChanged(Editable s) { 192 | 193 | } 194 | }); 195 | 196 | 197 | // String lastSeen = formatDate(DATE_FORMAT, mLastEdited); 198 | // mLastSeenTextView.setText(String.format(getResources().getString(R.string.last_edited), lastSeen)); 199 | 200 | setEnterDateLayoutVisible(mToDoDateSwitch.isChecked()); 201 | 202 | mToDoDateSwitch.setChecked(mUserHasReminder && (mUserReminderDate != null)); 203 | mToDoDateSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 204 | @Override 205 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 206 | if(isChecked){ 207 | app.send(this, "Action", "Reminder Set"); 208 | } 209 | else{ 210 | app.send(this, "Action", "Reminder Removed"); 211 | 212 | } 213 | 214 | if (!isChecked) { 215 | mUserReminderDate = null; 216 | } 217 | mUserHasReminder = isChecked; 218 | setDateAndTimeEditText(); 219 | setEnterDateLayoutVisibleWithAnimations(isChecked); 220 | hideKeyboard(mToDoTextBodyEditText); 221 | } 222 | }); 223 | 224 | 225 | mToDoSendFloatingActionButton.setOnClickListener(new View.OnClickListener() { 226 | @Override 227 | public void onClick(View v) { 228 | if(mUserReminderDate!=null && mUserReminderDate.before(new Date())){ 229 | app.send(this, "Action", "Date in the Past"); 230 | makeResult(RESULT_CANCELED); 231 | } 232 | else{ 233 | app.send(this, "Action", "Make Todo"); 234 | makeResult(RESULT_OK); 235 | } 236 | hideKeyboard(mToDoTextBodyEditText); 237 | finish(); 238 | } 239 | }); 240 | 241 | 242 | mDateEditText = (EditText)findViewById(R.id.newTodoDateEditText); 243 | mTimeEditText = (EditText)findViewById(R.id.newTodoTimeEditText); 244 | 245 | mDateEditText.setOnClickListener(new View.OnClickListener() { 246 | @Override 247 | public void onClick(View v) { 248 | 249 | Date date; 250 | hideKeyboard(mToDoTextBodyEditText); 251 | if(mUserToDoItem.getToDoDate()!=null){ 252 | // date = mUserToDoItem.getToDoDate(); 253 | date = mUserReminderDate; 254 | } 255 | else{ 256 | date = new Date(); 257 | } 258 | Calendar calendar = Calendar.getInstance(); 259 | calendar.setTime(date); 260 | int year = calendar.get(Calendar.YEAR); 261 | int month = calendar.get(Calendar.MONTH); 262 | int day = calendar.get(Calendar.DAY_OF_MONTH); 263 | 264 | 265 | DatePickerDialog datePickerDialog = DatePickerDialog.newInstance(AddToDoActivity.this, year, month, day); 266 | if(theme.equals(MainActivity.DARKTHEME)){ 267 | datePickerDialog.setThemeDark(true); 268 | } 269 | datePickerDialog.show(getFragmentManager(), "DateFragment"); 270 | 271 | } 272 | }); 273 | 274 | 275 | mTimeEditText.setOnClickListener(new View.OnClickListener() { 276 | @Override 277 | public void onClick(View v) { 278 | 279 | Date date; 280 | hideKeyboard(mToDoTextBodyEditText); 281 | if(mUserToDoItem.getToDoDate()!=null){ 282 | // date = mUserToDoItem.getToDoDate(); 283 | date = mUserReminderDate; 284 | } 285 | else{ 286 | date = new Date(); 287 | } 288 | Calendar calendar = Calendar.getInstance(); 289 | calendar.setTime(date); 290 | int hour = calendar.get(Calendar.HOUR_OF_DAY); 291 | int minute = calendar.get(Calendar.MINUTE); 292 | 293 | TimePickerDialog timePickerDialog = TimePickerDialog.newInstance(AddToDoActivity.this, hour, minute, DateFormat.is24HourFormat(AddToDoActivity.this)); 294 | if(theme.equals(MainActivity.DARKTHEME)){ 295 | timePickerDialog.setThemeDark(true); 296 | } 297 | timePickerDialog.show(getFragmentManager(), "TimeFragment"); 298 | } 299 | }); 300 | 301 | // mDefaultTimeOptions12H = new String[]{"9:00 AM", "12:00 PM", "3:00 PM", "6:00 PM", "9:00 PM", "12:00 AM"}; 302 | // mDefaultTimeOptions24H = new String[]{"9:00", "12:00", "15:00", "18:00", "21:00", "24:00"}; 303 | setDateAndTimeEditText(); 304 | 305 | // 306 | 307 | // mChooseDateButton = (Button)findViewById(R.id.newToDoChooseDateButton); 308 | // mChooseTimeButton = (Button)findViewById(R.id.newToDoChooseTimeButton); 309 | // 310 | // mChooseDateButton.setOnClickListener(new View.OnClickListener() { 311 | // @Override 312 | // public void onClick(View v) { 313 | // Date date; 314 | // hideKeyboard(mToDoTextBodyEditText); 315 | // if(mUserToDoItem.getToDoDate()!=null){ 316 | // date = mUserToDoItem.getToDoDate(); 317 | // } 318 | // else{ 319 | // date = new Date(); 320 | // } 321 | // Calendar calendar = Calendar.getInstance(); 322 | // calendar.setTime(date); 323 | // int year = calendar.get(Calendar.YEAR); 324 | // int month = calendar.get(Calendar.MONTH); 325 | // int day = calendar.get(Calendar.DAY_OF_MONTH); 326 | // 327 | // 328 | // DatePickerDialog datePickerDialog = DatePickerDialog.newInstance(AddToDoActivity.this, year, month, day); 329 | // if(theme.equals(MainActivity.DARKTHEME)){ 330 | // datePickerDialog.setThemeDark(true); 331 | // } 332 | // datePickerDialog.show(getFragmentManager(), "DateFragment"); 333 | // } 334 | // }); 335 | // 336 | // mChooseTimeButton.setOnClickListener(new View.OnClickListener() { 337 | // @Override 338 | // public void onClick(View v) { 339 | // Date date; 340 | // hideKeyboard(mToDoTextBodyEditText); 341 | // if(mUserToDoItem.getToDoDate()!=null){ 342 | // date = mUserToDoItem.getToDoDate(); 343 | // } 344 | // else{ 345 | // date = new Date(); 346 | // } 347 | // Calendar calendar = Calendar.getInstance(); 348 | // calendar.setTime(date); 349 | // int hour = calendar.get(Calendar.HOUR_OF_DAY); 350 | // int minute = calendar.get(Calendar.MINUTE); 351 | // 352 | // TimePickerDialog timePickerDialog = TimePickerDialog.newInstance(AddToDoActivity.this, hour, minute, DateFormat.is24HourFormat(AddToDoActivity.this)); 353 | // if(theme.equals(MainActivity.DARKTHEME)){ 354 | // timePickerDialog.setThemeDark(true); 355 | // } 356 | // timePickerDialog.show(getFragmentManager(), "TimeFragment"); 357 | // } 358 | // }); 359 | 360 | } 361 | 362 | private void setDateAndTimeEditText(){ 363 | 364 | if(mUserToDoItem.hasReminder() && mUserReminderDate!=null){ 365 | String userDate = formatDate("d MMM, yyyy", mUserReminderDate); 366 | String formatToUse; 367 | if(DateFormat.is24HourFormat(this)){ 368 | formatToUse = "k:mm"; 369 | } 370 | else{ 371 | formatToUse = "h:mm a"; 372 | 373 | } 374 | String userTime = formatDate(formatToUse, mUserReminderDate); 375 | mTimeEditText.setText(userTime); 376 | mDateEditText.setText(userDate); 377 | 378 | } 379 | else{ 380 | mDateEditText.setText(getString(R.string.date_reminder_default)); 381 | // mUserReminderDate = new Date(); 382 | boolean time24 = DateFormat.is24HourFormat(this); 383 | Calendar cal = Calendar.getInstance(); 384 | if(time24){ 385 | cal.set(Calendar.HOUR_OF_DAY, cal.get(Calendar.HOUR_OF_DAY)+1); 386 | } 387 | else{ 388 | cal.set(Calendar.HOUR, cal.get(Calendar.HOUR)+1); 389 | } 390 | cal.set(Calendar.MINUTE, 0); 391 | mUserReminderDate = cal.getTime(); 392 | Log.d("OskarSchindler", "Imagined Date: "+mUserReminderDate); 393 | String timeString; 394 | if(time24){ 395 | timeString = formatDate("k:mm", mUserReminderDate); 396 | } 397 | else{ 398 | timeString = formatDate("h:mm a", mUserReminderDate); 399 | } 400 | mTimeEditText.setText(timeString); 401 | // int hour = calendar.get(Calendar.HOUR_OF_DAY); 402 | // if(hour<9){ 403 | // timeOption = time24?mDefaultTimeOptions24H[0]:mDefaultTimeOptions12H[0]; 404 | // } 405 | // else if(hour < 12){ 406 | // timeOption = time24?mDefaultTimeOptions24H[1]:mDefaultTimeOptions12H[1]; 407 | // } 408 | // else if(hour < 15){ 409 | // timeOption = time24?mDefaultTimeOptions24H[2]:mDefaultTimeOptions12H[2]; 410 | // } 411 | // else if(hour < 18){ 412 | // timeOption = time24?mDefaultTimeOptions24H[3]:mDefaultTimeOptions12H[3]; 413 | // } 414 | // else if(hour < 21){ 415 | // timeOption = time24?mDefaultTimeOptions24H[4]:mDefaultTimeOptions12H[4]; 416 | // } 417 | // else{ 418 | // timeOption = time24?mDefaultTimeOptions24H[5]:mDefaultTimeOptions12H[5]; 419 | // } 420 | // mTimeEditText.setText(timeOption); 421 | } 422 | } 423 | 424 | private String getThemeSet(){ 425 | return getSharedPreferences(MainActivity.THEME_PREFERENCES, MODE_PRIVATE).getString(MainActivity.THEME_SAVED, MainActivity.LIGHTTHEME); 426 | } 427 | public void hideKeyboard(EditText et){ 428 | 429 | InputMethodManager imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); 430 | imm.hideSoftInputFromWindow(et.getWindowToken(), 0); 431 | } 432 | 433 | 434 | 435 | public void setDate(int year, int month, int day){ 436 | Calendar calendar = Calendar.getInstance(); 437 | int hour, minute; 438 | // int currentYear = calendar.get(Calendar.YEAR); 439 | // int currentMonth = calendar.get(Calendar.MONTH); 440 | // int currentDay = calendar.get(Calendar.DAY_OF_MONTH); 441 | 442 | Calendar reminderCalendar = Calendar.getInstance(); 443 | reminderCalendar.set(year, month, day); 444 | 445 | if(reminderCalendar.before(calendar)){ 446 | Toast.makeText(this, "My time-machine is a bit rusty", Toast.LENGTH_SHORT).show(); 447 | return; 448 | } 449 | 450 | if(mUserReminderDate!=null){ 451 | calendar.setTime(mUserReminderDate); 452 | } 453 | 454 | if(DateFormat.is24HourFormat(this)){ 455 | hour = calendar.get(Calendar.HOUR_OF_DAY); 456 | } 457 | else{ 458 | 459 | hour = calendar.get(Calendar.HOUR); 460 | } 461 | minute = calendar.get(Calendar.MINUTE); 462 | 463 | calendar.set(year, month, day, hour, minute); 464 | mUserReminderDate = calendar.getTime(); 465 | setReminderTextView(); 466 | // setDateAndTimeEditText(); 467 | setDateEditText(); 468 | } 469 | 470 | public void setTime(int hour, int minute){ 471 | Calendar calendar = Calendar.getInstance(); 472 | if(mUserReminderDate!=null){ 473 | calendar.setTime(mUserReminderDate); 474 | } 475 | 476 | // if(DateFormat.is24HourFormat(this) && hour == 0){ 477 | // //done for 24h time 478 | // hour = 24; 479 | // } 480 | int year = calendar.get(Calendar.YEAR); 481 | int month = calendar.get(Calendar.MONTH); 482 | int day = calendar.get(Calendar.DAY_OF_MONTH); 483 | Log.d("OskarSchindler", "Time set: "+hour); 484 | calendar.set(year, month, day, hour, minute, 0); 485 | mUserReminderDate = calendar.getTime(); 486 | 487 | setReminderTextView(); 488 | // setDateAndTimeEditText(); 489 | setTimeEditText(); 490 | } 491 | 492 | public void setDateEditText(){ 493 | String dateFormat = "d MMM, yyyy"; 494 | mDateEditText.setText(formatDate(dateFormat, mUserReminderDate)); 495 | } 496 | 497 | public void setTimeEditText(){ 498 | String dateFormat; 499 | if(DateFormat.is24HourFormat(this)){ 500 | dateFormat = "k:mm"; 501 | } 502 | else{ 503 | dateFormat = "h:mm a"; 504 | 505 | } 506 | mTimeEditText.setText(formatDate(dateFormat, mUserReminderDate)); 507 | } 508 | 509 | public void setReminderTextView(){ 510 | if(mUserReminderDate!=null){ 511 | mReminderTextView.setVisibility(View.VISIBLE); 512 | if(mUserReminderDate.before(new Date())){ 513 | Log.d("OskarSchindler", "DATE is "+mUserReminderDate); 514 | mReminderTextView.setText(getString(R.string.date_error_check_again)); 515 | mReminderTextView.setTextColor(Color.RED); 516 | return; 517 | } 518 | Date date = mUserReminderDate; 519 | String dateString = formatDate("d MMM, yyyy", date); 520 | String timeString; 521 | String amPmString = ""; 522 | 523 | if(DateFormat.is24HourFormat(this)){ 524 | timeString = formatDate("k:mm", date); 525 | } 526 | else{ 527 | timeString = formatDate("h:mm", date); 528 | amPmString = formatDate("a", date); 529 | } 530 | String finalString = String.format(getResources().getString(R.string.remind_date_and_time), dateString, timeString, amPmString); 531 | mReminderTextView.setTextColor(getResources().getColor(R.color.secondary_text)); 532 | mReminderTextView.setText(finalString); 533 | } 534 | else{ 535 | mReminderTextView.setVisibility(View.INVISIBLE); 536 | 537 | } 538 | } 539 | 540 | public void makeResult(int result){ 541 | Intent i = new Intent(); 542 | if(mUserEnteredText.length()>0){ 543 | 544 | String capitalizedString = Character.toUpperCase(mUserEnteredText.charAt(0))+mUserEnteredText.substring(1); 545 | mUserToDoItem.setToDoText(capitalizedString); 546 | } 547 | else{ 548 | mUserToDoItem.setToDoText(mUserEnteredText); 549 | } 550 | // mUserToDoItem.setLastEdited(mLastEdited); 551 | if(mUserReminderDate!=null){ 552 | Calendar calendar = Calendar.getInstance(); 553 | calendar.setTime(mUserReminderDate); 554 | calendar.set(Calendar.SECOND, 0); 555 | mUserReminderDate = calendar.getTime(); 556 | } 557 | mUserToDoItem.setHasReminder(mUserHasReminder); 558 | mUserToDoItem.setToDoDate(mUserReminderDate); 559 | mUserToDoItem.setTodoColor(mUserColor); 560 | i.putExtra(MainActivity.TODOITEM, mUserToDoItem); 561 | setResult(result, i); 562 | } 563 | 564 | @Override 565 | public void onBackPressed() { 566 | if(mUserReminderDate.before(new Date())){ 567 | mUserToDoItem.setToDoDate(null); 568 | } 569 | makeResult(RESULT_OK); 570 | super.onBackPressed(); 571 | } 572 | 573 | @Override 574 | public boolean onOptionsItemSelected(MenuItem item) { 575 | switch (item.getItemId()){ 576 | case android.R.id.home: 577 | if(NavUtils.getParentActivityName(this)!=null){ 578 | app.send(this, "Action", "Discard Todo"); 579 | makeResult(RESULT_CANCELED); 580 | NavUtils.navigateUpFromSameTask(this); 581 | } 582 | hideKeyboard(mToDoTextBodyEditText); 583 | return true; 584 | 585 | default: 586 | return super.onOptionsItemSelected(item); 587 | } 588 | } 589 | 590 | public static String formatDate(String formatString, Date dateToFormat){ 591 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(formatString); 592 | return simpleDateFormat.format(dateToFormat); 593 | } 594 | 595 | @Override 596 | public void onTimeSet(RadialPickerLayout radialPickerLayout, int hour, int minute) { 597 | setTime(hour, minute); 598 | } 599 | 600 | @Override 601 | public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) { 602 | setDate(year, month, day); 603 | } 604 | 605 | public void setEnterDateLayoutVisible(boolean checked){ 606 | if(checked){ 607 | mUserDateSpinnerContainingLinearLayout.setVisibility(View.VISIBLE); 608 | } 609 | else{ 610 | mUserDateSpinnerContainingLinearLayout.setVisibility(View.INVISIBLE); 611 | } 612 | } 613 | 614 | public void setEnterDateLayoutVisibleWithAnimations(boolean checked){ 615 | if(checked){ 616 | setReminderTextView(); 617 | mUserDateSpinnerContainingLinearLayout.animate().alpha(1.0f).setDuration(500).setListener( 618 | new Animator.AnimatorListener() { 619 | @Override 620 | public void onAnimationStart(Animator animation) { 621 | mUserDateSpinnerContainingLinearLayout.setVisibility(View.VISIBLE); 622 | } 623 | 624 | @Override 625 | public void onAnimationEnd(Animator animation) { 626 | } 627 | 628 | @Override 629 | public void onAnimationCancel(Animator animation) { 630 | } 631 | 632 | @Override 633 | public void onAnimationRepeat(Animator animation) { 634 | } 635 | } 636 | ); 637 | } 638 | else{ 639 | mUserDateSpinnerContainingLinearLayout.animate().alpha(0.0f).setDuration(500).setListener( 640 | new Animator.AnimatorListener() { 641 | @Override 642 | public void onAnimationStart(Animator animation) { 643 | 644 | } 645 | 646 | @Override 647 | public void onAnimationEnd(Animator animation) { 648 | mUserDateSpinnerContainingLinearLayout.setVisibility(View.INVISIBLE); 649 | } 650 | 651 | @Override 652 | public void onAnimationCancel(Animator animation) { 653 | 654 | } 655 | 656 | @Override 657 | public void onAnimationRepeat(Animator animation) { 658 | 659 | } 660 | } 661 | ); 662 | } 663 | 664 | } 665 | } 666 | 667 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/AnalyticsApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.app.Application; 4 | import android.content.pm.PackageManager; 5 | 6 | import com.google.android.gms.analytics.GoogleAnalytics; 7 | import com.google.android.gms.analytics.HitBuilders; 8 | import com.google.android.gms.analytics.Tracker; 9 | 10 | import java.util.Map; 11 | 12 | public class AnalyticsApplication extends Application { 13 | 14 | private Tracker mTracker; 15 | private static final boolean IS_ENABLED = true; 16 | synchronized private Tracker getDefaultTracker(){ 17 | if(mTracker==null){ 18 | GoogleAnalytics analytics = GoogleAnalytics.getInstance(this); 19 | 20 | /*R.xml.app_tracker contains my Analytics code 21 | To use this, go to Google Analytics, and get 22 | your code, create a file under res/xml , and save 23 | your code as UX-XXXXXXXX-Y 24 | */ 25 | 26 | //mTracker = analytics.newTracker(R.xml.app_tracker); 27 | mTracker = analytics.newTracker(R.xml.global_tracker); 28 | // 29 | mTracker.setAppName("Minimal"); 30 | mTracker.enableExceptionReporting(true); 31 | try{ 32 | mTracker.setAppId(getPackageManager().getPackageInfo(getPackageName(),0).versionName); 33 | } 34 | catch (PackageManager.NameNotFoundException e){ 35 | e.printStackTrace(); 36 | } 37 | 38 | } 39 | return mTracker; 40 | } 41 | 42 | public void send(Object screenName) { 43 | send(screenName, new HitBuilders.ScreenViewBuilder().build()); 44 | } 45 | 46 | private void send(Object screenName, Map params) { 47 | if(IS_ENABLED) { 48 | Tracker tracker = getDefaultTracker(); 49 | tracker.setScreenName(getClassName(screenName)); 50 | tracker.send(params); 51 | } 52 | } 53 | 54 | private String getClassName(Object o) { 55 | Class c = o.getClass(); 56 | while(c.isAnonymousClass()) { 57 | c = c.getEnclosingClass(); 58 | } 59 | return c.getSimpleName(); 60 | 61 | } 62 | public void send(Object screenName, String category, String action) { 63 | send(screenName, new HitBuilders.EventBuilder().setCategory(category).setAction(action).build()); 64 | } 65 | 66 | public void send(Object screenName, String category, String action, String label) { 67 | send(screenName, new HitBuilders.EventBuilder().setCategory(category).setAction(action).setLabel(label).build()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/CustomRecyclerScrollViewListener.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.util.Log; 5 | 6 | public abstract class CustomRecyclerScrollViewListener extends RecyclerView.OnScrollListener { 7 | int scrollDist = 0; 8 | boolean isVisible = true; 9 | static final float MINIMUM = 20; 10 | 11 | @Override 12 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 13 | super.onScrolled(recyclerView, dx, dy); 14 | // Log.d("OskarSchindler", "Scroll Distance "+scrollDist); 15 | 16 | if(isVisible && scrollDist>MINIMUM){ 17 | Log.d("OskarSchindler", "Hide "+scrollDist); 18 | hide(); 19 | scrollDist = 0; 20 | isVisible = false; 21 | } 22 | else if(!isVisible && scrollDist < -MINIMUM){ 23 | Log.d("OskarSchindler", "Show "+scrollDist); 24 | show(); 25 | scrollDist = 0; 26 | isVisible =true; 27 | } 28 | if((isVisible && dy>0) || (!isVisible && dy<0)){ 29 | Log.d("OskarSchindler", "Add Up "+scrollDist); 30 | scrollDist += dy; 31 | } 32 | } 33 | public abstract void show(); 34 | public abstract void hide(); 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/CustomTextInputLayout.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.support.design.widget.TextInputLayout; 7 | import android.support.v4.view.ViewCompat; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.EditText; 12 | 13 | public class CustomTextInputLayout extends TextInputLayout { 14 | 15 | private boolean mIsHintSet; 16 | private CharSequence mHint; 17 | 18 | public CustomTextInputLayout(Context context) { 19 | super(context); 20 | } 21 | 22 | public CustomTextInputLayout(Context context, AttributeSet attrs) { 23 | super(context, attrs); 24 | } 25 | 26 | @Override 27 | public void addView(View child, int index, ViewGroup.LayoutParams params) { 28 | if (child instanceof EditText) { 29 | // Since hint will be nullify on EditText once on parent addView, store hint value locally 30 | mHint = ((EditText)child).getHint(); 31 | } 32 | super.addView(child, index, params); 33 | } 34 | 35 | @Override 36 | protected void onDraw(Canvas canvas) { 37 | super.onDraw(canvas); 38 | 39 | if (!mIsHintSet && ViewCompat.isLaidOut(this)) { 40 | // We have to reset the previous hint so that equals check pass 41 | setHint(null); 42 | 43 | // In case that hint is changed programatically 44 | CharSequence currentEditTextHint = getEditText().getHint(); 45 | 46 | if (currentEditTextHint != null && currentEditTextHint.length() > 0) { 47 | mHint = currentEditTextHint; 48 | } 49 | setHint(mHint); 50 | mIsHintSet = true; 51 | } 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/DeleteNotificationService.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.app.IntentService; 4 | import android.content.Intent; 5 | import android.content.SharedPreferences; 6 | 7 | import java.util.ArrayList; 8 | import java.util.UUID; 9 | 10 | public class DeleteNotificationService extends IntentService { 11 | 12 | private StoreRetrieveData storeRetrieveData; 13 | private ArrayList mToDoItems; 14 | private ToDoItem mItem; 15 | 16 | public DeleteNotificationService(){ 17 | super("DeleteNotificationService"); 18 | } 19 | 20 | @Override 21 | protected void onHandleIntent(Intent intent) { 22 | storeRetrieveData = new StoreRetrieveData(this, MainActivity.FILENAME); 23 | UUID todoID = (UUID)intent.getSerializableExtra(TodoNotificationService.TODOUUID); 24 | 25 | mToDoItems = loadData(); 26 | if(mToDoItems!=null){ 27 | for(ToDoItem item : mToDoItems){ 28 | if(item.getIdentifier().equals(todoID)){ 29 | mItem = item; 30 | break; 31 | } 32 | } 33 | 34 | if(mItem!=null){ 35 | mToDoItems.remove(mItem); 36 | dataChanged(); 37 | saveData(); 38 | } 39 | 40 | } 41 | 42 | } 43 | 44 | private void dataChanged(){ 45 | SharedPreferences sharedPreferences = getSharedPreferences(MainActivity.SHARED_PREF_DATA_SET_CHANGED, MODE_PRIVATE); 46 | SharedPreferences.Editor editor = sharedPreferences.edit(); 47 | editor.putBoolean(MainActivity.CHANGE_OCCURED, true); 48 | editor.apply(); 49 | } 50 | 51 | private void saveData(){ 52 | try{ 53 | storeRetrieveData.saveToFile(mToDoItems); 54 | } 55 | catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | 60 | @Override 61 | public void onDestroy() { 62 | super.onDestroy(); 63 | saveData(); 64 | } 65 | 66 | private ArrayList loadData(){ 67 | try{ 68 | return storeRetrieveData.loadFromFile(); 69 | } 70 | catch (Exception e){ 71 | e.printStackTrace(); 72 | } 73 | 74 | return null; 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/ItemTouchHelperClass.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.support.v7.widget.helper.ItemTouchHelper; 5 | 6 | public class ItemTouchHelperClass extends ItemTouchHelper.Callback{ 7 | private ItemTouchHelperAdapter adapter; 8 | public interface ItemTouchHelperAdapter{ 9 | void onItemMoved(int fromPosition, int toPosition); 10 | void onItemRemoved(int position); 11 | } 12 | 13 | public ItemTouchHelperClass(ItemTouchHelperAdapter ad){ 14 | adapter = ad; 15 | } 16 | 17 | @Override 18 | public boolean isLongPressDragEnabled() { 19 | return true; 20 | } 21 | 22 | @Override 23 | public boolean isItemViewSwipeEnabled() { 24 | return true; 25 | } 26 | 27 | @Override 28 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 29 | int upFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; 30 | int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; 31 | 32 | return makeMovementFlags(upFlags, swipeFlags); 33 | } 34 | 35 | @Override 36 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 37 | adapter.onItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition()); 38 | return true; 39 | } 40 | 41 | @Override 42 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 43 | adapter.onItemRemoved(viewHolder.getAdapterPosition()); 44 | 45 | } 46 | 47 | // @SuppressWarnings("deprecation") 48 | // @Override 49 | // public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 50 | // if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){ 51 | // View itemView = viewHolder.itemView; 52 | // Paint p = new Paint(); 53 | // 54 | // 55 | // MainActivity.BasicListAdapter.ViewHolder vh= (MainActivity.BasicListAdapter.ViewHolder)viewHolder; 56 | // p.setColor(recyclerView.getResources().getColor(R.color.primary_light)); 57 | // 58 | // if(dX > 0){ 59 | // c.drawRect((float)itemView.getLeft(), (float)itemView.getTop(), dX, (float)itemView.getBottom(), p); 60 | // String toWrite = "Left"+itemView.getLeft()+" Top "+itemView.getTop()+" Right "+dX+" Bottom "+itemView.getBottom(); 61 | //// Log.d("OskarSchindler", toWrite); 62 | // } 63 | // else{ 64 | // String toWrite = "Left"+(itemView.getLeft()+dX)+" Top "+itemView.getTop()+" Right "+dX+" Bottom "+itemView.getBottom(); 65 | //// Log.d("OskarSchindler", toWrite); 66 | // c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom(), p); 67 | // } 68 | // super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 69 | // } 70 | // } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/PreferenceKeys.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.content.res.Resources; 4 | 5 | /** 6 | * Created by avjindersinghsekhon on 9/21/15. 7 | */ 8 | public class PreferenceKeys { 9 | final String night_mode_pref_key; 10 | 11 | public PreferenceKeys(Resources resources){ 12 | night_mode_pref_key = resources.getString(R.string.night_mode_pref_key); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/RecyclerViewEmptySupport.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | 8 | public class RecyclerViewEmptySupport extends RecyclerView { 9 | private View emptyView; 10 | 11 | private AdapterDataObserver observer = new AdapterDataObserver() { 12 | @Override 13 | public void onChanged() { 14 | showEmptyView(); 15 | } 16 | 17 | @Override 18 | public void onItemRangeInserted(int positionStart, int itemCount) { 19 | super.onItemRangeInserted(positionStart, itemCount); 20 | showEmptyView(); 21 | } 22 | 23 | @Override 24 | public void onItemRangeRemoved(int positionStart, int itemCount) { 25 | super.onItemRangeRemoved(positionStart, itemCount); 26 | showEmptyView(); 27 | } 28 | }; 29 | 30 | 31 | 32 | public RecyclerViewEmptySupport(Context context) { 33 | super(context); 34 | } 35 | 36 | public void showEmptyView(){ 37 | 38 | Adapter adapter = getAdapter(); 39 | if(adapter!=null && emptyView!=null){ 40 | if(adapter.getItemCount()==0){ 41 | emptyView.setVisibility(VISIBLE); 42 | RecyclerViewEmptySupport.this.setVisibility(GONE); 43 | } 44 | else{ 45 | emptyView.setVisibility(GONE); 46 | RecyclerViewEmptySupport.this.setVisibility(VISIBLE); 47 | } 48 | } 49 | 50 | } 51 | 52 | public RecyclerViewEmptySupport(Context context, AttributeSet attrs) { 53 | super(context, attrs); 54 | } 55 | 56 | public RecyclerViewEmptySupport(Context context, AttributeSet attrs, int defStyle) { 57 | super(context, attrs, defStyle); 58 | } 59 | 60 | @Override 61 | public void setAdapter(Adapter adapter) { 62 | super.setAdapter(adapter); 63 | if(adapter!=null){ 64 | adapter.registerAdapterDataObserver(observer); 65 | observer.onChanged(); 66 | } 67 | } 68 | 69 | public void setEmptyView(View v){ 70 | emptyView = v; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/ReminderActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.content.Intent; 4 | import android.content.SharedPreferences; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.util.Log; 10 | import android.view.Menu; 11 | import android.view.MenuItem; 12 | import android.view.View; 13 | import android.widget.ArrayAdapter; 14 | import android.widget.Button; 15 | import android.widget.TextView; 16 | 17 | import org.json.JSONException; 18 | 19 | import java.io.IOException; 20 | import java.util.ArrayList; 21 | import java.util.Calendar; 22 | import java.util.Date; 23 | import java.util.UUID; 24 | 25 | import fr.ganfra.materialspinner.MaterialSpinner; 26 | 27 | public class ReminderActivity extends AppCompatActivity{ 28 | private TextView mtoDoTextTextView; 29 | private Button mRemoveToDoButton; 30 | private MaterialSpinner mSnoozeSpinner; 31 | private String[] snoozeOptionsArray; 32 | private StoreRetrieveData storeRetrieveData; 33 | private ArrayList mToDoItems; 34 | private ToDoItem mItem; 35 | public static final String EXIT = "com.avjindersekhon.exit"; 36 | private TextView mSnoozeTextView; 37 | String theme; 38 | AnalyticsApplication app; 39 | 40 | @Override 41 | protected void onCreate(final Bundle savedInstanceState) { 42 | app = (AnalyticsApplication)getApplication(); 43 | app.send(this); 44 | 45 | theme = getSharedPreferences(MainActivity.THEME_PREFERENCES, MODE_PRIVATE).getString(MainActivity.THEME_SAVED, MainActivity.LIGHTTHEME); 46 | if(theme.equals(MainActivity.LIGHTTHEME)){ 47 | setTheme(R.style.CustomStyle_LightTheme); 48 | } 49 | else{ 50 | setTheme(R.style.CustomStyle_DarkTheme); 51 | } 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.reminder_layout); 54 | storeRetrieveData = new StoreRetrieveData(this, MainActivity.FILENAME); 55 | mToDoItems = MainActivity.getLocallyStoredData(storeRetrieveData); 56 | 57 | setSupportActionBar((Toolbar)findViewById(R.id.toolbar)); 58 | 59 | 60 | 61 | Intent i = getIntent(); 62 | UUID id = (UUID)i.getSerializableExtra(TodoNotificationService.TODOUUID); 63 | mItem = null; 64 | for(ToDoItem toDoItem : mToDoItems){ 65 | if (toDoItem.getIdentifier().equals(id)){ 66 | mItem = toDoItem; 67 | break; 68 | } 69 | } 70 | 71 | snoozeOptionsArray = getResources().getStringArray(R.array.snooze_options); 72 | 73 | mRemoveToDoButton = (Button)findViewById(R.id.toDoReminderRemoveButton); 74 | mtoDoTextTextView = (TextView)findViewById(R.id.toDoReminderTextViewBody); 75 | mSnoozeTextView = (TextView)findViewById(R.id.reminderViewSnoozeTextView); 76 | mSnoozeSpinner = (MaterialSpinner)findViewById(R.id.todoReminderSnoozeSpinner); 77 | 78 | // mtoDoTextTextView.setBackgroundColor(item.getTodoColor()); 79 | mtoDoTextTextView.setText(mItem.getToDoText()); 80 | 81 | if(theme.equals(MainActivity.LIGHTTHEME)){ 82 | mSnoozeTextView.setTextColor(getResources().getColor(R.color.secondary_text)); 83 | } 84 | else{ 85 | mSnoozeTextView.setTextColor(Color.WHITE); 86 | mSnoozeTextView.setCompoundDrawablesWithIntrinsicBounds( 87 | R.drawable.ic_snooze_white_24dp,0,0,0 88 | ); 89 | } 90 | 91 | mRemoveToDoButton.setOnClickListener(new View.OnClickListener() { 92 | @Override 93 | public void onClick(View v) { 94 | app.send(this, "Action", "Todo Removed from Reminder Activity"); 95 | mToDoItems.remove(mItem); 96 | changeOccurred(); 97 | saveData(); 98 | closeApp(); 99 | // finish(); 100 | } 101 | }); 102 | 103 | 104 | // ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, snoozeOptionsArray); 105 | ArrayAdapter adapter = new ArrayAdapter<>(this, R.layout.spinner_text_view, snoozeOptionsArray); 106 | // adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 107 | adapter.setDropDownViewResource(R.layout.spinner_dropdown_item); 108 | 109 | mSnoozeSpinner.setAdapter(adapter); 110 | // mSnoozeSpinner.setSelection(0); 111 | 112 | } 113 | 114 | private void closeApp(){ 115 | Intent i = new Intent(ReminderActivity.this, MainActivity.class); 116 | i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 117 | // i.putExtra(EXIT, true); 118 | SharedPreferences sharedPreferences = getSharedPreferences(MainActivity.SHARED_PREF_DATA_SET_CHANGED, MODE_PRIVATE); 119 | SharedPreferences.Editor editor = sharedPreferences.edit(); 120 | editor.putBoolean(EXIT, true); 121 | editor.apply(); 122 | startActivity(i); 123 | 124 | } 125 | 126 | @Override 127 | public boolean onCreateOptionsMenu(Menu menu) { 128 | getMenuInflater().inflate(R.menu.menu_reminder, menu); 129 | return true; 130 | } 131 | private void changeOccurred(){ 132 | SharedPreferences sharedPreferences = getSharedPreferences(MainActivity.SHARED_PREF_DATA_SET_CHANGED, MODE_PRIVATE); 133 | SharedPreferences.Editor editor = sharedPreferences.edit(); 134 | editor.putBoolean(MainActivity.CHANGE_OCCURED, true); 135 | // editor.commit(); 136 | editor.apply(); 137 | } 138 | 139 | private Date addTimeToDate(int mins){ 140 | app.send(this, "Action", "Snoozed", "For "+mins+" minutes"); 141 | Date date = new Date(); 142 | Calendar calendar = Calendar.getInstance(); 143 | calendar.setTime(date); 144 | calendar.add(Calendar.MINUTE, mins); 145 | return calendar.getTime(); 146 | } 147 | private int valueFromSpinner(){ 148 | switch (mSnoozeSpinner.getSelectedItemPosition()){ 149 | case 0: 150 | return 10; 151 | case 1: 152 | return 30; 153 | case 2: 154 | return 60; 155 | default: 156 | return 0; 157 | } 158 | } 159 | 160 | @Override 161 | public boolean onOptionsItemSelected(MenuItem item) { 162 | switch (item.getItemId()){ 163 | case R.id.toDoReminderDoneMenuItem: 164 | Date date = addTimeToDate(valueFromSpinner()); 165 | mItem.setToDoDate(date); 166 | mItem.setHasReminder(true); 167 | Log.d("OskarSchindler", "Date Changed to: " + date); 168 | changeOccurred(); 169 | saveData(); 170 | closeApp(); 171 | //foo 172 | return true; 173 | default: 174 | return super.onOptionsItemSelected(item); 175 | } 176 | } 177 | 178 | // @Override 179 | // protected void onPause() { 180 | // super.onPause(); 181 | // try{ 182 | // storeRetrieveData.saveToFile(mToDoItems); 183 | // } 184 | // catch (JSONException | IOException e){ 185 | // e.printStackTrace(); 186 | // } 187 | // } 188 | 189 | private void saveData(){ 190 | try{ 191 | storeRetrieveData.saveToFile(mToDoItems); 192 | } 193 | catch (JSONException | IOException e){ 194 | e.printStackTrace(); 195 | } 196 | } 197 | 198 | @Override 199 | protected void onDestroy() { 200 | super.onDestroy(); 201 | // try{ 202 | // storeRetrieveData.saveToFile(mToDoItems); 203 | // } 204 | // catch (JSONException | IOException e){ 205 | // e.printStackTrace(); 206 | // } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/ScrollingFABBehaviour.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.content.Context; 4 | import android.support.design.widget.CoordinatorLayout; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.design.widget.Snackbar; 7 | import android.support.v7.widget.Toolbar; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | public class ScrollingFABBehaviour extends CoordinatorLayout.Behavior { 12 | private int toolbarHeight; 13 | private static boolean scrolledUp = false; 14 | private static boolean scrolledDown = false; 15 | 16 | public ScrollingFABBehaviour(Context context, AttributeSet attributeSet){ 17 | super(context, attributeSet); 18 | this.toolbarHeight = Utils.getToolbarHeight(context); 19 | } 20 | 21 | 22 | @Override 23 | public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) { 24 | return (dependency instanceof Snackbar.SnackbarLayout) || (dependency instanceof Toolbar); 25 | // return (dependency instanceof Snackbar.SnackbarLayout); 26 | } 27 | 28 | @Override 29 | public boolean onDependentViewChanged(CoordinatorLayout parent, final FloatingActionButton child, View dependency) { 30 | if(dependency instanceof Snackbar.SnackbarLayout){ 31 | float finalVal = (float)parent.getHeight() - dependency.getY(); 32 | child.setTranslationY(-finalVal); 33 | } 34 | // 35 | // if(dependency instanceof RecyclerView){ 36 | // RecyclerView view = (RecyclerView)dependency; 37 | // CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)child.getLayoutParams(); 38 | // int fabBottomMargin = lp.bottomMargin; 39 | // final int distanceToScroll = child.getHeight() + fabBottomMargin; 40 | // 41 | // final RecyclerView.LayoutManager rlp = (RecyclerView.LayoutManager)view.getLayoutManager(); 42 | // Log.d("OskarSchindler", "Height: "+rlp.getHeight()); 43 | // 44 | // 45 | // 46 | // } 47 | if(dependency instanceof Toolbar){ 48 | CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)child.getLayoutParams(); 49 | int fabBottomMargin = lp.bottomMargin; 50 | int distanceToScroll = child.getHeight() + fabBottomMargin; 51 | float finalVal = dependency.getY()/(float)toolbarHeight; 52 | float distFinal = -distanceToScroll * finalVal; 53 | child.setTranslationY(distFinal); 54 | } 55 | 56 | 57 | return true; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.app.FragmentManager; 4 | import android.graphics.Color; 5 | import android.graphics.PorterDuff; 6 | import android.graphics.drawable.Drawable; 7 | import android.os.Bundle; 8 | import android.support.v4.app.NavUtils; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.Toolbar; 11 | import android.view.MenuItem; 12 | 13 | public class SettingsActivity extends AppCompatActivity{ 14 | 15 | AnalyticsApplication app; 16 | @Override 17 | protected void onResume() { 18 | super.onResume(); 19 | app.send(this); 20 | } 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | 25 | app = (AnalyticsApplication)getApplication(); 26 | String theme = getSharedPreferences(MainActivity.THEME_PREFERENCES, MODE_PRIVATE).getString(MainActivity.THEME_SAVED, MainActivity.LIGHTTHEME); 27 | if(theme.equals(MainActivity.LIGHTTHEME)){ 28 | setTheme(R.style.CustomStyle_LightTheme); 29 | } 30 | else{ 31 | setTheme(R.style.CustomStyle_DarkTheme); 32 | } 33 | super.onCreate(savedInstanceState); 34 | // getSupportActionBar().setDisplayHomeAsUpEnabled(true); 35 | setContentView(R.layout.activity_settings); 36 | Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); 37 | setSupportActionBar(toolbar); 38 | 39 | final Drawable backArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha); 40 | if(backArrow!=null){ 41 | backArrow.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP); 42 | 43 | } 44 | 45 | if(getSupportActionBar()!=null){ 46 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 47 | getSupportActionBar().setHomeAsUpIndicator(backArrow); 48 | } 49 | 50 | FragmentManager fm= getFragmentManager(); 51 | fm.beginTransaction().replace(R.id.mycontent, new SettingsFragment()).commit(); 52 | } 53 | 54 | @Override 55 | public boolean onOptionsItemSelected(MenuItem item) { 56 | switch(item.getItemId()){ 57 | case android.R.id.home: 58 | if(NavUtils.getParentActivityName(this)!=null){ 59 | NavUtils.navigateUpFromSameTask(this); 60 | } 61 | return true; 62 | default: 63 | return super.onOptionsItemSelected(item); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/SettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.os.Bundle; 6 | import android.preference.CheckBoxPreference; 7 | import android.preference.PreferenceFragment; 8 | 9 | public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener{ 10 | AnalyticsApplication app; 11 | 12 | 13 | @Override 14 | public void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | addPreferencesFromResource(R.xml.preferences_layout); 17 | app = (AnalyticsApplication) getActivity().getApplication(); 18 | } 19 | 20 | @Override 21 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 22 | PreferenceKeys preferenceKeys = new PreferenceKeys(getResources()); 23 | if(key.equals(preferenceKeys.night_mode_pref_key)){ 24 | SharedPreferences themePreferences = getActivity().getSharedPreferences(MainActivity.THEME_PREFERENCES, Context.MODE_PRIVATE); 25 | SharedPreferences.Editor themeEditor = themePreferences.edit(); 26 | //We tell our MainLayout to recreate itself because mode has changed 27 | themeEditor.putBoolean(MainActivity.RECREATE_ACTIVITY, true); 28 | 29 | CheckBoxPreference checkBoxPreference = (CheckBoxPreference)findPreference(preferenceKeys.night_mode_pref_key); 30 | if(checkBoxPreference.isChecked()){ 31 | //Comment out this line if not using Google Analytics 32 | app.send(this, "Settings", "Night Mode used"); 33 | themeEditor.putString(MainActivity.THEME_SAVED, MainActivity.DARKTHEME); 34 | } 35 | else{ 36 | themeEditor.putString(MainActivity.THEME_SAVED, MainActivity.LIGHTTHEME); 37 | } 38 | themeEditor.apply(); 39 | 40 | getActivity().recreate(); 41 | } 42 | } 43 | 44 | @Override 45 | public void onResume() { 46 | super.onResume(); 47 | getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); 48 | } 49 | 50 | @Override 51 | public void onPause() { 52 | super.onPause(); 53 | getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/avjindersinghsekhon/minimaltodo/StoreRetrieveData.java: -------------------------------------------------------------------------------- 1 | package com.example.avjindersinghsekhon.minimaltodo; 2 | 3 | import android.content.Context; 4 | 5 | import org.json.JSONArray; 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | import org.json.JSONTokener; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.FileInputStream; 12 | import java.io.FileNotFoundException; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.io.InputStreamReader; 16 | import java.io.OutputStreamWriter; 17 | import java.util.ArrayList; 18 | 19 | public class StoreRetrieveData { 20 | private Context mContext; 21 | private String mFileName; 22 | 23 | public StoreRetrieveData(Context context, String filename){ 24 | mContext = context; 25 | mFileName = filename; 26 | } 27 | 28 | public static JSONArray toJSONArray(ArrayList items) throws JSONException{ 29 | JSONArray jsonArray = new JSONArray(); 30 | for(ToDoItem item : items){ 31 | JSONObject jsonObject = item.toJSON(); 32 | jsonArray.put(jsonObject); 33 | } 34 | return jsonArray; 35 | } 36 | 37 | public void saveToFile(ArrayList items) throws JSONException, IOException{ 38 | FileOutputStream fileOutputStream; 39 | OutputStreamWriter outputStreamWriter; 40 | fileOutputStream = mContext.openFileOutput(mFileName, Context.MODE_PRIVATE); 41 | outputStreamWriter = new OutputStreamWriter(fileOutputStream); 42 | outputStreamWriter.write(toJSONArray(items).toString()); 43 | outputStreamWriter.close(); 44 | fileOutputStream.close(); 45 | } 46 | 47 | public ArrayList loadFromFile() throws IOException, JSONException{ 48 | ArrayList items = new ArrayList<>(); 49 | BufferedReader bufferedReader = null; 50 | FileInputStream fileInputStream = null; 51 | try { 52 | fileInputStream = mContext.openFileInput(mFileName); 53 | StringBuilder builder = new StringBuilder(); 54 | String line; 55 | bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream)); 56 | while((line = bufferedReader.readLine())!=null){ 57 | builder.append(line); 58 | } 59 | 60 | JSONArray jsonArray = (JSONArray)new JSONTokener(builder.toString()).nextValue(); 61 | for(int i =0; i 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dropdown_text_background_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dropdown_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/about_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 16 | 17 | 23 | 30 | 31 | 38 | 39 | 46 | 47 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_to_do.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 15 | 16 | 20 | 21 | 29 | 30 | 31 | 38 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 70 | 71 | 79 | 80 | 93 | 94 | 102 | 103 | 104 | 105 | 115 | 116 | 122 | 123 |