├── app ├── .gitignore ├── src │ ├── main │ │ ├── ic_launcher_sleep_tracker-web.png │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_sleep_tracker.png │ │ │ │ └── ic_launcher_sleep_tracker_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_sleep_tracker.png │ │ │ │ └── ic_launcher_sleep_tracker_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_sleep_tracker.png │ │ │ │ └── ic_launcher_sleep_tracker_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_sleep_tracker.png │ │ │ │ └── ic_launcher_sleep_tracker_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_sleep_tracker.png │ │ │ │ └── ic_launcher_sleep_tracker_round.png │ │ │ ├── font │ │ │ │ └── roboto.xml │ │ │ ├── values │ │ │ │ ├── preloaded_fonts.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ ├── strings.xml │ │ │ │ └── font_certs.xml │ │ │ ├── anim │ │ │ │ └── slide_in_right.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ ├── ic_launcher_round.xml │ │ │ │ ├── ic_launcher_sleep_tracker.xml │ │ │ │ └── ic_launcher_sleep_tracker_round.xml │ │ │ ├── layout │ │ │ │ ├── activity_main.xml │ │ │ │ ├── fragment_sleep_tracker.xml │ │ │ │ └── fragment_sleep_quality.xml │ │ │ ├── drawable │ │ │ │ ├── ic_sleep_1.xml │ │ │ │ ├── ic_sleep_4.xml │ │ │ │ ├── ic_sleep_2.xml │ │ │ │ ├── ic_sleep_0.xml │ │ │ │ ├── ic_sleep_5.xml │ │ │ │ ├── ic_sleep_3.xml │ │ │ │ ├── ic_launcher_sleep_tracker_background.xml │ │ │ │ └── ic_launcher_sleep_tracker_foreground.xml │ │ │ └── navigation │ │ │ │ └── navigation.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── android │ │ │ └── trackmysleepquality │ │ │ ├── database │ │ │ ├── SleepNight.kt │ │ │ ├── SleepDatabaseDao.kt │ │ │ └── SleepDatabase.kt │ │ │ ├── sleepquality │ │ │ ├── SleepQualityViewModelFactory.kt │ │ │ ├── SleepQualityViewModel.kt │ │ │ └── SleepQualityFragment.kt │ │ │ ├── sleeptracker │ │ │ ├── SleepTrackerViewModelFactory.kt │ │ │ ├── SleepTrackerFragment.kt │ │ │ └── SleepTrackerViewModel.kt │ │ │ ├── MainActivity.kt │ │ │ └── Util.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── example │ │ └── android │ │ └── trackmysleepquality │ │ └── SleepDatabaseTest.kt ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── CODEOWNERS ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── screenshots ├── sleep_quality_tracker_start.png ├── sleep_quality_tracker_stop.png └── sleep_quality_tracker_quality.png ├── gradle.properties ├── .github └── workflows │ └── manual.yml ├── gradlew.bat ├── README.md ├── gradlew └── LICENSE.txt /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @udacity/active-public-content -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /screenshots/sleep_quality_tracker_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/screenshots/sleep_quality_tracker_start.png -------------------------------------------------------------------------------- /screenshots/sleep_quality_tracker_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/screenshots/sleep_quality_tracker_stop.png -------------------------------------------------------------------------------- /app/src/main/ic_launcher_sleep_tracker-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/ic_launcher_sleep_tracker-web.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /screenshots/sleep_quality_tracker_quality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/screenshots/sleep_quality_tracker_quality.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_sleep_tracker_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_sleep_tracker_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_sleep_tracker_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_sleep_tracker_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/andfun-kotlin-sleep-tracker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_sleep_tracker_round.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Aug 11 17:39:48 PDT 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/font/roboto.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | android.useAndroidX=true 15 | android.enableJetifier=true 16 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/preloaded_fonts.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | @font/roboto 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 16dp 19 | 64dp 20 | 20sp 21 | 48dp 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | #6ab343 20 | #388310 21 | #6ab343 22 | 23 | #388310 24 | #f0f0f0 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_sleep_tracker_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.database 18 | 19 | import androidx.room.ColumnInfo 20 | import androidx.room.Entity 21 | import androidx.room.PrimaryKey 22 | 23 | @Entity(tableName = "daily_sleep_quality_table") 24 | data class SleepNight( 25 | @PrimaryKey(autoGenerate = true) 26 | var nightId: Long = 0L, 27 | 28 | @ColumnInfo(name = "start_time_milli") 29 | val startTimeMilli: Long = System.currentTimeMillis(), 30 | 31 | @ColumnInfo(name = "end_time_milli") 32 | var endTimeMilli: Long = startTimeMilli, 33 | 34 | @ColumnInfo(name = "quality_rating") 35 | var sleepQuality: Int = -1 36 | ) 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 23 | 24 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.sleepquality 18 | 19 | import androidx.lifecycle.ViewModel 20 | import androidx.lifecycle.ViewModelProvider 21 | import com.example.android.trackmysleepquality.database.SleepDatabaseDao 22 | 23 | /** 24 | * This is pretty much boiler plate code for a ViewModel Factory. 25 | * 26 | * Provides the key for the night and the SleepDatabaseDao to the ViewModel. 27 | */ 28 | class SleepQualityViewModelFactory( 29 | private val sleepNightKey: Long, 30 | private val dataSource: SleepDatabaseDao) : ViewModelProvider.Factory { 31 | @Suppress("unchecked_cast") 32 | override fun create(modelClass: Class): T { 33 | if (modelClass.isAssignableFrom(SleepQualityViewModel::class.java)) { 34 | return SleepQualityViewModel(sleepNightKey, dataSource) as T 35 | } 36 | throw IllegalArgumentException("Unknown ViewModel class") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.sleeptracker 18 | 19 | import android.app.Application 20 | import androidx.lifecycle.ViewModel 21 | import androidx.lifecycle.ViewModelProvider 22 | import com.example.android.trackmysleepquality.database.SleepDatabaseDao 23 | 24 | /** 25 | * This is pretty much boiler plate code for a ViewModel Factory. 26 | * 27 | * Provides the SleepDatabaseDao and context to the ViewModel. 28 | */ 29 | class SleepTrackerViewModelFactory( 30 | private val dataSource: SleepDatabaseDao, 31 | private val application: Application) : ViewModelProvider.Factory { 32 | @Suppress("unchecked_cast") 33 | override fun create(modelClass: Class): T { 34 | if (modelClass.isAssignableFrom(SleepTrackerViewModel::class.java)) { 35 | return SleepTrackerViewModel(dataSource, application) as T 36 | } 37 | throw IllegalArgumentException("Unknown ViewModel class") 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sleep_1.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sleep_4.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.github/workflows/manual.yml: -------------------------------------------------------------------------------- 1 | # Workflow to ensure whenever a Github PR is submitted, 2 | # a JIRA ticket gets created automatically. 3 | name: Manual Workflow 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on pull request events but only for the master branch 8 | pull_request_target: 9 | types: [opened, reopened] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | test-transition-issue: 16 | name: Convert Github Issue to Jira Issue 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@master 21 | 22 | - name: Login 23 | uses: atlassian/gajira-login@master 24 | env: 25 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} 26 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} 27 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} 28 | 29 | - name: Create NEW JIRA ticket 30 | id: create 31 | uses: atlassian/gajira-create@master 32 | with: 33 | project: CONUPDATE 34 | issuetype: Task 35 | summary: | 36 | Github PR nd940 - Android Kotlin Developer | Repo: ${{ github.repository }} | PR# ${{github.event.number}} 37 | description: | 38 | Repo link: https://github.com/${{ github.repository }} 39 | PR no. ${{ github.event.pull_request.number }} 40 | PR title: ${{ github.event.pull_request.title }} 41 | PR description: ${{ github.event.pull_request.description }} 42 | In addition, please resolve other issues, if any. 43 | fields: '{"components": [{"name":"nd940 - Android Kotlin Developer"}], "customfield_16449":"https://classroom.udacity.com/", "customfield_16450":"Resolve the PR", "labels": ["github"], "priority":{"id": "4"}}' 44 | 45 | - name: Log created issue 46 | run: echo "Issue ${{ steps.create.outputs.issue }} was created" 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality 18 | 19 | import android.os.Bundle 20 | import androidx.appcompat.app.AppCompatActivity 21 | 22 | 23 | /** 24 | * This is the toy app for lesson 6 of the 25 | * Android App Development in Kotlin course on Udacity(https://www.udacity.com/course/???). 26 | * 27 | * The SleepQualityTracker app is a demo app that helps you collect information about your sleep. 28 | * - Start time, end time, quality, and time slept 29 | * 30 | * This app demonstrates the following views and techniques: 31 | * - Room database, DAO, and Coroutines 32 | * 33 | * It also uses and builds on the following techniques from previous lessons: 34 | * - Transformation map 35 | * - Data Binding in XML files 36 | * - ViewModel Factory 37 | * - Using Backing Properties to protect MutableLiveData 38 | * - Observable state LiveData variables to trigger navigation 39 | */ 40 | 41 | /** 42 | * This main activity is just a container for our fragments, 43 | * where the real action is. 44 | */ 45 | class MainActivity : AppCompatActivity() { 46 | 47 | override fun onCreate(savedInstanceState: Bundle?) { 48 | super.onCreate(savedInstanceState) 49 | 50 | setContentView(R.layout.activity_main) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sleep_2.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sleep_0.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sleep_5.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sleep_3.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.database 18 | 19 | import androidx.lifecycle.LiveData 20 | import androidx.room.Dao 21 | import androidx.room.Insert 22 | import androidx.room.Query 23 | import androidx.room.Update 24 | 25 | /** 26 | * Defines methods for using the SleepNight class with Room. 27 | */ 28 | @Dao 29 | interface SleepDatabaseDao { 30 | 31 | @Insert 32 | suspend fun insert(night: SleepNight) 33 | 34 | /** 35 | * When updating a row with a value already set in a column, 36 | * replaces the old value with the new one. 37 | * 38 | * @param night new value to write 39 | */ 40 | @Update 41 | suspend fun update(night: SleepNight) 42 | 43 | /** 44 | * Selects and returns the row that matches the supplied start time, which is our key. 45 | * 46 | * @param key startTimeMilli to match 47 | */ 48 | @Query("SELECT * from daily_sleep_quality_table WHERE nightId = :key") 49 | suspend fun get(key: Long): SleepNight? 50 | 51 | /** 52 | * Deletes all values from the table. 53 | * 54 | * This does not delete the table, only its contents. 55 | */ 56 | @Query("DELETE FROM daily_sleep_quality_table") 57 | suspend fun clear() 58 | 59 | /** 60 | * Selects and returns all rows in the table, 61 | * 62 | * sorted by start time in descending order. 63 | */ 64 | @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC") 65 | fun getAllNights(): LiveData> 66 | 67 | /** 68 | * Selects and returns the latest night. 69 | */ 70 | @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1") 71 | suspend fun getTonight(): SleepNight? 72 | 73 | } 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/navigation/navigation.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 25 | 26 | 31 | 36 | 37 | 38 | 43 | 46 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | Track My Sleep Quality 21 | SleepTrackerFragment 22 | SleepQualityFragment 23 | 24 | 25 | Start 26 | Stop 27 | Clear 28 | 29 | 30 | Sleep Quality 0 31 | Sleep Quality 1 32 | Sleep Quality 2 33 | Sleep Quality 3 34 | Sleep Quality 4 35 | Sleep Quality 5 36 | 37 | 38 | HERE IS YOUR SLEEP DATA]]> 39 | Start:]]> 40 | End:]]> 41 | Quality:]]> 42 | Hours:Minutes:Seconds]]> 43 | 44 | 45 | How was your sleep? 46 | Very bad 47 | Poor 48 | So-so 49 | OK 50 | Pretty good 51 | Excellent! 52 | 53 | 54 | All your data is gone forever. 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/android/trackmysleepquality/SleepDatabaseTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality 18 | 19 | import androidx.room.Room 20 | import androidx.test.ext.junit.runners.AndroidJUnit4 21 | import androidx.test.platform.app.InstrumentationRegistry 22 | import com.example.android.trackmysleepquality.database.SleepDatabase 23 | import com.example.android.trackmysleepquality.database.SleepDatabaseDao 24 | import com.example.android.trackmysleepquality.database.SleepNight 25 | import kotlinx.coroutines.runBlocking 26 | import org.junit.Assert.assertEquals 27 | import org.junit.After 28 | import org.junit.Before 29 | import org.junit.Test 30 | import org.junit.runner.RunWith 31 | import java.io.IOException 32 | 33 | /** 34 | * This is not meant to be a full set of tests. For simplicity, most of your samples do not 35 | * include tests. However, when building the Room, it is helpful to make sure it works before 36 | * adding the UI. 37 | */ 38 | 39 | @RunWith(AndroidJUnit4::class) 40 | class SleepDatabaseTest { 41 | 42 | private lateinit var sleepDao: SleepDatabaseDao 43 | private lateinit var db: SleepDatabase 44 | 45 | @Before 46 | fun createDb() { 47 | val context = InstrumentationRegistry.getInstrumentation().targetContext 48 | // Using an in-memory database because the information stored here disappears when the 49 | // process is killed. 50 | db = Room.inMemoryDatabaseBuilder(context, SleepDatabase::class.java) 51 | // Allowing main thread queries, just for testing. 52 | .allowMainThreadQueries() 53 | .build() 54 | sleepDao = db.sleepDatabaseDao 55 | } 56 | 57 | @After 58 | @Throws(IOException::class) 59 | fun closeDb() { 60 | db.close() 61 | } 62 | 63 | @Test 64 | @Throws(Exception::class) 65 | fun insertAndGetNight() = runBlocking { 66 | val night = SleepNight() 67 | sleepDao.insert(night) 68 | val tonight = sleepDao.getTonight() 69 | assertEquals(tonight?.sleepQuality, -1) 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.sleepquality 18 | 19 | import androidx.lifecycle.LiveData 20 | import androidx.lifecycle.MutableLiveData 21 | import androidx.lifecycle.ViewModel 22 | import androidx.lifecycle.viewModelScope 23 | import com.example.android.trackmysleepquality.database.SleepDatabaseDao 24 | import kotlinx.coroutines.* 25 | 26 | /** 27 | * ViewModel for SleepQualityFragment. 28 | * 29 | * @param sleepNightKey The key of the current night we are working on. 30 | */ 31 | class SleepQualityViewModel( 32 | private val sleepNightKey: Long = 0L, 33 | val database: SleepDatabaseDao) : ViewModel() { 34 | 35 | 36 | /** 37 | */ 38 | 39 | /** 40 | * 41 | * 42 | */ 43 | 44 | /** 45 | * Variable that tells the fragment whether it should navigate to [SleepTrackerFragment]. 46 | * 47 | * This is `private` because we don't want to expose the ability to set [MutableLiveData] to 48 | * the [Fragment] 49 | */ 50 | private val _navigateToSleepTracker = MutableLiveData() 51 | 52 | /** 53 | * When true immediately navigate back to the [SleepTrackerFragment] 54 | */ 55 | val navigateToSleepTracker: LiveData 56 | get() = _navigateToSleepTracker 57 | 58 | /** 59 | * 60 | */ 61 | 62 | /** 63 | * Call this immediately after navigating to [SleepTrackerFragment] 64 | */ 65 | fun doneNavigating() { 66 | _navigateToSleepTracker.value = null 67 | } 68 | 69 | /** 70 | * Sets the sleep quality and updates the database. 71 | * 72 | * Then navigates back to the SleepTrackerFragment. 73 | */ 74 | fun onSetSleepQuality(quality: Int) { 75 | viewModelScope.launch { 76 | val tonight = database.get(sleepNightKey) ?: return@launch 77 | tonight.sleepQuality = quality 78 | database.update(tonight) 79 | 80 | // Setting this state variable to true will alert the observer and trigger navigation. 81 | _navigateToSleepTracker.value = true 82 | } 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'com.android.application' 18 | apply plugin: 'kotlin-android' 19 | // Kotlin Android Extensions is deprecated, which means that using Kotlin synthetics for view binding is no longer supported. 20 | // apply plugin: 'kotlin-android-extensions' 21 | apply plugin: 'kotlin-kapt' 22 | apply plugin: 'androidx.navigation.safeargs' 23 | 24 | android { 25 | compileSdk 34 26 | defaultConfig { 27 | applicationId "com.example.android.trackmysleepquality" 28 | minSdkVersion 21 29 | targetSdkVersion 34 30 | versionCode 1 31 | versionName "1.0" 32 | multiDexEnabled true 33 | vectorDrawables.useSupportLibrary = true 34 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 35 | } 36 | buildTypes { 37 | release { 38 | minifyEnabled false 39 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 40 | } 41 | } 42 | 43 | // Enables data binding. 44 | buildFeatures { 45 | dataBinding true 46 | } 47 | namespace = "com.example.android.trackmysleepquality" 48 | 49 | compileOptions { 50 | sourceCompatibility = JavaVersion.VERSION_21 51 | targetCompatibility = JavaVersion.VERSION_21 52 | } 53 | } 54 | 55 | dependencies { 56 | implementation fileTree(dir: 'libs', include: ['*.jar']) 57 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version_kotlin" 59 | 60 | // Support libraries 61 | implementation "androidx.constraintlayout:constraintlayout:$version_constraint_layout" 62 | 63 | // Android KTX 64 | implementation "androidx.core:core-ktx:$version_core" 65 | 66 | // Room and Lifecycle dependencies 67 | implementation "androidx.room:room-runtime:$version_room" 68 | kapt "androidx.room:room-compiler:$version_room" 69 | // The APIs in lifecycle-extensions have been deprecated. Instead, add dependencies for the specific Lifecycle artifacts you need. 70 | // implementation "androidx.lifecycle:lifecycle-extensions:$version_lifecycle_extensions" 71 | 72 | // Coroutines 73 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_coroutine" 74 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_coroutine" 75 | 76 | // Navigation 77 | implementation "androidx.navigation:navigation-fragment-ktx:$version_navigation" 78 | implementation "androidx.navigation:navigation-ui-ktx:$version_navigation" 79 | 80 | // ViewModel and LiveData 81 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$version_lifecycle" 82 | 83 | // Kotlin Extensions and Coroutines support for Room 84 | implementation "androidx.room:room-ktx:$version_room" 85 | 86 | 87 | // Testing 88 | testImplementation 'junit:junit:4.13.2' 89 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 90 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 91 | } 92 | 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.sleepquality 18 | 19 | import android.os.Bundle 20 | import android.view.LayoutInflater 21 | import android.view.View 22 | import android.view.ViewGroup 23 | import androidx.databinding.DataBindingUtil 24 | import androidx.fragment.app.Fragment 25 | import androidx.lifecycle.Observer 26 | import androidx.lifecycle.ViewModelProvider 27 | import androidx.navigation.fragment.findNavController 28 | import com.example.android.trackmysleepquality.R 29 | import com.example.android.trackmysleepquality.database.SleepDatabase 30 | import com.example.android.trackmysleepquality.databinding.FragmentSleepQualityBinding 31 | 32 | /** 33 | * Fragment that displays a list of clickable icons, 34 | * each representing a sleep quality rating. 35 | * Once the user taps an icon, the quality is set in the current sleepNight 36 | * and the database is updated. 37 | */ 38 | class SleepQualityFragment : Fragment() { 39 | 40 | /** 41 | * Called when the Fragment is ready to display content to the screen. 42 | * 43 | * This function uses DataBindingUtil to inflate R.layout.fragment_sleep_quality. 44 | */ 45 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 46 | savedInstanceState: Bundle?): View? { 47 | 48 | // Get a reference to the binding object and inflate the fragment views. 49 | val binding: FragmentSleepQualityBinding = DataBindingUtil.inflate( 50 | inflater, R.layout.fragment_sleep_quality, container, false) 51 | 52 | val application = requireNotNull(this.activity).application 53 | 54 | val arguments = SleepQualityFragmentArgs.fromBundle(arguments!!) 55 | 56 | // Create an instance of the ViewModel Factory. 57 | val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao 58 | val viewModelFactory = SleepQualityViewModelFactory(arguments.sleepNightKey, dataSource) 59 | 60 | // Get a reference to the ViewModel associated with this fragment. 61 | val sleepQualityViewModel = 62 | ViewModelProvider( 63 | this, viewModelFactory).get(SleepQualityViewModel::class.java) 64 | 65 | // To use the View Model with data binding, you have to explicitly 66 | // give the binding object a reference to it. 67 | binding.sleepQualityViewModel = sleepQualityViewModel 68 | 69 | // Add an Observer to the state variable for Navigating when a Quality icon is tapped. 70 | sleepQualityViewModel.navigateToSleepTracker.observe(viewLifecycleOwner, Observer { 71 | if (it == true) { // Observed state is true. 72 | this.findNavController().navigate( 73 | SleepQualityFragmentDirections.actionSleepQualityFragmentToSleepTrackerFragment()) 74 | // Reset state to make sure we only navigate once, even if the device 75 | // has a configuration change. 76 | sleepQualityViewModel.doneNavigating() 77 | } 78 | }) 79 | 80 | return binding.root 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_sleep_tracker_background.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 28 | 31 | 34 | 35 | 36 | 39 | 42 | 45 | 48 | 49 | 50 | 51 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/values/font_certs.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | @array/com_google_android_gms_fonts_certs_dev 20 | @array/com_google_android_gms_fonts_certs_prod 21 | 22 | 23 | 24 | MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs= 25 | 26 | 27 | 28 | 29 | MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/Util.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality 18 | 19 | import android.annotation.SuppressLint 20 | import android.content.res.Resources 21 | import android.os.Build 22 | import android.text.Html 23 | import android.text.Spanned 24 | import androidx.core.text.HtmlCompat 25 | import com.example.android.trackmysleepquality.database.SleepNight 26 | import java.text.SimpleDateFormat 27 | 28 | /** 29 | * These functions create a formatted string that can be set in a TextView. 30 | */ 31 | 32 | /** 33 | * Returns a string representing the numeric quality rating. 34 | */ 35 | fun convertNumericQualityToString(quality: Int, resources: Resources): String { 36 | var qualityString = resources.getString(R.string.three_ok) 37 | when (quality) { 38 | -1 -> qualityString = "--" 39 | 0 -> qualityString = resources.getString(R.string.zero_very_bad) 40 | 1 -> qualityString = resources.getString(R.string.one_poor) 41 | 2 -> qualityString = resources.getString(R.string.two_soso) 42 | 4 -> qualityString = resources.getString(R.string.four_pretty_good) 43 | 5 -> qualityString = resources.getString(R.string.five_excellent) 44 | } 45 | return qualityString 46 | } 47 | 48 | 49 | /** 50 | * Take the Long milliseconds returned by the system and stored in Room, 51 | * and convert it to a nicely formatted string for display. 52 | * 53 | * EEEE - Display the long letter version of the weekday 54 | * MMM - Display the letter abbreviation of the nmotny 55 | * dd-yyyy - day in month and full year numerically 56 | * HH:mm - Hours and minutes in 24hr format 57 | */ 58 | @SuppressLint("SimpleDateFormat") 59 | fun convertLongToDateString(systemTime: Long): String { 60 | return SimpleDateFormat("EEEE MMM-dd-yyyy' Time: 'HH:mm") 61 | .format(systemTime).toString() 62 | } 63 | 64 | /** 65 | * Takes a list of SleepNights and converts and formats it into one string for display. 66 | * 67 | * For display in a TextView, we have to supply one string, and styles are per TextView, not 68 | * applicable per word. So, we build a formatted string using HTML. This is handy, but we will 69 | * learn a better way of displaying this data in a future lesson. 70 | * 71 | * @param nights - List of all SleepNights in the database. 72 | * @param resources - Resources object for all the resources defined for our app. 73 | * 74 | * @return Spanned - An interface for text that has formatting attached to it. 75 | * See: https://developer.android.com/reference/android/text/Spanned 76 | */ 77 | 78 | fun formatNights(nights: List, resources: Resources): Spanned { 79 | val sb = StringBuilder() 80 | sb.apply { 81 | append(resources.getString(R.string.title)) 82 | nights.forEach { 83 | append("
") 84 | append(resources.getString(R.string.start_time)) 85 | append("\t${convertLongToDateString(it.startTimeMilli)}
") 86 | if (it.endTimeMilli != it.startTimeMilli) { 87 | append(resources.getString(R.string.end_time)) 88 | append("\t${convertLongToDateString(it.endTimeMilli)}
") 89 | append(resources.getString(R.string.quality)) 90 | append("\t${convertNumericQualityToString(it.sleepQuality, resources)}
") 91 | append(resources.getString(R.string.hours_slept)) 92 | // Hours 93 | append("\t ${it.endTimeMilli.minus(it.startTimeMilli) / 1000 / 60 / 60}:") 94 | // Minutes 95 | append("${it.endTimeMilli.minus(it.startTimeMilli) / 1000 / 60}:") 96 | // Seconds 97 | append("${it.endTimeMilli.minus(it.startTimeMilli) / 1000}

