From c685d8f3f19983660ac7173b16f1e9cb76acb7d7 Mon Sep 17 00:00:00 2001 From: Aleks Haecky Date: Wed, 15 May 2019 11:22:27 -0700 Subject: [PATCH] RecyclerView apps added. Change-Id: If081193ea949419364bdb2dad5b3375493c1592a --- RecyclerViewClickHandler/README.md | 55 ++++ RecyclerViewClickHandler/app/.gitignore | 1 + RecyclerViewClickHandler/app/build.gradle | 80 ++++++ .../app/proguard-rules.pro | 21 ++ .../app/src/main/AndroidManifest.xml | 24 ++ .../main/ic_launcher_sleep_tracker-web.png | Bin 0 -> 29407 bytes .../trackmysleepquality/MainActivity.kt | 30 ++ .../android/trackmysleepquality/Util.kt | 156 +++++++++++ .../database/SleepDatabase.kt | 107 +++++++ .../database/SleepDatabaseDao.kt | 80 ++++++ .../database/SleepNight.kt | 38 +++ .../sleepdetail/SleepDetailFragment.kt | 84 ++++++ .../sleepdetail/SleepDetailViewModel.kt | 97 +++++++ .../SleepDetailViewModelFactory.kt | 39 +++ .../sleepquality/SleepQualityFragment.kt | 85 ++++++ .../sleepquality/SleepQualityViewModel.kt | 112 ++++++++ .../SleepQualityViewModelFactory.kt | 39 +++ .../sleeptracker/BindingUtils.kt | 59 ++++ .../sleeptracker/SleepNightAdapter.kt | 70 +++++ .../sleeptracker/SleepTrackerFragment.kt | 140 ++++++++++ .../sleeptracker/SleepTrackerViewModel.kt | 263 ++++++++++++++++++ .../SleepTrackerViewModelFactory.kt | 40 +++ .../app/src/main/res/anim/slide_in_right.xml | 25 ++ .../ic_launcher_sleep_tracker_background.xml | 55 ++++ .../ic_launcher_sleep_tracker_foreground.xml | 77 +++++ .../app/src/main/res/drawable/ic_sleep_0.xml | 28 ++ .../app/src/main/res/drawable/ic_sleep_1.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_2.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_3.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_4.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_5.xml | 28 ++ .../src/main/res/drawable/ic_sleep_active.xml | 77 +++++ .../app/src/main/res/font/roboto.xml | 7 + .../app/src/main/res/layout/activity_main.xml | 32 +++ .../main/res/layout/fragment_sleep_detail.xml | 84 ++++++ .../res/layout/fragment_sleep_quality.xml | 130 +++++++++ .../res/layout/fragment_sleep_tracker.xml | 98 +++++++ .../main/res/layout/list_item_sleep_night.xml | 65 +++++ .../layout/list_item_sleep_night_linear.xml | 71 +++++ .../src/main/res/layout/text_item_view.xml | 22 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 ++ .../ic_launcher_sleep_tracker.xml | 21 ++ .../ic_launcher_sleep_tracker_round.xml | 21 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../mipmap-hdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 3283 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 4111 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../mipmap-mdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 2194 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 2623 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 4447 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 5977 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 6657 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 9490 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 8813 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 13582 bytes .../src/main/res/navigation/navigation.xml | 75 +++++ .../app/src/main/res/values/colors.xml | 26 ++ .../app/src/main/res/values/dimens.xml | 22 ++ .../app/src/main/res/values/font_certs.xml | 32 +++ .../src/main/res/values/preloaded_fonts.xml | 21 ++ .../app/src/main/res/values/strings.xml | 61 ++++ .../app/src/main/res/values/styles.xml | 34 +++ RecyclerViewClickHandler/build.gradle | 55 ++++ RecyclerViewClickHandler/gradle.properties | 15 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + RecyclerViewClickHandler/gradlew | 172 ++++++++++++ RecyclerViewClickHandler/gradlew.bat | 84 ++++++ RecyclerViewClickHandler/settings.gradle | 1 + RecyclerViewDiffUtilDataBinding/README.md | 55 ++++ .../app/.gitignore | 1 + .../app/build.gradle | 80 ++++++ .../app/proguard-rules.pro | 21 ++ .../app/src/main/AndroidManifest.xml | 24 ++ .../main/ic_launcher_sleep_tracker-web.png | Bin 0 -> 29407 bytes .../trackmysleepquality/MainActivity.kt | 30 ++ .../android/trackmysleepquality/Util.kt | 156 +++++++++++ .../database/SleepDatabase.kt | 107 +++++++ .../database/SleepDatabaseDao.kt | 74 +++++ .../database/SleepNight.kt | 38 +++ .../sleepquality/SleepQualityFragment.kt | 85 ++++++ .../sleepquality/SleepQualityViewModel.kt | 113 ++++++++ .../SleepQualityViewModelFactory.kt | 39 +++ .../sleeptracker/BindingUtils.kt | 53 ++++ .../sleeptracker/SleepNightAdapter.kt | 71 +++++ .../sleeptracker/SleepTrackerFragment.kt | 120 ++++++++ .../sleeptracker/SleepTrackerViewModel.kt | 249 +++++++++++++++++ .../SleepTrackerViewModelFactory.kt | 40 +++ .../app/src/main/res/anim/slide_in_right.xml | 25 ++ .../ic_launcher_sleep_tracker_background.xml | 55 ++++ .../ic_launcher_sleep_tracker_foreground.xml | 77 +++++ .../app/src/main/res/drawable/ic_sleep_0.xml | 28 ++ .../app/src/main/res/drawable/ic_sleep_1.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_2.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_3.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_4.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_5.xml | 28 ++ .../src/main/res/drawable/ic_sleep_active.xml | 77 +++++ .../app/src/main/res/font/roboto.xml | 7 + .../app/src/main/res/layout/activity_main.xml | 32 +++ .../res/layout/fragment_sleep_quality.xml | 130 +++++++++ .../res/layout/fragment_sleep_tracker.xml | 99 +++++++ .../main/res/layout/list_item_sleep_night.xml | 71 +++++ .../src/main/res/layout/text_item_view.xml | 22 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 ++ .../ic_launcher_sleep_tracker.xml | 21 ++ .../ic_launcher_sleep_tracker_round.xml | 21 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../mipmap-hdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 3283 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 4111 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../mipmap-mdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 2194 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 2623 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 4447 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 5977 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 6657 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 9490 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 8813 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 13582 bytes .../src/main/res/navigation/navigation.xml | 54 ++++ .../app/src/main/res/values/colors.xml | 26 ++ .../app/src/main/res/values/dimens.xml | 22 ++ .../app/src/main/res/values/font_certs.xml | 32 +++ .../src/main/res/values/preloaded_fonts.xml | 21 ++ .../app/src/main/res/values/strings.xml | 61 ++++ .../app/src/main/res/values/styles.xml | 34 +++ RecyclerViewDiffUtilDataBinding/build.gradle | 55 ++++ .../gradle.properties | 15 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + RecyclerViewDiffUtilDataBinding/gradlew | 172 ++++++++++++ RecyclerViewDiffUtilDataBinding/gradlew.bat | 84 ++++++ .../settings.gradle | 1 + RecyclerViewFundamentals/README.md | 53 ++++ RecyclerViewFundamentals/app/.gitignore | 1 + RecyclerViewFundamentals/app/build.gradle | 80 ++++++ .../app/proguard-rules.pro | 21 ++ .../app/src/main/AndroidManifest.xml | 24 ++ .../main/ic_launcher_sleep_tracker-web.png | Bin 0 -> 29407 bytes .../trackmysleepquality/MainActivity.kt | 30 ++ .../android/trackmysleepquality/Util.kt | 156 +++++++++++ .../database/SleepDatabase.kt | 107 +++++++ .../database/SleepDatabaseDao.kt | 74 +++++ .../database/SleepNight.kt | 38 +++ .../sleepquality/SleepQualityFragment.kt | 85 ++++++ .../sleepquality/SleepQualityViewModel.kt | 113 ++++++++ .../SleepQualityViewModelFactory.kt | 39 +++ .../sleeptracker/SleepNightAdapter.kt | 80 ++++++ .../sleeptracker/SleepTrackerFragment.kt | 120 ++++++++ .../sleeptracker/SleepTrackerViewModel.kt | 249 +++++++++++++++++ .../SleepTrackerViewModelFactory.kt | 40 +++ .../app/src/main/res/anim/slide_in_right.xml | 25 ++ .../ic_launcher_sleep_tracker_background.xml | 55 ++++ .../ic_launcher_sleep_tracker_foreground.xml | 77 +++++ .../app/src/main/res/drawable/ic_sleep_0.xml | 28 ++ .../app/src/main/res/drawable/ic_sleep_1.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_2.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_3.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_4.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_5.xml | 28 ++ .../src/main/res/drawable/ic_sleep_active.xml | 77 +++++ .../app/src/main/res/font/roboto.xml | 7 + .../app/src/main/res/layout/activity_main.xml | 32 +++ .../res/layout/fragment_sleep_quality.xml | 130 +++++++++ .../res/layout/fragment_sleep_tracker.xml | 99 +++++++ .../main/res/layout/list_item_sleep_night.xml | 58 ++++ .../src/main/res/layout/text_item_view.xml | 22 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 ++ .../ic_launcher_sleep_tracker.xml | 21 ++ .../ic_launcher_sleep_tracker_round.xml | 21 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../mipmap-hdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 3283 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 4111 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../mipmap-mdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 2194 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 2623 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 4447 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 5977 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 6657 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 9490 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 8813 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 13582 bytes .../src/main/res/navigation/navigation.xml | 54 ++++ .../app/src/main/res/values/colors.xml | 26 ++ .../app/src/main/res/values/dimens.xml | 22 ++ .../app/src/main/res/values/font_certs.xml | 32 +++ .../src/main/res/values/preloaded_fonts.xml | 21 ++ .../app/src/main/res/values/strings.xml | 61 ++++ .../app/src/main/res/values/styles.xml | 34 +++ RecyclerViewFundamentals/build.gradle | 55 ++++ RecyclerViewFundamentals/gradle.properties | 15 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + RecyclerViewFundamentals/gradlew | 172 ++++++++++++ RecyclerViewFundamentals/gradlew.bat | 84 ++++++ RecyclerViewFundamentals/settings.gradle | 1 + RecyclerViewGridLayout/README.md | 54 ++++ RecyclerViewGridLayout/app/.gitignore | 1 + RecyclerViewGridLayout/app/build.gradle | 80 ++++++ RecyclerViewGridLayout/app/proguard-rules.pro | 21 ++ .../app/src/main/AndroidManifest.xml | 24 ++ .../main/ic_launcher_sleep_tracker-web.png | Bin 0 -> 29407 bytes .../trackmysleepquality/MainActivity.kt | 30 ++ .../android/trackmysleepquality/Util.kt | 156 +++++++++++ .../database/SleepDatabase.kt | 107 +++++++ .../database/SleepDatabaseDao.kt | 74 +++++ .../database/SleepNight.kt | 38 +++ .../sleepquality/SleepQualityFragment.kt | 85 ++++++ .../sleepquality/SleepQualityViewModel.kt | 113 ++++++++ .../SleepQualityViewModelFactory.kt | 39 +++ .../sleeptracker/BindingUtils.kt | 53 ++++ .../sleeptracker/SleepNightAdapter.kt | 71 +++++ .../sleeptracker/SleepTrackerFragment.kt | 126 +++++++++ .../sleeptracker/SleepTrackerViewModel.kt | 249 +++++++++++++++++ .../SleepTrackerViewModelFactory.kt | 40 +++ .../app/src/main/res/anim/slide_in_right.xml | 25 ++ .../ic_launcher_sleep_tracker_background.xml | 55 ++++ .../ic_launcher_sleep_tracker_foreground.xml | 77 +++++ .../app/src/main/res/drawable/ic_sleep_0.xml | 28 ++ .../app/src/main/res/drawable/ic_sleep_1.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_2.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_3.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_4.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_5.xml | 28 ++ .../src/main/res/drawable/ic_sleep_active.xml | 77 +++++ .../app/src/main/res/font/roboto.xml | 7 + .../app/src/main/res/layout/activity_main.xml | 32 +++ .../res/layout/fragment_sleep_quality.xml | 130 +++++++++ .../res/layout/fragment_sleep_tracker.xml | 98 +++++++ .../main/res/layout/list_item_sleep_night.xml | 60 ++++ .../layout/list_item_sleep_night_linear.xml | 71 +++++ .../src/main/res/layout/text_item_view.xml | 22 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 ++ .../ic_launcher_sleep_tracker.xml | 21 ++ .../ic_launcher_sleep_tracker_round.xml | 21 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../mipmap-hdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 3283 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 4111 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../mipmap-mdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 2194 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 2623 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 4447 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 5977 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 6657 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 9490 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 8813 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 13582 bytes .../src/main/res/navigation/navigation.xml | 54 ++++ .../app/src/main/res/values/colors.xml | 26 ++ .../app/src/main/res/values/dimens.xml | 22 ++ .../app/src/main/res/values/font_certs.xml | 32 +++ .../src/main/res/values/preloaded_fonts.xml | 21 ++ .../app/src/main/res/values/strings.xml | 60 ++++ .../app/src/main/res/values/styles.xml | 34 +++ RecyclerViewGridLayout/build.gradle | 55 ++++ RecyclerViewGridLayout/gradle.properties | 15 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + RecyclerViewGridLayout/gradlew | 172 ++++++++++++ RecyclerViewGridLayout/gradlew.bat | 84 ++++++ RecyclerViewGridLayout/settings.gradle | 1 + RecyclerViewHeaders/README.md | 56 ++++ RecyclerViewHeaders/app/.gitignore | 1 + RecyclerViewHeaders/app/build.gradle | 80 ++++++ RecyclerViewHeaders/app/proguard-rules.pro | 21 ++ .../app/src/main/AndroidManifest.xml | 24 ++ .../main/ic_launcher_sleep_tracker-web.png | Bin 0 -> 29407 bytes .../trackmysleepquality/MainActivity.kt | 30 ++ .../android/trackmysleepquality/Util.kt | 156 +++++++++++ .../database/SleepDatabase.kt | 107 +++++++ .../database/SleepDatabaseDao.kt | 80 ++++++ .../database/SleepNight.kt | 38 +++ .../sleepdetail/SleepDetailFragment.kt | 82 ++++++ .../sleepdetail/SleepDetailViewModel.kt | 94 +++++++ .../SleepDetailViewModelFactory.kt | 38 +++ .../sleepquality/SleepQualityFragment.kt | 85 ++++++ .../sleepquality/SleepQualityViewModel.kt | 112 ++++++++ .../SleepQualityViewModelFactory.kt | 38 +++ .../sleeptracker/BindingUtils.kt | 59 ++++ .../sleeptracker/SleepNightAdapter.kt | 134 +++++++++ .../sleeptracker/SleepTrackerFragment.kt | 148 ++++++++++ .../sleeptracker/SleepTrackerViewModel.kt | 263 ++++++++++++++++++ .../SleepTrackerViewModelFactory.kt | 39 +++ .../app/src/main/res/anim/slide_in_right.xml | 25 ++ .../ic_launcher_sleep_tracker_background.xml | 55 ++++ .../ic_launcher_sleep_tracker_foreground.xml | 77 +++++ .../app/src/main/res/drawable/ic_sleep_0.xml | 28 ++ .../app/src/main/res/drawable/ic_sleep_1.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_2.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_3.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_4.xml | 30 ++ .../app/src/main/res/drawable/ic_sleep_5.xml | 28 ++ .../src/main/res/drawable/ic_sleep_active.xml | 77 +++++ .../app/src/main/res/font/roboto.xml | 7 + .../app/src/main/res/layout/activity_main.xml | 32 +++ .../main/res/layout/fragment_sleep_detail.xml | 83 ++++++ .../res/layout/fragment_sleep_quality.xml | 130 +++++++++ .../res/layout/fragment_sleep_tracker.xml | 98 +++++++ .../app/src/main/res/layout/header.xml | 29 ++ .../main/res/layout/list_item_sleep_night.xml | 64 +++++ .../layout/list_item_sleep_night_linear.xml | 70 +++++ .../src/main/res/layout/text_item_view.xml | 21 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 ++ .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 ++ .../ic_launcher_sleep_tracker.xml | 21 ++ .../ic_launcher_sleep_tracker_round.xml | 21 ++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../mipmap-hdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 3283 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 4111 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../mipmap-mdpi/ic_launcher_sleep_tracker.png | Bin 0 -> 2194 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 2623 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 4447 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 5977 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 6657 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 9490 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes .../ic_launcher_sleep_tracker.png | Bin 0 -> 8813 bytes .../ic_launcher_sleep_tracker_round.png | Bin 0 -> 13582 bytes .../src/main/res/navigation/navigation.xml | 75 +++++ .../app/src/main/res/values/colors.xml | 26 ++ .../app/src/main/res/values/dimens.xml | 22 ++ .../app/src/main/res/values/font_certs.xml | 32 +++ .../src/main/res/values/preloaded_fonts.xml | 21 ++ .../app/src/main/res/values/strings.xml | 61 ++++ .../app/src/main/res/values/styles.xml | 34 +++ RecyclerViewHeaders/build.gradle | 55 ++++ RecyclerViewHeaders/gradle.properties | 15 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + RecyclerViewHeaders/gradlew | 172 ++++++++++++ RecyclerViewHeaders/gradlew.bat | 84 ++++++ RecyclerViewHeaders/settings.gradle | 1 + 376 files changed, 14930 insertions(+) create mode 100755 RecyclerViewClickHandler/README.md create mode 100755 RecyclerViewClickHandler/app/.gitignore create mode 100755 RecyclerViewClickHandler/app/build.gradle create mode 100755 RecyclerViewClickHandler/app/proguard-rules.pro create mode 100755 RecyclerViewClickHandler/app/src/main/AndroidManifest.xml create mode 100755 RecyclerViewClickHandler/app/src/main/ic_launcher_sleep_tracker-web.png create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/MainActivity.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/Util.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt create mode 100644 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailFragment.kt create mode 100644 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModel.kt create mode 100644 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModelFactory.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt create mode 100644 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/BindingUtils.kt create mode 100644 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt create mode 100755 RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt create mode 100755 RecyclerViewClickHandler/app/src/main/res/anim/slide_in_right.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_0.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_1.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_2.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_3.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_4.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_5.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_active.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/font/roboto.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/layout/activity_main.xml create mode 100644 RecyclerViewClickHandler/app/src/main/res/layout/fragment_sleep_detail.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/layout/fragment_sleep_quality.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/layout/fragment_sleep_tracker.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/layout/list_item_sleep_night.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/layout/list_item_sleep_night_linear.xml create mode 100644 RecyclerViewClickHandler/app/src/main/res/layout/text_item_view.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker_round.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewClickHandler/app/src/main/res/navigation/navigation.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/values/colors.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/values/dimens.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/values/font_certs.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/values/preloaded_fonts.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/values/strings.xml create mode 100755 RecyclerViewClickHandler/app/src/main/res/values/styles.xml create mode 100755 RecyclerViewClickHandler/build.gradle create mode 100755 RecyclerViewClickHandler/gradle.properties create mode 100755 RecyclerViewClickHandler/gradle/wrapper/gradle-wrapper.jar create mode 100755 RecyclerViewClickHandler/gradle/wrapper/gradle-wrapper.properties create mode 100755 RecyclerViewClickHandler/gradlew create mode 100755 RecyclerViewClickHandler/gradlew.bat create mode 100755 RecyclerViewClickHandler/settings.gradle create mode 100755 RecyclerViewDiffUtilDataBinding/README.md create mode 100755 RecyclerViewDiffUtilDataBinding/app/.gitignore create mode 100755 RecyclerViewDiffUtilDataBinding/app/build.gradle create mode 100755 RecyclerViewDiffUtilDataBinding/app/proguard-rules.pro create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/AndroidManifest.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/ic_launcher_sleep_tracker-web.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/MainActivity.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/Util.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt create mode 100644 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/BindingUtils.kt create mode 100644 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/anim/slide_in_right.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_sleep_0.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_sleep_1.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_sleep_2.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_sleep_3.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_sleep_4.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_sleep_5.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/drawable/ic_sleep_active.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/font/roboto.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/layout/activity_main.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/layout/fragment_sleep_quality.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/layout/fragment_sleep_tracker.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/layout/list_item_sleep_night.xml create mode 100644 RecyclerViewDiffUtilDataBinding/app/src/main/res/layout/text_item_view.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker_round.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/navigation/navigation.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/values/colors.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/values/dimens.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/values/font_certs.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/values/preloaded_fonts.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/values/strings.xml create mode 100755 RecyclerViewDiffUtilDataBinding/app/src/main/res/values/styles.xml create mode 100755 RecyclerViewDiffUtilDataBinding/build.gradle create mode 100755 RecyclerViewDiffUtilDataBinding/gradle.properties create mode 100755 RecyclerViewDiffUtilDataBinding/gradle/wrapper/gradle-wrapper.jar create mode 100755 RecyclerViewDiffUtilDataBinding/gradle/wrapper/gradle-wrapper.properties create mode 100755 RecyclerViewDiffUtilDataBinding/gradlew create mode 100755 RecyclerViewDiffUtilDataBinding/gradlew.bat create mode 100755 RecyclerViewDiffUtilDataBinding/settings.gradle create mode 100755 RecyclerViewFundamentals/README.md create mode 100755 RecyclerViewFundamentals/app/.gitignore create mode 100755 RecyclerViewFundamentals/app/build.gradle create mode 100755 RecyclerViewFundamentals/app/proguard-rules.pro create mode 100755 RecyclerViewFundamentals/app/src/main/AndroidManifest.xml create mode 100755 RecyclerViewFundamentals/app/src/main/ic_launcher_sleep_tracker-web.png create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/MainActivity.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/Util.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt create mode 100644 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt create mode 100755 RecyclerViewFundamentals/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt create mode 100755 RecyclerViewFundamentals/app/src/main/res/anim/slide_in_right.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_sleep_0.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_sleep_1.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_sleep_2.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_sleep_3.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_sleep_4.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_sleep_5.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/drawable/ic_sleep_active.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/font/roboto.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/layout/activity_main.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/layout/fragment_sleep_quality.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/layout/fragment_sleep_tracker.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/layout/list_item_sleep_night.xml create mode 100644 RecyclerViewFundamentals/app/src/main/res/layout/text_item_view.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker_round.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewFundamentals/app/src/main/res/navigation/navigation.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/values/colors.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/values/dimens.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/values/font_certs.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/values/preloaded_fonts.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/values/strings.xml create mode 100755 RecyclerViewFundamentals/app/src/main/res/values/styles.xml create mode 100755 RecyclerViewFundamentals/build.gradle create mode 100755 RecyclerViewFundamentals/gradle.properties create mode 100755 RecyclerViewFundamentals/gradle/wrapper/gradle-wrapper.jar create mode 100755 RecyclerViewFundamentals/gradle/wrapper/gradle-wrapper.properties create mode 100755 RecyclerViewFundamentals/gradlew create mode 100755 RecyclerViewFundamentals/gradlew.bat create mode 100755 RecyclerViewFundamentals/settings.gradle create mode 100755 RecyclerViewGridLayout/README.md create mode 100755 RecyclerViewGridLayout/app/.gitignore create mode 100755 RecyclerViewGridLayout/app/build.gradle create mode 100755 RecyclerViewGridLayout/app/proguard-rules.pro create mode 100755 RecyclerViewGridLayout/app/src/main/AndroidManifest.xml create mode 100755 RecyclerViewGridLayout/app/src/main/ic_launcher_sleep_tracker-web.png create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/MainActivity.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/Util.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt create mode 100644 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/BindingUtils.kt create mode 100644 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt create mode 100755 RecyclerViewGridLayout/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt create mode 100755 RecyclerViewGridLayout/app/src/main/res/anim/slide_in_right.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_sleep_0.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_sleep_1.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_sleep_2.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_sleep_3.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_sleep_4.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_sleep_5.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/drawable/ic_sleep_active.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/font/roboto.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/layout/activity_main.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/layout/fragment_sleep_quality.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/layout/fragment_sleep_tracker.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/layout/list_item_sleep_night.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/layout/list_item_sleep_night_linear.xml create mode 100644 RecyclerViewGridLayout/app/src/main/res/layout/text_item_view.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker_round.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewGridLayout/app/src/main/res/navigation/navigation.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/values/colors.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/values/dimens.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/values/font_certs.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/values/preloaded_fonts.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/values/strings.xml create mode 100755 RecyclerViewGridLayout/app/src/main/res/values/styles.xml create mode 100755 RecyclerViewGridLayout/build.gradle create mode 100755 RecyclerViewGridLayout/gradle.properties create mode 100755 RecyclerViewGridLayout/gradle/wrapper/gradle-wrapper.jar create mode 100755 RecyclerViewGridLayout/gradle/wrapper/gradle-wrapper.properties create mode 100755 RecyclerViewGridLayout/gradlew create mode 100755 RecyclerViewGridLayout/gradlew.bat create mode 100755 RecyclerViewGridLayout/settings.gradle create mode 100755 RecyclerViewHeaders/README.md create mode 100755 RecyclerViewHeaders/app/.gitignore create mode 100755 RecyclerViewHeaders/app/build.gradle create mode 100755 RecyclerViewHeaders/app/proguard-rules.pro create mode 100755 RecyclerViewHeaders/app/src/main/AndroidManifest.xml create mode 100755 RecyclerViewHeaders/app/src/main/ic_launcher_sleep_tracker-web.png create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/MainActivity.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/Util.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt create mode 100644 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailFragment.kt create mode 100644 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModel.kt create mode 100644 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModelFactory.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt create mode 100644 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/BindingUtils.kt create mode 100644 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt create mode 100755 RecyclerViewHeaders/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt create mode 100755 RecyclerViewHeaders/app/src/main/res/anim/slide_in_right.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_sleep_0.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_sleep_1.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_sleep_2.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_sleep_3.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_sleep_4.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_sleep_5.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/drawable/ic_sleep_active.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/font/roboto.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/layout/activity_main.xml create mode 100644 RecyclerViewHeaders/app/src/main/res/layout/fragment_sleep_detail.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/layout/fragment_sleep_quality.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/layout/fragment_sleep_tracker.xml create mode 100644 RecyclerViewHeaders/app/src/main/res/layout/header.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/layout/list_item_sleep_night.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/layout/list_item_sleep_night_linear.xml create mode 100644 RecyclerViewHeaders/app/src/main/res/layout/text_item_view.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker_round.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker.png create mode 100755 RecyclerViewHeaders/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker_round.png create mode 100755 RecyclerViewHeaders/app/src/main/res/navigation/navigation.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/values/colors.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/values/dimens.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/values/font_certs.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/values/preloaded_fonts.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/values/strings.xml create mode 100755 RecyclerViewHeaders/app/src/main/res/values/styles.xml create mode 100755 RecyclerViewHeaders/build.gradle create mode 100755 RecyclerViewHeaders/gradle.properties create mode 100755 RecyclerViewHeaders/gradle/wrapper/gradle-wrapper.jar create mode 100755 RecyclerViewHeaders/gradle/wrapper/gradle-wrapper.properties create mode 100755 RecyclerViewHeaders/gradlew create mode 100755 RecyclerViewHeaders/gradlew.bat create mode 100755 RecyclerViewHeaders/settings.gradle diff --git a/RecyclerViewClickHandler/README.md b/RecyclerViewClickHandler/README.md new file mode 100755 index 0000000..2df9584 --- /dev/null +++ b/RecyclerViewClickHandler/README.md @@ -0,0 +1,55 @@ +TrackMySleepQuality with RecyclerView - Solution Code for 7.4 +============================================================= + +Solution code for Android Kotlin Fundamentals Codelab 7.4 Interacting with RecyclerView items + +Introduction +------------ + +TrackMySleepQuality is an app for recording sleep data for each night. +You can record a start and stop time, assign a quality rating, and clear the database. + +Learn how to make items in the RecyclerView clickable. +Implement a click listener and navigate on click in your Android Kotlin app. + +Pre-requisites +-------------- + +You should be familiar with: + +* Building a basic user interface (UI) using an activity, fragments, and views. +* Navigating between fragments, and using safeArgs to pass data between fragments. +* Using view models, view model factories, transformations, and LiveData and their observers. +* Creating a Room database, creating a DAO, and defining entities. +* Using coroutines for database tasks and other long-running tasks. +* How to implement a basic RecyclerView with an Adapter, ViewHolder, and item layout. +* How to implement data binding for RecyclerView. +* How to create and use binding adapters to transform data. +* How to use GridLayoutManager. + + +Getting Started +--------------- + +1. Download and run the app. + +License +------- + +Copyright 2019 Google, Inc. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. + diff --git a/RecyclerViewClickHandler/app/.gitignore b/RecyclerViewClickHandler/app/.gitignore new file mode 100755 index 0000000..796b96d --- /dev/null +++ b/RecyclerViewClickHandler/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/RecyclerViewClickHandler/app/build.gradle b/RecyclerViewClickHandler/app/build.gradle new file mode 100755 index 0000000..89f56de --- /dev/null +++ b/RecyclerViewClickHandler/app/build.gradle @@ -0,0 +1,80 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' +apply plugin: 'androidx.navigation.safeargs' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.example.android.trackmysleepqualityrecyclerview" + minSdkVersion 19 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables.useSupportLibrary = true + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + // Enables data binding. + dataBinding { + enabled = true + } + +} + +dependencies { + + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + // Support libraries + implementation "androidx.appcompat:appcompat:1.0.0" + implementation "androidx.fragment:fragment:1.0.0" + implementation "androidx.constraintlayout:constraintlayout:2.0.0-alpha2" + + // Android KTX + implementation 'androidx.core:core-ktx:1.0.1' + + // Room and Lifecycle dependencies + implementation "androidx.room:room-runtime:$room_version" + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + kapt "androidx.room:room-compiler:$room_version" + implementation "androidx.lifecycle:lifecycle-extensions:2.0.0" + + // Coroutines + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version" + + // Navigation + implementation "android.arch.navigation:navigation-fragment-ktx:$navigationVersion" + implementation "android.arch.navigation:navigation-ui-ktx:$navigationVersion" + + // Testing + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.0-alpha4' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4' +} + diff --git a/RecyclerViewClickHandler/app/proguard-rules.pro b/RecyclerViewClickHandler/app/proguard-rules.pro new file mode 100755 index 0000000..f1b4245 --- /dev/null +++ b/RecyclerViewClickHandler/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/RecyclerViewClickHandler/app/src/main/AndroidManifest.xml b/RecyclerViewClickHandler/app/src/main/AndroidManifest.xml new file mode 100755 index 0000000..58a0b98 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/ic_launcher_sleep_tracker-web.png b/RecyclerViewClickHandler/app/src/main/ic_launcher_sleep_tracker-web.png new file mode 100755 index 0000000000000000000000000000000000000000..668bfae8748fce8a49de3e9adf5e70a41ed28ef9 GIT binary patch literal 29407 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 { + val seconds = TimeUnit.SECONDS.convert(durationMilli, TimeUnit.MILLISECONDS) + res.getString(R.string.seconds_length, seconds, weekdayString) + } + durationMilli < ONE_HOUR_MILLIS -> { + val minutes = TimeUnit.MINUTES.convert(durationMilli, TimeUnit.MILLISECONDS) + res.getString(R.string.minutes_length, minutes, weekdayString) + } + else -> { + val hours = TimeUnit.HOURS.convert(durationMilli, TimeUnit.MILLISECONDS) + res.getString(R.string.hours_length, hours, weekdayString) + } + } +} + +/** + * Returns a string representing the numeric quality rating. + */ +fun convertNumericQualityToString(quality: Int, resources: Resources): String { + var qualityString = resources.getString(R.string.three_ok) + when (quality) { + -1 -> qualityString = "--" + 0 -> qualityString = resources.getString(R.string.zero_very_bad) + 1 -> qualityString = resources.getString(R.string.one_poor) + 2 -> qualityString = resources.getString(R.string.two_soso) + 4 -> qualityString = resources.getString(R.string.four_pretty_good) + 5 -> qualityString = resources.getString(R.string.five_excellent) + } + return qualityString +} + + +/** + * Take the Long milliseconds returned by the system and stored in Room, + * and convert it to a nicely formatted string for display. + * + * EEEE - Display the long letter version of the weekday + * MMM - Display the letter abbreviation of the nmotny + * dd-yyyy - day in month and full year numerically + * HH:mm - Hours and minutes in 24hr format + */ +@SuppressLint("SimpleDateFormat") +fun convertLongToDateString(systemTime: Long): String { + return SimpleDateFormat("EEEE MMM-dd-yyyy' Time: 'HH:mm") + .format(systemTime).toString() +} + +/** + * Takes a list of SleepNights and converts and formats it into one string for display. + * + * For display in a TextView, we have to supply one string, and styles are per TextView, not + * applicable per word. So, we build a formatted string using HTML. This is handy, but we will + * learn a better way of displaying this data in a future lesson. + * + * @param nights - List of all SleepNights in the database. + * @param resources - Resources object for all the resources defined for our app. + * + * @return Spanned - An interface for text that has formatting attached to it. + * See: https://developer.android.com/reference/android/text/Spanned + */ +fun formatNights(nights: List, resources: Resources): Spanned { + val sb = StringBuilder() + sb.apply { + append(resources.getString(R.string.title)) + nights.forEach { + append("
") + append(resources.getString(R.string.start_time)) + append("\t${convertLongToDateString(it.startTimeMilli)}
") + if (it.endTimeMilli != it.startTimeMilli) { + append(resources.getString(R.string.end_time)) + append("\t${convertLongToDateString(it.endTimeMilli)}
") + append(resources.getString(R.string.quality)) + append("\t${convertNumericQualityToString(it.sleepQuality, resources)}
") + append(resources.getString(R.string.hours_slept)) + // Hours + append("\t ${it.endTimeMilli.minus(it.startTimeMilli) / 1000 / 60 / 60}:") + // Minutes + append("${it.endTimeMilli.minus(it.startTimeMilli) / 1000 / 60}:") + // Seconds + append("${it.endTimeMilli.minus(it.startTimeMilli) / 1000}

