From dc1515f6208748325896f10db46fc35315ce4321 Mon Sep 17 00:00:00 2001 From: impactrudia Date: Tue, 22 Feb 2022 17:20:24 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat=20:=20viewModel=20=EC=9D=B4=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=84=A3?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GuessTheWord-Starter/app/build.gradle | 3 + .../guesstheword/screens/game/GameFragment.kt | 87 ++++++------------- .../screens/game/GameViewModel.kt | 80 +++++++++++++++++ .../screens/score/ScoreFragment.kt | 8 ++ .../screens/score/ScoreViewModel.kt | 13 +++ .../screens/score/ScoreViewModelFactory.kt | 14 +++ 6 files changed, 145 insertions(+), 60 deletions(-) create mode 100644 GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameViewModel.kt create mode 100644 GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModel.kt create mode 100644 GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModelFactory.kt diff --git a/GuessTheWord-Starter/app/build.gradle b/GuessTheWord-Starter/app/build.gradle index b1848a1c4..710cec948 100755 --- a/GuessTheWord-Starter/app/build.gradle +++ b/GuessTheWord-Starter/app/build.gradle @@ -56,4 +56,7 @@ dependencies { // Navigation implementation "androidx.navigation:navigation-fragment-ktx:2.3.0" implementation "androidx.navigation:navigation-ui-ktx:2.3.0" + + //ViewModel + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' } diff --git a/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameFragment.kt b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameFragment.kt index 57d8b72ac..ad3f78b70 100755 --- a/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameFragment.kt +++ b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameFragment.kt @@ -17,11 +17,15 @@ package com.example.android.guesstheword.screens.game import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.NavHostFragment import com.example.android.guesstheword.R import com.example.android.guesstheword.databinding.GameFragmentBinding @@ -30,17 +34,10 @@ import com.example.android.guesstheword.databinding.GameFragmentBinding */ class GameFragment : Fragment() { - // The current word - private var word = "" - - // The current score - private var score = 0 - - // The list of words - the front of the list is the next word to guess - private lateinit var wordList: MutableList - private lateinit var binding: GameFragmentBinding + private lateinit var viewModel: GameViewModel + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -52,79 +49,49 @@ class GameFragment : Fragment() { false ) - resetList() - nextWord() + Log.i("GameFragment", "Called ViewModelProvider.get") + viewModel = ViewModelProvider(this).get(GameViewModel::class.java) binding.correctButton.setOnClickListener { onCorrect() } binding.skipButton.setOnClickListener { onSkip() } + binding.endGameButton.setOnClickListener { onEndGame() } updateScoreText() updateWordText() return binding.root } - /** - * Resets the list of words and randomizes the order - */ - private fun resetList() { - wordList = mutableListOf( - "queen", - "hospital", - "basketball", - "cat", - "change", - "snail", - "soup", - "calendar", - "sad", - "desk", - "guitar", - "home", - "railway", - "zebra", - "jelly", - "car", - "crow", - "trade", - "bag", - "roll", - "bubble" - ) - wordList.shuffle() - } - - /** Methods for buttons presses **/ + /** Methods for button click handlers **/ private fun onSkip() { - score-- - nextWord() + viewModel.onSkip() + updateWordText() + updateScoreText() } private fun onCorrect() { - score++ - nextWord() - } - - /** - * Moves to the next word in the list - */ - private fun nextWord() { - if (!wordList.isEmpty()) { - //Select and remove a word from the list - word = wordList.removeAt(0) - } + viewModel.onCorrect() updateWordText() updateScoreText() } - /** Methods for updating the UI **/ - private fun updateWordText() { - binding.wordText.text = word + binding.wordText.text = viewModel.word } private fun updateScoreText() { - binding.scoreText.text = score.toString() + binding.scoreText.text = viewModel.score.toString() + } + + private fun onEndGame() { + gameFinished() + } + + private fun gameFinished() { + Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show() + val action = GameFragmentDirections.actionGameToScore() + action.score = viewModel.score + NavHostFragment.findNavController(this).navigate(action) } } diff --git a/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameViewModel.kt b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameViewModel.kt new file mode 100644 index 000000000..1bca08627 --- /dev/null +++ b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/game/GameViewModel.kt @@ -0,0 +1,80 @@ +package com.example.android.guesstheword.screens.game + +import android.util.Log +import androidx.lifecycle.ViewModel + +class GameViewModel : ViewModel() { + + // The current word + var word = "" + + // The current score + var score = 0 + + // The list of words - the front of the list is the next word to guess + private lateinit var wordList: MutableList + + /** + * Resets the list of words and randomizes the order + */ + fun resetList() { + wordList = mutableListOf( + "queen", + "hospital", + "basketball", + "cat", + "change", + "snail", + "soup", + "calendar", + "sad", + "desk", + "guitar", + "home", + "railway", + "zebra", + "jelly", + "car", + "crow", + "trade", + "bag", + "roll", + "bubble" + ) + wordList.shuffle() + } + + + init { + resetList() + nextWord() + Log.i("GameViewModel", "GameViewModel created!") + } + + /** + * Moves to the next word in the list + */ + private fun nextWord() { + if (!wordList.isEmpty()) { + //Select and remove a word from the list + word = wordList.removeAt(0) + } + + } + + /** Methods for buttons presses **/ + fun onSkip() { + score-- + nextWord() + } + + fun onCorrect() { + score++ + nextWord() + } + + override fun onCleared() { + super.onCleared() + Log.i("GameViewModel", "GameViewModel destroyed!!") + } +} \ No newline at end of file diff --git a/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreFragment.kt b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreFragment.kt index 4962b73ea..5dd914abe 100755 --- a/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreFragment.kt +++ b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreFragment.kt @@ -22,6 +22,7 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.navArgs import com.example.android.guesstheword.R import com.example.android.guesstheword.databinding.ScoreFragmentBinding @@ -31,6 +32,9 @@ import com.example.android.guesstheword.databinding.ScoreFragmentBinding */ class ScoreFragment : Fragment() { + private lateinit var viewModel: ScoreViewModel + private lateinit var viewModelFactory: ScoreViewModelFactory + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -45,6 +49,10 @@ class ScoreFragment : Fragment() { false ) + viewModelFactory = ScoreViewModelFactory(ScoreFragmentArgs.fromBundle(requireArguments()).score) + viewModel = ViewModelProvider(this, viewModelFactory).get(ScoreViewModel::class.java) + + binding.scoreText.text = viewModel.score.toString() return binding.root } } diff --git a/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModel.kt b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModel.kt new file mode 100644 index 000000000..0bed049b9 --- /dev/null +++ b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModel.kt @@ -0,0 +1,13 @@ +package com.example.android.guesstheword.screens.score + +import android.util.Log +import androidx.lifecycle.ViewModel + +class ScoreViewModel(finalScore: Int) : ViewModel() { + // The final score + var score = finalScore + + init { + Log.i("ScoreViewModel", "Final score is $finalScore") + } +} \ No newline at end of file diff --git a/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModelFactory.kt b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModelFactory.kt new file mode 100644 index 000000000..73d0c2d56 --- /dev/null +++ b/GuessTheWord-Starter/app/src/main/java/com/example/android/guesstheword/screens/score/ScoreViewModelFactory.kt @@ -0,0 +1,14 @@ +package com.example.android.guesstheword.screens.score + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +class ScoreViewModelFactory(private val finalScore: Int) : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + if(modelClass.isAssignableFrom(ScoreViewModel::class.java)) { + return ScoreViewModel(finalScore) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} \ No newline at end of file From ff8944b31d5bacc19bdfc1fa25a53187e5603d7d Mon Sep 17 00:00:00 2001 From: impactrudia Date: Wed, 23 Feb 2022 22:08:48 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat=20:=20database=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=ED=95=B4=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trackmysleepquality/SleepDatabaseTest.kt | 108 +++++++++--------- .../database/SleepDatabase.kt | 32 ++++++ .../database/SleepDatabaseDao.kt | 24 +++- .../database/SleepNight.kt | 15 +++ 4 files changed, 124 insertions(+), 55 deletions(-) diff --git a/TrackMySleepQuality-Starter/app/src/androidTest/java/com/example/android/trackmysleepquality/SleepDatabaseTest.kt b/TrackMySleepQuality-Starter/app/src/androidTest/java/com/example/android/trackmysleepquality/SleepDatabaseTest.kt index 1e5d85669..5e857eeb4 100755 --- a/TrackMySleepQuality-Starter/app/src/androidTest/java/com/example/android/trackmysleepquality/SleepDatabaseTest.kt +++ b/TrackMySleepQuality-Starter/app/src/androidTest/java/com/example/android/trackmysleepquality/SleepDatabaseTest.kt @@ -15,57 +15,57 @@ */ package com.example.android.trackmysleepquality -// -//import androidx.room.Room -//import androidx.test.ext.junit.runners.AndroidJUnit4 -//import androidx.test.platform.app.InstrumentationRegistry -//import com.example.android.trackmysleepquality.database.SleepDatabase -//import com.example.android.trackmysleepquality.database.SleepDatabaseDao -//import com.example.android.trackmysleepquality.database.SleepNight -//import org.junit.Assert.assertEquals -//import org.junit.After -//import org.junit.Before -//import org.junit.Test -//import org.junit.runner.RunWith -//import java.io.IOException -// -// -///** -// * This is not meant to be a full set of tests. For simplicity, most of your samples do not -// * include tests. However, when building the Room, it is helpful to make sure it works before -// * adding the UI. -// */ -// -//@RunWith(AndroidJUnit4::class) -//class SleepDatabaseTest { -// -// private lateinit var sleepDao: SleepDatabaseDao -// private lateinit var db: SleepDatabase -// -// @Before -// fun createDb() { -// val context = InstrumentationRegistry.getInstrumentation().targetContext -// // Using an in-memory database because the information stored here disappears when the -// // process is killed. -// db = Room.inMemoryDatabaseBuilder(context, SleepDatabase::class.java) -// // Allowing main thread queries, just for testing. -// .allowMainThreadQueries() -// .build() -// sleepDao = db.sleepDatabaseDao -// } -// -// @After -// @Throws(IOException::class) -// fun closeDb() { -// db.close() -// } -// -// @Test -// @Throws(Exception::class) -// fun insertAndGetNight() { -// val night = SleepNight() -// sleepDao.insert(night) -// val tonight = sleepDao.getTonight() -// assertEquals(tonight?.sleepQuality, -1) -// } -//} \ No newline at end of file + +import androidx.room.Room +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.example.android.trackmysleepquality.database.SleepDatabase +import com.example.android.trackmysleepquality.database.SleepDatabaseDao +import com.example.android.trackmysleepquality.database.SleepNight +import org.junit.Assert.assertEquals +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import java.io.IOException + + +/** + * This is not meant to be a full set of tests. For simplicity, most of your samples do not + * include tests. However, when building the Room, it is helpful to make sure it works before + * adding the UI. + */ + +@RunWith(AndroidJUnit4::class) +class SleepDatabaseTest { + + private lateinit var sleepDao: SleepDatabaseDao + private lateinit var db: SleepDatabase + + @Before + fun createDb() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + // Using an in-memory database because the information stored here disappears when the + // process is killed. + db = Room.inMemoryDatabaseBuilder(context, SleepDatabase::class.java) + // Allowing main thread queries, just for testing. + .allowMainThreadQueries() + .build() + sleepDao = db.sleepDatabaseDao + } + + @After + @Throws(IOException::class) + fun closeDb() { + db.close() + } + + @Test + @Throws(Exception::class) + fun insertAndGetNight() { + val night = SleepNight() + sleepDao.insert(night) + val tonight = sleepDao.getTonight() + assertEquals(tonight?.sleepQuality, -1) + } +} \ No newline at end of file diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt index f29a7d352..474fc6010 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt @@ -15,3 +15,35 @@ */ package com.example.android.trackmysleepquality.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database(entities = [SleepNight::class], version = 1, exportSchema = false) +abstract class SleepDatabase : RoomDatabase() { + abstract val sleepDatabaseDao: SleepDatabaseDao + + companion object { + @Volatile + private var INSTANCE: SleepDatabase? = null + + fun getInstance(context: Context): SleepDatabase { + synchronized(this) { + var instance = INSTANCE + + if (instance == null) { + instance = Room.databaseBuilder( + context.applicationContext, + SleepDatabase::class.java, + "sleep_history_database" + ).fallbackToDestructiveMigration() + .build() + INSTANCE = instance + } + return instance + } + } + } +} diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt index 6410761f3..ba3d29a2e 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabaseDao.kt @@ -16,7 +16,29 @@ package com.example.android.trackmysleepquality.database +import androidx.lifecycle.LiveData import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update @Dao -interface SleepDatabaseDao +interface SleepDatabaseDao { + @Insert + fun insert(night: SleepNight) + + @Update + fun update(night: SleepNight) + + @Query("SELECT * from daily_sleep_quality_table WHERE nightId = :key") + fun get(key: Long): SleepNight? + + @Query("DELETE FROM daily_sleep_quality_table") + fun clear() + + @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1") + fun getTonight(): SleepNight? + + @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC") + fun getAllNights(): LiveData> +} diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt index e80e4b70b..fa06e0a50 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepNight.kt @@ -16,3 +16,18 @@ package com.example.android.trackmysleepquality.database +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@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 +) \ No newline at end of file From 00865ae1a76b7a8490589849d9e0d2202ffa7607 Mon Sep 17 00:00:00 2001 From: impactrudia Date: Fri, 25 Feb 2022 05:01:05 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat=20:=20viewmodel=20dao=20=EB=B6=99?= =?UTF-8?q?=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TrackMySleepQuality-Starter/app/build.gradle | 5 ++ .../database/SleepDatabase.kt | 4 +- .../sleepquality/SleepQualityViewModel.kt | 5 ++ .../SleepQualityViewModelFactory.kt | 13 ++++ .../sleeptracker/SleepTrackerFragment.kt | 25 ++++++- .../sleeptracker/SleepTrackerViewModel.kt | 71 ++++++++++++++++++- .../res/layout/fragment_sleep_tracker.xml | 37 ++++++++-- 7 files changed, 147 insertions(+), 13 deletions(-) diff --git a/TrackMySleepQuality-Starter/app/build.gradle b/TrackMySleepQuality-Starter/app/build.gradle index 25ed8d70e..1dacb3cae 100755 --- a/TrackMySleepQuality-Starter/app/build.gradle +++ b/TrackMySleepQuality-Starter/app/build.gradle @@ -80,5 +80,10 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" + + // Kotlin Extensions and Coroutines support for Room + implementation "androidx.room:room-ktx:$room_version" } diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt index 474fc6010..3be0ce071 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/database/SleepDatabase.kt @@ -38,7 +38,9 @@ abstract class SleepDatabase : RoomDatabase() { context.applicationContext, SleepDatabase::class.java, "sleep_history_database" - ).fallbackToDestructiveMigration() + ) + .fallbackToDestructiveMigration() + .allowMainThreadQueries() .build() INSTANCE = instance } diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt index e66449235..f44abb05f 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModel.kt @@ -15,3 +15,8 @@ */ package com.example.android.trackmysleepquality.sleepquality + +import androidx.lifecycle.ViewModel + +class SleepQualityViewModel : ViewModel() { +} \ No newline at end of file diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt index e66449235..44d027b83 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleepquality/SleepQualityViewModelFactory.kt @@ -15,3 +15,16 @@ */ package com.example.android.trackmysleepquality.sleepquality + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +class SleepQualityViewModelFactory : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(SleepQualityViewModel::class.java)) { + return SleepQualityViewModel() as T + } + throw IllegalArgumentException("Unknown viewModel class") + } +} \ No newline at end of file diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt index d395f78e9..7e548b8ba 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerFragment.kt @@ -22,7 +22,9 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider import com.example.android.trackmysleepquality.R +import com.example.android.trackmysleepquality.database.SleepDatabase import com.example.android.trackmysleepquality.databinding.FragmentSleepTrackerBinding /** @@ -37,12 +39,29 @@ class SleepTrackerFragment : Fragment() { * * This function uses DataBindingUtil to inflate R.layout.fragment_sleep_quality. */ - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { + 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) + inflater, R.layout.fragment_sleep_tracker, container, false + ) + + val application = requireNotNull(this.activity).application + + val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao + + val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application) + + val sleepTrackerViewModel = + ViewModelProvider( + this, viewModelFactory + ).get(SleepTrackerViewModel::class.java) + + binding.lifecycleOwner = this + binding.sleepTrackerViewModel = sleepTrackerViewModel return binding.root } diff --git a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt index 77fe6e337..3d59770a5 100755 --- a/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt +++ b/TrackMySleepQuality-Starter/app/src/main/java/com/example/android/trackmysleepquality/sleeptracker/SleepTrackerViewModel.kt @@ -18,13 +18,80 @@ package com.example.android.trackmysleepquality.sleeptracker import android.app.Application import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Transformations +import androidx.lifecycle.viewModelScope import com.example.android.trackmysleepquality.database.SleepDatabaseDao +import com.example.android.trackmysleepquality.database.SleepNight +import kotlinx.coroutines.launch /** * ViewModel for SleepTrackerFragment. */ class SleepTrackerViewModel( - val database: SleepDatabaseDao, - application: Application) : AndroidViewModel(application) { + val database: SleepDatabaseDao, + application: Application +) : AndroidViewModel(application) { + + private val nights = database.getAllNights() + + val nightsString = Transformations.map(nights) { nights -> + "${nights.toString()}"// formatNights(nights, application.resources) + } + + private var tonight = MutableLiveData() + + init { + initializeTonight() + } + + private fun initializeTonight() { + viewModelScope.launch { +// tonight.value = getTonightFromDatabase() + } + } + + private suspend fun getTonightFromDatabase(): SleepNight? { + var night: SleepNight? = database.getTonight() ?: return null + if (night?.endTimeMilli != night?.startTimeMilli) { + night = null + } + return night + } + + fun onStartTracking() { + viewModelScope.launch { + val newNight = SleepNight() + insert(newNight) + tonight.value = getTonightFromDatabase() + } + } + + private suspend fun insert(night: SleepNight) { + database.insert(night) + } + + fun onStopTracking() { + viewModelScope.launch { + val oldNight = tonight.value ?: return@launch + oldNight.endTimeMilli = System.currentTimeMillis() + update(oldNight) + } + } + + private suspend fun update(night: SleepNight) { + database.update(night) + } + + fun onClear() { + viewModelScope.launch { + clear() + tonight.value = null + } + } + + suspend fun clear() { + database.clear() + } } diff --git a/TrackMySleepQuality-Starter/app/src/main/res/layout/fragment_sleep_tracker.xml b/TrackMySleepQuality-Starter/app/src/main/res/layout/fragment_sleep_tracker.xml index a54e99e5d..e5515fe56 100755 --- a/TrackMySleepQuality-Starter/app/src/main/res/layout/fragment_sleep_tracker.xml +++ b/TrackMySleepQuality-Starter/app/src/main/res/layout/fragment_sleep_tracker.xml @@ -24,6 +24,9 @@ click handlers, and state variables. --> + @@ -49,14 +52,30 @@ which keeps it displayed and updated in the TextView whenever it changes. --> - + android:orientation="vertical"> + + + + + +