") 98 | } 99 | } 100 | } 101 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 102 | return Html.fromHtml(sb.toString(), Html.FROM_HTML_MODE_LEGACY) 103 | } else { 104 | return HtmlCompat.fromHtml(sb.toString(), HtmlCompat.FROM_HTML_MODE_LEGACY) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_sleep_tracker_foreground.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 28 | 31 | 38 | 45 | 50 | 51 | 52 | 55 | 58 | 61 | 64 | 67 | 70 | 71 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.database 18 | 19 | import android.content.Context 20 | import androidx.room.Database 21 | import androidx.room.Room 22 | import androidx.room.RoomDatabase 23 | 24 | /** 25 | * A database that stores SleepNight information. 26 | * And a global method to get access to the database. 27 | * 28 | * This pattern is pretty much the same for any database, 29 | * so you can reuse it. 30 | */ 31 | @Database(entities = [SleepNight::class], version = 1, exportSchema = false) 32 | abstract class SleepDatabase : RoomDatabase() { 33 | 34 | /** 35 | * Connects the database to the DAO. 36 | */ 37 | abstract val sleepDatabaseDao: SleepDatabaseDao 38 | 39 | /** 40 | * Define a companion object, this allows us to add functions on the SleepDatabase class. 41 | * 42 | * For example, clients can call `SleepDatabase.getInstance(context)` to instantiate 43 | * a new SleepDatabase. 44 | */ 45 | companion object { 46 | /** 47 | * INSTANCE will keep a reference to any database returned via getInstance. 48 | * 49 | * This will help us avoid repeatedly initializing the database, which is expensive. 50 | * 51 | * The value of a volatile variable will never be cached, and all writes and 52 | * reads will be done to and from the main memory. It means that changes made by one 53 | * thread to shared data are visible to other threads. 54 | */ 55 | @Volatile 56 | private var INSTANCE: SleepDatabase? = null 57 | 58 | /** 59 | * Helper function to get the database. 60 | * 61 | * If a database has already been retrieved, the previous database will be returned. 62 | * Otherwise, create a new database. 63 | * 64 | * This function is threadsafe, and callers should cache the result for multiple database 65 | * calls to avoid overhead. 66 | * 67 | * This is an example of a simple Singleton pattern that takes another Singleton as an 68 | * argument in Kotlin. 69 | * 70 | * To learn more about Singleton read the wikipedia article: 71 | * https://en.wikipedia.org/wiki/Singleton_pattern 72 | * 73 | * @param context The application context Singleton, used to get access to the filesystem. 74 | */ 75 | fun getInstance(context: Context): SleepDatabase { 76 | // Multiple threads can ask for the database at the same time, ensure we only initialize 77 | // it once by using synchronized. Only one thread may enter a synchronized block at a 78 | // time. 79 | synchronized(this) { 80 | // Copy the current value of INSTANCE to a local variable so Kotlin can smart cast. 81 | // Smart cast is only available to local variables. 82 | var instance = INSTANCE 83 | // If instance is `null` make a new database instance. 84 | if (instance == null) { 85 | instance = Room.databaseBuilder( 86 | context.applicationContext, 87 | SleepDatabase::class.java, 88 | "sleep_history_database" 89 | ) 90 | // Wipes and rebuilds instead of migrating if no Migration object. 91 | // Migration is not part of this lesson. You can learn more about 92 | // migration with Room in this blog post: 93 | // https://medium.com/androiddevelopers/understanding-migrations-with-room-f01e04b07929 94 | .fallbackToDestructiveMigration() 95 | .build() 96 | // Assign INSTANCE to the newly created database. 97 | INSTANCE = instance 98 | } 99 | // Return instance; smart cast to be non-null. 100 | return instance 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.trackmysleepquality.sleeptracker 18 | 19 | import android.os.Bundle 20 | import android.view.LayoutInflater 21 | import android.view.View 22 | import android.view.ViewGroup 23 | import androidx.databinding.DataBindingUtil 24 | import androidx.fragment.app.Fragment 25 | import androidx.lifecycle.Observer 26 | import androidx.lifecycle.ViewModelProvider 27 | import androidx.navigation.fragment.findNavController 28 | import com.example.android.trackmysleepquality.R 29 | import com.example.android.trackmysleepquality.database.SleepDatabase 30 | import com.example.android.trackmysleepquality.databinding.FragmentSleepTrackerBinding 31 | import com.google.android.material.snackbar.Snackbar 32 | 33 | /** 34 | * A fragment with buttons to record start and end times for sleep, which are saved in 35 | * a database. Cumulative data is displayed in a simple scrollable TextView. 36 | * (Because we have not learned about RecyclerView yet.) 37 | */ 38 | class SleepTrackerFragment : Fragment() { 39 | 40 | /** 41 | * Called when the Fragment is ready to display content to the screen. 42 | * 43 | * This function uses DataBindingUtil to inflate R.layout.fragment_sleep_quality. 44 | */ 45 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 46 | savedInstanceState: Bundle?): View { 47 | 48 | // Get a reference to the binding object and inflate the fragment views. 49 | val binding: FragmentSleepTrackerBinding = DataBindingUtil.inflate( 50 | inflater, R.layout.fragment_sleep_tracker, container, false) 51 | 52 | val application = requireNotNull(this.activity).application 53 | 54 | val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao 55 | 56 | val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application) 57 | 58 | val sleepTrackerViewModel = 59 | ViewModelProvider( 60 | this, viewModelFactory).get(SleepTrackerViewModel::class.java) 61 | 62 | binding.sleepTrackerViewModel = sleepTrackerViewModel 63 | 64 | // binding.setLifecycleOwner(this) 65 | binding.lifecycleOwner = this 66 | 67 | 68 | 69 | // Add an Observer on the state variable for showing a Snackbar message 70 | // when the CLEAR button is pressed. 71 | sleepTrackerViewModel.showSnackBarEvent.observe(viewLifecycleOwner, Observer { 72 | if (it == true) { // Observed state is true. 73 | Snackbar.make( 74 | binding.root, 75 | getString(R.string.cleared_message), 76 | Snackbar.LENGTH_SHORT // How long to display the message. 77 | ).show() 78 | // Reset state to make sure the snackbar is only shown once, even if the device 79 | // has a configuration change. 80 | sleepTrackerViewModel.doneShowingSnackbar() 81 | } 82 | }) 83 | 84 | // Add an Observer on the state variable for Navigating when STOP button is pressed. 85 | sleepTrackerViewModel.navigateToSleepQuality.observe(viewLifecycleOwner, Observer { night -> 86 | night?.let { 87 | // We need to get the navController from this, because button is not ready, and it 88 | // just has to be a view. For some reason, this only matters if we hit stop again 89 | // after using the back button, not if we hit stop and choose a quality. 90 | // Also, in the Navigation Editor, for Quality -> Tracker, check "Inclusive" for 91 | // popping the stack to get the correct behavior if we press stop multiple times 92 | // followed by back. 93 | // Also: https://stackoverflow.com/questions/28929637/difference-and-uses-of-oncreate-oncreateview-and-onactivitycreated-in-fra 94 | this.findNavController().navigate( 95 | SleepTrackerFragmentDirections 96 | .actionSleepTrackerFragmentToSleepQualityFragment(night.nightId)) 97 | // Reset state to make sure we only navigate once, even if the device 98 | // has a configuration change. 99 | sleepTrackerViewModel.doneNavigating() 100 | } 101 | }) 102 | 103 | return binding.root 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Room - SleepQualityTracker app 2 | 3 | This is the toy app for Lesson 6 of the [Android App Development in Kotlin course on Udacity](https://www.udacity.com/course/???). 4 | 5 | ## SleepQualityTracker 6 | 7 | The SleepQualityTracker app is a demo app that helps you collect information about your sleep. 8 | * Start time 9 | * End time 10 | * Quality 11 | * Time slept 12 | 13 | This app demonstrates the following views and techniques: 14 | * Room database 15 | * DAO 16 | * Coroutines 17 | 18 | It also uses and builds on the following techniques from previous lessons: 19 | * Transformation map 20 | * Data Binding in XML files 21 | * ViewModel Factory 22 | * Using Backing Properties to protect MutableLiveData 23 | * Observable state LiveData variables to trigger navigation 24 | 25 | ## Screenshots 26 | 27 | ![Screenshot1](screenshots/sleep_quality_tracker_start.png) 28 | ![Screenshot2](screenshots/sleep_quality_tracker_stop.png) 29 | ![Screenshot3](screenshots/sleep_quality_tracker_quality.png) 30 | 31 | ## How to use this repo while taking the course 32 | 33 | 34 | Each code repository in this class has a chain of commits that looks like this: 35 | 36 | ![listofcommits](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58befe2e_listofcommits/listofcommits.png) 37 | 38 | These commits show every step you'll take to create the app. Each commit contains instructions for completing the that step. 39 | 40 | Each commit also has a **branch** associated with it of the same name as the commit message, as seen below: 41 | 42 | ![branches](https://d17h27t6h515a5.cloudfront.net/topher/2017/April/590390fe_branches-ud855/branches-ud855.png 43 | ) 44 | Access all branches from this tab. 45 | 46 | ![listofbranches](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58befe76_listofbranches/listofbranches.png 47 | ) 48 | 49 | 50 | ![branchesdropdown](https://d17h27t6h515a5.cloudfront.net/topher/2017/April/590391a3_branches-dropdown-ud855/branches-dropdown-ud855.png 51 | ) 52 | 53 | The branches are also accessible from the drop-down in the "Code" tab. 54 | 55 | ## Requirements 56 | 57 | 1. Android Studio (Jellyfish or above) 58 | 2. JDK 21 with `JAVA_HOME` environment variable set. If you don't have JDK 21 installed or `JAVA_HOME` is not set, consider using a tool like `sdkman` to simplify the process. Refer to the sdkman documentation for installation instructions: [sdkman installation](https://sdkman.io/install) 59 | 60 | ## Working with the Course Code 61 | 62 | Here are the basic steps for working with and completing exercises in the repo. 63 | 64 | The basic steps are: 65 | 66 | 1. Clone the repo. 67 | 2. Check out the branch corresponding to the step you want to attempt. 68 | 3. Find and complete the TODOs. 69 | 4. Optionally commit your code changes. 70 | 5. Compare your code with the solution. 71 | 6. Repeat steps 2-5 until you've gone trough all the steps to complete the toy app. 72 | 73 | 74 | **Step 1: Clone the repo** 75 | 76 | As you go through the course, you'll be instructed to clone the different exercise repositories, so you don't need to set these up now. You can clone a repository from github in a folder of your choice with the command: 77 | 78 | ```bash 79 | git clone https://github.com/udacity/REPOSITORY_NAME.git 80 | ``` 81 | 82 | **Step 2: Check out the step branch** 83 | 84 | As you go through different steps in the code, you'll be told which step you're on, as well as a link to the corresponding branch. 85 | 86 | You'll want to check out the branch associated with that step. The command to check out a branch would be: 87 | 88 | ```bash 89 | git checkout BRANCH_NAME 90 | ``` 91 | 92 | **Step 3: Find and complete the TODOs** 93 | 94 | Once you've checked out the branch, you'll have the code in the exact state you need. You'll even have TODOs, which are special comments that tell you all the steps you need to complete the exercise. You can easily navigate to all the TODOs using Android Studio's TODO tool. To open the TODO tool, click the button at the bottom of the screen that says TODO. This will display a list of all comments with TODO in the project. 95 | 96 | We've numbered the TODO steps so you can do them in order: 97 | ![todos](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58bf00e7_todos/todos.png 98 | ) 99 | 100 | **Step 4: Commit your code changes** 101 | 102 | After You've completed the TODOs, you can optionally commit your changes. This will allow you to see the code you wrote whenever you return to the branch. The following git code will add and save **all** your changes. 103 | 104 | ```bash 105 | git add . 106 | git commit -m "Your commit message" 107 | ``` 108 | 109 | **Step 5: Compare with the solution** 110 | 111 | Most exercises will have a list of steps for you to check off in the classroom. Once you've checked these off, you'll see a pop up window with a link to the solution code. Note the **Diff** link: 112 | 113 | ![solutionwindow](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58bf00f9_solutionwindow/solutionwindow.png 114 | ) 115 | 116 | The **Diff** link will take you to a Github diff as seen below: 117 | ![diff](https://d17h27t6h515a5.cloudfront.net/topher/2017/March/58bf0108_diffsceenshot/diffsceenshot.png 118 | ) 119 | 120 | All of the code that was added in the solution is in green, and the removed code (which will usually be the TODO comments) is in red. 121 | 122 | You can also compare your code locally with the branch of the following step. 123 | 124 | ## Report Issues 125 | Notice any issues with a repository? Please file a github issue in the repository. 126 | 127 | 128 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_sleep_tracker.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 21 | 22 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 37 | 38 | 41 | 42 | 50 | 51 | 54 | 55 | 63 | 64 | 65 | 68 | 69 |