") + } + } + } + // fromHtml is deprecated for target API without a flag, but since our minSDK is 19, we + // can't use the newer version, which requires minSDK of 24 + //https://developer.android.com/reference/android/text/Html#fromHtml(java.lang.String,%20int) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return Html.fromHtml(sb.toString(), Html.FROM_HTML_MODE_LEGACY) + } else { + @Suppress("DEPRECATION") + return Html.fromHtml(sb.toString()) + } +} + +/** + * ViewHolder that holds a single [TextView]. + * + * A ViewHolder holds a view for the [RecyclerView] as well as providing additional information + * to the RecyclerView such as where on the screen it was last drawn during scrolling. + */ +class TextItemViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView) \ No newline at end of file diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt new file mode 100755 index 0000000..483642b --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +/** + * A database that stores SleepNight information. + * And a global method to get access to the database. + * + * This pattern is pretty much the same for any database, + * so you can reuse it. + */ +@Database(entities = [SleepNight::class], version = 1, exportSchema = false) +abstract class SleepDatabase : RoomDatabase() { + + /** + * Connects the database to the DAO. + */ + abstract val sleepDatabaseDao: SleepDatabaseDao + + /** + * Define a companion object, this allows us to add functions on the SleepDatabase class. + * + * For example, clients can call `SleepDatabase.getInstance(context)` to instantiate + * a new SleepDatabase. + */ + companion object { + /** + * INSTANCE will keep a reference to any database returned via getInstance. + * + * This will help us avoid repeatedly initializing the database, which is expensive. + * + * The value of a volatile variable will never be cached, and all writes and + * reads will be done to and from the main memory. It means that changes made by one + * thread to shared data are visible to other threads. + */ + @Volatile + private var INSTANCE: SleepDatabase? = null + + /** + * Helper function to get the database. + * + * If a database has already been retrieved, the previous database will be returned. + * Otherwise, create a new database. + * + * This function is threadsafe, and callers should cache the result for multiple database + * calls to avoid overhead. + * + * This is an example of a simple Singleton pattern that takes another Singleton as an + * argument in Kotlin. + * + * To learn more about Singleton read the wikipedia article: + * https://en.wikipedia.org/wiki/Singleton_pattern + * + * @param context The application context Singleton, used to get access to the filesystem. + */ + fun getInstance(context: Context): SleepDatabase { + // Multiple threads can ask for the database at the same time, ensure we only initialize + // it once by using synchronized. Only one thread may enter a synchronized block at a + // time. + synchronized(this) { + + // Copy the current value of INSTANCE to a local variable so Kotlin can smart cast. + // Smart cast is only available to local variables. + var instance = INSTANCE + + // If instance is `null` make a new database instance. + if (instance == null) { + instance = Room.databaseBuilder( + context.applicationContext, + SleepDatabase::class.java, + "sleep_history_database" + ) + // Wipes and rebuilds instead of migrating if no Migration object. + // Migration is not part of this lesson. You can learn more about + // migration with Room in this blog post: + // https://medium.com/androiddevelopers/understanding-migrations-with-room-f01e04b07929 + .fallbackToDestructiveMigration() + .build() + // Assign INSTANCE to the newly created database. + INSTANCE = instance + } + + // Return instance; smart cast to be non-null. + return instance + } + } + } +} diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt new file mode 100755 index 0000000..39c5444 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.database + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update + + +/** + * Defines methods for using the SleepNight class with Room. + */ +@Dao +interface SleepDatabaseDao { + + @Insert + fun insert(night: SleepNight) + + /** + * When updating a row with a value already set in a column, + * replaces the old value with the new one. + * + * @param night new value to write + */ + @Update + fun update(night: SleepNight) + + /** + * Selects and returns the row that matches the supplied start time, which is our key. + * + * @param key startTimeMilli to match + */ + @Query("SELECT * from daily_sleep_quality_table WHERE nightId = :key") + fun get(key: Long): SleepNight + + /** + * Deletes all values from the table. + * + * This does not delete the table, only its contents. + */ + @Query("DELETE FROM daily_sleep_quality_table") + fun clear() + + /** + * Selects and returns all rows in the table, + * + * sorted by start time in descending order. + */ + @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC") + fun getAllNights(): LiveData> + + /** + * Selects and returns the latest night. + */ + @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1") + fun getTonight(): SleepNight? + + /** + * Selects and returns the night with given nightId. + */ + @Query("SELECT * from daily_sleep_quality_table WHERE nightId = :key") + fun getNightWithId(key: Long): LiveData +} diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt new file mode 100755 index 0000000..b776812 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.database + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +/** + * Represents one night's sleep through start, end times, and the sleep quality. + */ +@Entity(tableName = "daily_sleep_quality_table") +data class SleepNight( + @PrimaryKey(autoGenerate = true) + var nightId: Long = 0L, + + @ColumnInfo(name = "start_time_milli") + val startTimeMilli: Long = System.currentTimeMillis(), + + @ColumnInfo(name = "end_time_milli") + var endTimeMilli: Long = startTimeMilli, + + @ColumnInfo(name = "quality_rating") + var sleepQuality: Int = -1) diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailFragment.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailFragment.kt new file mode 100644 index 0000000..81b3310 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailFragment.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleepdetail + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import androidx.navigation.fragment.findNavController +import com.example.android.trackmysleepquality.R +import com.example.android.trackmysleepquality.database.SleepDatabase +import com.example.android.trackmysleepquality.databinding.FragmentSleepDetailBinding + + +/** + * A simple [Fragment] subclass. + * Activities that contain this fragment must implement the + * [SleepDetailFragment.OnFragmentInteractionListener] interface + * to handle interaction events. + * Use the [SleepDetailFragment.newInstance] factory method to + * create an instance of this fragment. + * + */ +class SleepDetailFragment : Fragment() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + // Get a reference to the binding object and inflate the fragment views. + val binding: FragmentSleepDetailBinding = DataBindingUtil.inflate( + inflater, R.layout.fragment_sleep_detail, container, false) + + val application = requireNotNull(this.activity).application + val arguments = SleepDetailFragmentArgs.fromBundle(arguments) + + // Create an instance of the ViewModel Factory. + val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao + val viewModelFactory = SleepDetailViewModelFactory(arguments.sleepNightKey, dataSource) + + // Get a reference to the ViewModel associated with this fragment. + val sleepDetailViewModel = + ViewModelProviders.of( + this, viewModelFactory).get(SleepDetailViewModel::class.java) + + // To use the View Model with data binding, you have to explicitly + // give the binding object a reference to it. + binding.sleepDetailViewModel = sleepDetailViewModel + + binding.setLifecycleOwner(this) + + // Add an Observer to the state variable for Navigating when a Quality icon is tapped. + sleepDetailViewModel.navigateToSleepTracker.observe(this, Observer { + if (it == true) { // Observed state is true. + this.findNavController().navigate( + SleepDetailFragmentDirections.actionSleepDetailFragmentToSleepTrackerFragment()) + // Reset state to make sure we only navigate once, even if the device + // has a configuration change. + sleepDetailViewModel.doneNavigating() + } + }) + + return binding.root + } + + +} \ No newline at end of file diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModel.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModel.kt new file mode 100644 index 0000000..e449a94 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModel.kt @@ -0,0 +1,97 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleepdetail + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.example.android.trackmysleepquality.database.SleepDatabaseDao +import com.example.android.trackmysleepquality.database.SleepNight +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * ViewModel for SleepQualityFragment. + * + * @param sleepNightKey The key of the current night we are working on. + */ +class SleepDetailViewModel( + private val sleepNightKey: Long = 0L, + dataSource: SleepDatabaseDao) : ViewModel() { + + /** + * Hold a reference to SleepDatabase via its SleepDatabaseDao. + */ + val database = dataSource + + /** Coroutine setup variables */ + + /** + * viewModelJob allows us to cancel all coroutines started by this ViewModel. + */ + private val viewModelJob = Job() + + private val night: LiveData + + fun getNight() = night + + + init { + night=database.getNightWithId(sleepNightKey) + } + + /** + * Variable that tells the fragment whether it should navigate to [SleepTrackerFragment]. + * + * This is `private` because we don't want to expose the ability to set [MutableLiveData] to + * the [Fragment] + */ + private val _navigateToSleepTracker = MutableLiveData() + + /** + * When true immediately navigate back to the [SleepTrackerFragment] + */ + val navigateToSleepTracker: LiveData + get() = _navigateToSleepTracker + + /** + * Cancels all coroutines when the ViewModel is cleared, to cleanup any pending work. + * + * onCleared() gets called when the ViewModel is destroyed. + */ + override fun onCleared() { + super.onCleared() + viewModelJob.cancel() + } + + + /** + * Call this immediately after navigating to [SleepTrackerFragment] + */ + fun doneNavigating() { + _navigateToSleepTracker.value = null + } + + fun onClose() { + _navigateToSleepTracker.value = true + } + +} \ No newline at end of file diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModelFactory.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModelFactory.kt new file mode 100644 index 0000000..fb59a98 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepdetail/SleepDetailViewModelFactory.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleepdetail + + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.android.trackmysleepquality.database.SleepDatabaseDao + +/** + * This is pretty much boiler plate code for a ViewModel Factory. + * + * Provides the key for the night and the SleepDatabaseDao to the ViewModel. + */ +class SleepDetailViewModelFactory( + private val sleepNightKey: Long, + private val dataSource: SleepDatabaseDao) : ViewModelProvider.Factory { + @Suppress("unchecked_cast") + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(SleepDetailViewModel::class.java)) { + return SleepDetailViewModel(sleepNightKey, dataSource) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} \ No newline at end of file diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt new file mode 100755 index 0000000..db22082 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleepquality + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import androidx.navigation.fragment.findNavController +import com.example.android.trackmysleepquality.R +import com.example.android.trackmysleepquality.database.SleepDatabase +import com.example.android.trackmysleepquality.databinding.FragmentSleepQualityBinding + +/** + * Fragment that displays a list of clickable icons, + * each representing a sleep quality rating. + * Once the user taps an icon, the quality is set in the current sleepNight + * and the database is updated. + */ +class SleepQualityFragment : Fragment() { + + /** + * Called when the Fragment is ready to display content to the screen. + * + * This function uses DataBindingUtil to inflate R.layout.fragment_sleep_quality. + * + * It is also responsible for passing the [SleepQualityViewModel] to the + * [FragmentSleepQualityBinding] generated by DataBinding. This will allow DataBinding + * to use the [LiveData] on our ViewModel. + */ + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + // Get a reference to the binding object and inflate the fragment views. + val binding: FragmentSleepQualityBinding = DataBindingUtil.inflate( + inflater, R.layout.fragment_sleep_quality, container, false) + + val application = requireNotNull(this.activity).application + val arguments = SleepQualityFragmentArgs.fromBundle(arguments) + + // Create an instance of the ViewModel Factory. + val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao + val viewModelFactory = SleepQualityViewModelFactory(arguments.sleepNightKey, dataSource) + + // Get a reference to the ViewModel associated with this fragment. + val sleepQualityViewModel = + ViewModelProviders.of( + this, viewModelFactory).get(SleepQualityViewModel::class.java) + + // To use the View Model with data binding, you have to explicitly + // give the binding object a reference to it. + binding.sleepQualityViewModel = sleepQualityViewModel + + // Add an Observer to the state variable for Navigating when a Quality icon is tapped. + sleepQualityViewModel.navigateToSleepTracker.observe(this, Observer { + if (it == true) { // Observed state is true. + this.findNavController().navigate( + SleepQualityFragmentDirections.actionSleepQualityFragmentToSleepTrackerFragment()) + // Reset state to make sure we only navigate once, even if the device + // has a configuration change. + sleepQualityViewModel.doneNavigating() + } + }) + + return binding.root + } +} diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt new file mode 100755 index 0000000..52ce4d8 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleepquality + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.example.android.trackmysleepquality.database.SleepDatabaseDao +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * ViewModel for SleepQualityFragment. + * + * @param sleepNightKey The key of the current night we are working on. + */ +class SleepQualityViewModel( + private val sleepNightKey: Long = 0L, + dataSource: SleepDatabaseDao) : ViewModel() { + + /** + * Hold a reference to SleepDatabase via its SleepDatabaseDao. + */ + val database = dataSource + + /** Coroutine setup variables */ + + /** + * viewModelJob allows us to cancel all coroutines started by this ViewModel. + */ + private val viewModelJob = Job() + + /** + * A [CoroutineScope] keeps track of all coroutines started by this ViewModel. + * + * Because we pass it [viewModelJob], any coroutine started in this scope can be cancelled + * by calling `viewModelJob.cancel()` + * + * By default, all coroutines started in uiScope will launch in [Dispatchers.Main] which is + * the main thread on Android. This is a sensible default because most coroutines started by + * a [ViewModel] update the UI after performing some processing. + */ + private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob) + + /** + * Variable that tells the fragment whether it should navigate to [SleepTrackerFragment]. + * + * This is `private` because we don't want to expose the ability to set [MutableLiveData] to + * the [Fragment] + */ + private val _navigateToSleepTracker = MutableLiveData() + + /** + * When true immediately navigate back to the [SleepTrackerFragment] + */ + val navigateToSleepTracker: LiveData + get() = _navigateToSleepTracker + + /** + * Cancels all coroutines when the ViewModel is cleared, to cleanup any pending work. + * + * onCleared() gets called when the ViewModel is destroyed. + */ + override fun onCleared() { + super.onCleared() + viewModelJob.cancel() + } + + /** + * Call this immediately after navigating to [SleepTrackerFragment] + */ + fun doneNavigating() { + _navigateToSleepTracker.value = null + } + + /** + * Sets the sleep quality and updates the database. + * + * Then navigates back to the SleepTrackerFragment. + */ + fun onSetSleepQuality(quality: Int) { + uiScope.launch { + // IO is a thread pool for running operations that access the disk, such as + // our Room database. + withContext(Dispatchers.IO) { + val tonight = database.get(sleepNightKey) + tonight.sleepQuality = quality + database.update(tonight) + } + + // Setting this state variable to true will alert the observer and trigger navigation. + _navigateToSleepTracker.value = true + } + } +} diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt new file mode 100755 index 0000000..3c6a35d --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleepquality + + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.android.trackmysleepquality.database.SleepDatabaseDao + +/** + * This is pretty much boiler plate code for a ViewModel Factory. + * + * Provides the key for the night and the SleepDatabaseDao to the ViewModel. + */ +class SleepQualityViewModelFactory( + private val sleepNightKey: Long, + private val dataSource: SleepDatabaseDao) : ViewModelProvider.Factory { + @Suppress("unchecked_cast") + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(SleepQualityViewModel::class.java)) { + return SleepQualityViewModel(sleepNightKey, dataSource) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/BindingUtils.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/BindingUtils.kt new file mode 100644 index 0000000..b5089e0 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/BindingUtils.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleeptracker + +import android.widget.ImageView +import android.widget.TextView +import androidx.databinding.BindingAdapter +import com.example.android.trackmysleepquality.R +import com.example.android.trackmysleepquality.convertDurationToFormatted +import com.example.android.trackmysleepquality.convertNumericQualityToString +import com.example.android.trackmysleepquality.database.SleepNight + + +@BindingAdapter("sleepDurationFormatted") +fun TextView.setSleepDurationFormatted(item: SleepNight?) { + item?.let { + text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources) + } +} + + +@BindingAdapter("sleepQualityString") +fun TextView.setSleepQualityString(item: SleepNight?) { + item?.let { + text = convertNumericQualityToString(item.sleepQuality, context.resources) + } +} + + +@BindingAdapter("sleepImage") +fun ImageView.setSleepImage(item: SleepNight?) { + item?.let { + setImageResource(when (item.sleepQuality) { + 0 -> R.drawable.ic_sleep_0 + 1 -> R.drawable.ic_sleep_1 + 2 -> R.drawable.ic_sleep_2 + + 3 -> R.drawable.ic_sleep_3 + + 4 -> R.drawable.ic_sleep_4 + 5 -> R.drawable.ic_sleep_5 + else -> R.drawable.ic_sleep_active + }) + } +} \ No newline at end of file diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt new file mode 100644 index 0000000..9382360 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepNightAdapter.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleeptracker + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.example.android.trackmysleepquality.database.SleepNight +import com.example.android.trackmysleepquality.databinding.ListItemSleepNightBinding + +class SleepNightAdapter(val clickListener: SleepNightListener) : ListAdapter(SleepNightDiffCallback()) { + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(getItem(position)!!, clickListener) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder.from(parent) + } + + class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){ + + fun bind(item: SleepNight, clickListener: SleepNightListener) { + binding.sleep = item + binding.clickListener = clickListener + binding.executePendingBindings() + } + + companion object { + fun from(parent: ViewGroup): ViewHolder { + val layoutInflater = LayoutInflater.from(parent.context) + val binding = ListItemSleepNightBinding.inflate(layoutInflater, parent, false) + return ViewHolder(binding) + } + } + } +} + + +class SleepNightDiffCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean { + return oldItem.nightId == newItem.nightId + } + + override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean { + return oldItem == newItem + } +} + + +class SleepNightListener(val clickListener: (sleepId: Long) -> Unit) { + fun onClick(night: SleepNight) = clickListener(night.nightId) +} diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt new file mode 100755 index 0000000..10d7d34 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt @@ -0,0 +1,140 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleeptracker + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.GridLayoutManager +import com.example.android.trackmysleepquality.R +import com.example.android.trackmysleepquality.database.SleepDatabase +import com.example.android.trackmysleepquality.databinding.FragmentSleepTrackerBinding +import com.google.android.material.snackbar.Snackbar + +/** + * A fragment with buttons to record start and end times for sleep, which are saved in + * a database. Cumulative data is displayed in a simple scrollable TextView. + * (Because we have not learned about RecyclerView yet.) + * The Clear button will clear all data from the database. + */ +class SleepTrackerFragment : Fragment() { + + /** + * Called when the Fragment is ready to display content to the screen. + * + * This function uses DataBindingUtil to inflate R.layout.fragment_sleep_quality. + * + * It is also responsible for passing the [SleepTrackerViewModel] to the + * [FragmentSleepTrackerBinding] generated by DataBinding. This will allow DataBinding + * to use the [LiveData] on our ViewModel. + */ + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + // Get a reference to the binding object and inflate the fragment views. + val binding: FragmentSleepTrackerBinding = DataBindingUtil.inflate( + inflater, R.layout.fragment_sleep_tracker, container, false) + + val application = requireNotNull(this.activity).application + + // Create an instance of the ViewModel Factory. + val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao + val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application) + + // Get a reference to the ViewModel associated with this fragment. + val sleepTrackerViewModel = + ViewModelProviders.of( + this, viewModelFactory).get(SleepTrackerViewModel::class.java) + + // To use the View Model with data binding, you have to explicitly + // give the binding object a reference to it. + binding.sleepTrackerViewModel = sleepTrackerViewModel + + val adapter = SleepNightAdapter(SleepNightListener { nightId -> + //Toast.makeText(context, "${nightId}", Toast.LENGTH_LONG).show() + sleepTrackerViewModel.onSleepNightClicked(nightId) + }) + binding.sleepList.adapter = adapter + + + sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer { + it?.let { + adapter.submitList(it) + } + }) + + // Specify the current activity as the lifecycle owner of the binding. + // This is necessary so that the binding can observe LiveData updates. + binding.setLifecycleOwner(this) + + // Add an Observer on the state variable for showing a Snackbar message + // when the CLEAR button is pressed. + sleepTrackerViewModel.showSnackBarEvent.observe(this, Observer { + if (it == true) { // Observed state is true. + Snackbar.make( + activity!!.findViewById(android.R.id.content), + getString(R.string.cleared_message), + Snackbar.LENGTH_SHORT // How long to display the message. + ).show() + // Reset state to make sure the toast is only shown once, even if the device + // has a configuration change. + sleepTrackerViewModel.doneShowingSnackbar() + } + }) + + // Add an Observer on the state variable for Navigating when STOP button is pressed. + sleepTrackerViewModel.navigateToSleepQuality.observe(this, Observer { night -> + night?.let { + // We need to get the navController from this, because button is not ready, and it + // just has to be a view. For some reason, this only matters if we hit stop again + // after using the back button, not if we hit stop and choose a quality. + // Also, in the Navigation Editor, for Quality -> Tracker, check "Inclusive" for + // popping the stack to get the correct behavior if we press stop multiple times + // followed by back. + // Also: https://stackoverflow.com/questions/28929637/difference-and-uses-of-oncreate-oncreateview-and-onactivitycreated-in-fra + this.findNavController().navigate( + SleepTrackerFragmentDirections + .actionSleepTrackerFragmentToSleepQualityFragment(night.nightId)) + // Reset state to make sure we only navigate once, even if the device + // has a configuration change. + sleepTrackerViewModel.doneNavigating() + } + }) + + // Add an Observer on the state variable for Navigating when and item is clicked. + sleepTrackerViewModel.navigateToSleepDetail.observe(this, Observer { night -> + night?.let { + + this.findNavController().navigate( + SleepTrackerFragmentDirections + .actionSleepTrackerFragmentToSleepDetailFragment(night)) + sleepTrackerViewModel.onSleepDetailNavigated() + } + }) + + val manager = GridLayoutManager(activity, 3) + binding.sleepList.layoutManager = manager + + return binding.root + } +} diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt new file mode 100755 index 0000000..a42e69f --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt @@ -0,0 +1,263 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleeptracker + +import android.app.Application +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Transformations +import androidx.lifecycle.ViewModel +import com.example.android.trackmysleepquality.database.SleepDatabaseDao +import com.example.android.trackmysleepquality.database.SleepNight +import com.example.android.trackmysleepquality.formatNights +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * ViewModel for SleepTrackerFragment. + */ +class SleepTrackerViewModel( + dataSource: SleepDatabaseDao, + application: Application) : ViewModel() { + + /** + * Hold a reference to SleepDatabase via SleepDatabaseDao. + */ + val database = dataSource + + /** Coroutine variables */ + + /** + * viewModelJob allows us to cancel all coroutines started by this ViewModel. + */ + private var viewModelJob = Job() + + /** + * A [CoroutineScope] keeps track of all coroutines started by this ViewModel. + * + * Because we pass it [viewModelJob], any coroutine started in this uiScope can be cancelled + * by calling `viewModelJob.cancel()` + * + * By default, all coroutines started in uiScope will launch in [Dispatchers.Main] which is + * the main thread on Android. This is a sensible default because most coroutines started by + * a [ViewModel] update the UI after performing some processing. + */ + private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob) + + private var tonight = MutableLiveData() + + val nights = database.getAllNights() + + /** + * Converted nights to Spanned for displaying. + */ + val nightsString = Transformations.map(nights) { nights -> + formatNights(nights, application.resources) + } + + /** + * If tonight has not been set, then the START button should be visible. + */ + val startButtonVisible = Transformations.map(tonight) { + null == it + } + + /** + * If tonight has been set, then the STOP button should be visible. + */ + val stopButtonVisible = Transformations.map(tonight) { + null != it + } + + /** + * If there are any nights in the database, show the CLEAR button. + */ + val clearButtonVisible = Transformations.map(nights) { + it?.isNotEmpty() + } + + /** + * Request a toast by setting this value to true. + * + * This is private because we don't want to expose setting this value to the Fragment. + */ + private var _showSnackbarEvent = MutableLiveData() + + /** + * If this is true, immediately `show()` a toast and call `doneShowingSnackbar()`. + */ + val showSnackBarEvent: LiveData + get() = _showSnackbarEvent + + /** + * Variable that tells the Fragment to navigate to a specific [SleepQualityFragment] + * + * This is private because we don't want to expose setting this value to the Fragment. + */ + private val _navigateToSleepQuality = MutableLiveData() + + /** + * If this is non-null, immediately navigate to [SleepQualityFragment] and call [doneNavigating] + */ + val navigateToSleepQuality: LiveData + get() = _navigateToSleepQuality + + /** + * Call this immediately after calling `show()` on a toast. + * + * It will clear the toast request, so if the user rotates their phone it won't show a duplicate + * toast. + */ + fun doneShowingSnackbar() { + _showSnackbarEvent.value = null + } + + /** + * Call this immediately after navigating to [SleepQualityFragment] + * + * It will clear the navigation request, so if the user rotates their phone it won't navigate + * twice. + */ + fun doneNavigating() { + _navigateToSleepQuality.value = null + } + + /** + * Navigation for the SleepDetail fragment. + */ + private val _navigateToSleepDetail = MutableLiveData() + val navigateToSleepDetail + get() = _navigateToSleepDetail + + fun onSleepNightClicked(id: Long) { + _navigateToSleepDetail.value = id + } + + fun onSleepDetailNavigated() { + _navigateToSleepDetail.value = null + } + + init { + initializeTonight() + } + + private fun initializeTonight() { + uiScope.launch { + tonight.value = getTonightFromDatabase() + } + } + + /** + * Handling the case of the stopped app or forgotten recording, + * the start and end times will be the same.j + * + * If the start time and end time are not the same, then we do not have an unfinished + * recording. + */ + private suspend fun getTonightFromDatabase(): SleepNight? { + return withContext(Dispatchers.IO) { + var night = database.getTonight() + if (night?.endTimeMilli != night?.startTimeMilli) { + night = null + } + night + } + } + + private suspend fun insert(night: SleepNight) { + withContext(Dispatchers.IO) { + database.insert(night) + } + } + + private suspend fun update(night: SleepNight) { + withContext(Dispatchers.IO) { + database.update(night) + } + } + + private suspend fun clear() { + withContext(Dispatchers.IO) { + database.clear() + } + } + + /** + * Executes when the START button is clicked. + */ + fun onStart() { + uiScope.launch { + // Create a new night, which captures the current time, + // and insert it into the database. + val newNight = SleepNight() + + insert(newNight) + + tonight.value = getTonightFromDatabase() + } + } + + /** + * Executes when the STOP button is clicked. + */ + fun onStop() { + uiScope.launch { + // In Kotlin, the return@label syntax is used for specifying which function among + // several nested ones this statement returns from. + // In this case, we are specifying to return from launch(). + val oldNight = tonight.value ?: return@launch + + // Update the night in the database to add the end time. + oldNight.endTimeMilli = System.currentTimeMillis() + + update(oldNight) + + // Set state to navigate to the SleepQualityFragment. + _navigateToSleepQuality.value = oldNight + } + } + + /** + * Executes when the CLEAR button is clicked. + */ + fun onClear() { + uiScope.launch { + // Clear the database table. + clear() + + // And clear tonight since it's no longer in the database + tonight.value = null + + // Show a snackbar message, because it's friendly. + _showSnackbarEvent.value = true + } + } + + /** + * Called when the ViewModel is dismantled. + * At this point, we want to cancel all coroutines; + * otherwise we end up with processes that have nowhere to return to + * using memory and resources. + */ + override fun onCleared() { + super.onCleared() + viewModelJob.cancel() + } +} \ No newline at end of file diff --git a/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt new file mode 100755 index 0000000..abcd8ac --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.trackmysleepquality.sleeptracker + + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.android.trackmysleepquality.database.SleepDatabaseDao + +/** + * This is pretty much boiler plate code for a ViewModel Factory. + * + * Provides the SleepDatabaseDao and context to the ViewModel. + */ +class SleepTrackerViewModelFactory( + private val dataSource: SleepDatabaseDao, + private val application: Application) : ViewModelProvider.Factory { + @Suppress("unchecked_cast") + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(SleepTrackerViewModel::class.java)) { + return SleepTrackerViewModel(dataSource, application) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/RecyclerViewClickHandler/app/src/main/res/anim/slide_in_right.xml b/RecyclerViewClickHandler/app/src/main/res/anim/slide_in_right.xml new file mode 100755 index 0000000..49f7779 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/anim/slide_in_right.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml new file mode 100755 index 0000000..0b1f6bd --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml new file mode 100755 index 0000000..a117d56 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_0.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_0.xml new file mode 100755 index 0000000..91c0b47 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_0.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_1.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_1.xml new file mode 100755 index 0000000..8cc34f7 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_1.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_2.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_2.xml new file mode 100755 index 0000000..0b7b818 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_2.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_3.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_3.xml new file mode 100755 index 0000000..677b9ae --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_3.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_4.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_4.xml new file mode 100755 index 0000000..39eab52 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_4.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_5.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_5.xml new file mode 100755 index 0000000..f23a2ae --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_5.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_active.xml b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_active.xml new file mode 100755 index 0000000..a117d56 --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/drawable/ic_sleep_active.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/font/roboto.xml b/RecyclerViewClickHandler/app/src/main/res/font/roboto.xml new file mode 100755 index 0000000..2641caf --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/font/roboto.xml @@ -0,0 +1,7 @@ + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/layout/activity_main.xml b/RecyclerViewClickHandler/app/src/main/res/layout/activity_main.xml new file mode 100755 index 0000000..a21679c --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,32 @@ + + + + + + + + + diff --git a/RecyclerViewClickHandler/app/src/main/res/layout/fragment_sleep_detail.xml b/RecyclerViewClickHandler/app/src/main/res/layout/fragment_sleep_detail.xml new file mode 100644 index 0000000..a4a70ca --- /dev/null +++ b/RecyclerViewClickHandler/app/src/main/res/layout/fragment_sleep_detail.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + +