From fe85497aa9545ca042dabb6f7776d298aff5dc86 Mon Sep 17 00:00:00 2001 From: Gertjan Bosteels Date: Mon, 15 Nov 2021 10:55:03 +0100 Subject: [PATCH 1/6] adds database + adds joke count in db + instantiate db in JokeViewModel --- JokeApp/app/build.gradle | 6 +- .../com/example/jokeapp/JokeDatabaseTest.kt | 58 +++++++++++++++++++ .../example/jokeapp/database/jokes/Joke.kt | 21 +++++++ .../jokeapp/database/jokes/JokeDatabase.kt | 36 ++++++++++++ .../jokeapp/database/jokes/JokeDatabaseDao.kt | 36 ++++++++++++ .../jokeapp/screens/jokes/JokeFragment.kt | 13 ++++- .../jokeapp/screens/jokes/JokeViewModel.kt | 47 ++++++++++++--- .../screens/jokes/JokeViewModelFactory.kt | 15 +++++ .../app/src/main/res/layout/fragment_joke.xml | 10 ++++ 9 files changed, 231 insertions(+), 11 deletions(-) create mode 100644 JokeApp/app/src/androidTest/java/com/example/jokeapp/JokeDatabaseTest.kt create mode 100644 JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/Joke.kt create mode 100644 JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabase.kt create mode 100644 JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt create mode 100644 JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModelFactory.kt diff --git a/JokeApp/app/build.gradle b/JokeApp/app/build.gradle index b66e789..0730b58 100644 --- a/JokeApp/app/build.gradle +++ b/JokeApp/app/build.gradle @@ -50,15 +50,18 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.0' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.test.ext:junit-ktx:1.1.3' + implementation 'androidx.room:room-common:2.3.0' + implementation 'androidx.room:room-ktx:2.3.0' testImplementation 'junit:junit:4.+' testImplementation 'org.hamcrest:hamcrest:2.2' + testImplementation "androidx.room:room-testing:2.2.6" androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' testImplementation "org.robolectric:robolectric:4.5.1" @@ -67,6 +70,7 @@ dependencies { implementation "android.arch.navigation:navigation-ui-ktx:$version_navigation" implementation 'com.jakewharton.timber:timber:5.0.1' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + kapt "androidx.room:room-compiler:2.3.0" } diff --git a/JokeApp/app/src/androidTest/java/com/example/jokeapp/JokeDatabaseTest.kt b/JokeApp/app/src/androidTest/java/com/example/jokeapp/JokeDatabaseTest.kt new file mode 100644 index 0000000..aa11cf8 --- /dev/null +++ b/JokeApp/app/src/androidTest/java/com/example/jokeapp/JokeDatabaseTest.kt @@ -0,0 +1,58 @@ +package com.example.jokeapp + +import android.util.Log +import androidx.room.Room +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry + +import com.example.jokeapp.database.jokes.Joke +import com.example.jokeapp.database.jokes.JokeDatabase +import com.example.jokeapp.database.jokes.JokeDatabaseDao +import kotlinx.coroutines.runBlocking +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 JokeDatabaseTest { + + private lateinit var jokeDao: JokeDatabaseDao + private lateinit var db: JokeDatabase + + @Before + fun createDb() { + Log.i("before", "running before") + 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, JokeDatabase::class.java) + // Allowing main thread queries, just for testing. + .allowMainThreadQueries() + .build() + jokeDao = db.jokeDatabaseDao + } + + @After + @Throws(IOException::class) + fun closeDb() { + db.close() + } + + @Test + @Throws(Exception::class) + fun insertAndGetJoke() = runBlocking { + val joke = Joke() + jokeDao.insert(joke) + val lastJoke = jokeDao.getLastJoke() + assertEquals(lastJoke?.punchline, "") + } +} \ No newline at end of file diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/Joke.kt b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/Joke.kt new file mode 100644 index 0000000..23fb7c2 --- /dev/null +++ b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/Joke.kt @@ -0,0 +1,21 @@ +package com.example.jokeapp.database.jokes + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "custom_joke_table") +data class Joke( + @PrimaryKey(autoGenerate = true) + var jokeId: Long = 0L, + + @ColumnInfo(name = "joke_setup") + var jokeSetup: String = "", + + @ColumnInfo(name = "joke_type") + var jokeType: String = "", + + @ColumnInfo(name = "joke_punchline") + var punchline: String = "", + +) \ No newline at end of file diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabase.kt b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabase.kt new file mode 100644 index 0000000..80b6506 --- /dev/null +++ b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabase.kt @@ -0,0 +1,36 @@ +package com.example.jokeapp.database.jokes + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database(entities = [Joke::class], version = 1, exportSchema = false) +abstract class JokeDatabase : RoomDatabase() { + + abstract val jokeDatabaseDao: JokeDatabaseDao + + companion object { + + @Volatile + private var INSTANCE: JokeDatabase? = null + + fun getInstance(context: Context): JokeDatabase { + synchronized(this) { + var instance = INSTANCE + + if (instance == null) { + instance = Room.databaseBuilder( + context.applicationContext, + JokeDatabase::class.java, + "custom_joke_database" + ) + .fallbackToDestructiveMigration() + .build() + INSTANCE = instance + } + return instance + } + } + } +} \ No newline at end of file diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt new file mode 100644 index 0000000..79c23a1 --- /dev/null +++ b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt @@ -0,0 +1,36 @@ +package com.example.jokeapp.database.jokes + + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update + +/** + * Defines methods for using the SleepNight class with Room. + */ +@Dao +interface JokeDatabaseDao { + + @Insert + suspend fun insert(joke: Joke) + + @Update + suspend fun update(joke: Joke) + + @Query("SELECT * from custom_joke_table WHERE jokeId = :key") + suspend fun get(key: Long): Joke? + + @Query("DELETE FROM custom_joke_table") + suspend fun clear() + + @Query("SELECT * FROM custom_joke_table ORDER BY jokeId DESC") + fun getAllJokes(): LiveData> + + @Query("SELECT * FROM custom_joke_table ORDER BY jokeId DESC LIMIT 1") + suspend fun getLastJoke(): Joke? + + @Query("SELECT COUNT(*) FROM custom_joke_table") + suspend fun numberOfJokes(): Int +} diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt index 1e12d70..74242b3 100644 --- a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt @@ -1,5 +1,6 @@ package com.example.jokeapp.screens.jokes +import android.app.Activity import android.os.Bundle import androidx.fragment.app.Fragment import android.view.LayoutInflater @@ -10,6 +11,7 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.navigation.findNavController import com.example.jokeapp.R +import com.example.jokeapp.database.jokes.JokeDatabase import com.example.jokeapp.databinding.FragmentJokeBinding import kotlin.random.Random @@ -28,6 +30,9 @@ class JokeFragment : Fragment() { lateinit var binding: FragmentJokeBinding lateinit var viewModel : JokeViewModel + + + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -41,7 +46,13 @@ class JokeFragment : Fragment() { //It needs to be special to survive e.g. config changes //viewModel = JokeViewModel() - viewModel = ViewModelProvider(this).get(JokeViewModel::class.java) + //Get an instance of the appContext to setup the database + val appContext = requireNotNull(this.activity).application + val dataSource = JokeDatabase.getInstance(appContext).jokeDatabaseDao + + //use a factory to pass the database reference to the viewModel + val viewModelFactory = JokeViewModelFactory(dataSource, appContext) + viewModel = ViewModelProvider(this, viewModelFactory).get(JokeViewModel::class.java) binding.jokes = viewModel diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt index a2663f9..14ca995 100644 --- a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt @@ -1,17 +1,20 @@ package com.example.jokeapp.screens.jokes -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel +import android.app.Activity +import android.app.Application +import androidx.lifecycle.* +import com.example.jokeapp.database.jokes.JokeDatabase +import com.example.jokeapp.database.jokes.JokeDatabaseDao +import kotlinx.coroutines.launch import timber.log.Timber import kotlin.random.Random -class JokeViewModel: ViewModel() { +class JokeViewModel(val database: JokeDatabaseDao, application: Application): AndroidViewModel(application) { var happyJokes = 0 var badJokes = 0 - private val jokes = listOf( + /*private val jokes = listOf( "My wife said I should do lunges to stay in shape. That would be a big step forward.", "I thought the dryer was shrinking my clothes. Turns out it was the refrigerator all along", "I only know 25 letters of the alphabet. I don't know y.", @@ -19,7 +22,16 @@ class JokeViewModel: ViewModel() { "This graveyard looks overcrowded. People must be dying to get in.", "I have a joke about chemistry, but I don't think it will get a reaction.", "I used to be addicted to soap, but I'm clean now." - ) + )*/ + + //Jokes will be a livedata field because the db returns it as livedata + private val jokes = database.getAllJokes() + //numberOfJokes is no livedata yet --> wrap it in livedata here. + private val numberOfJokes = MutableLiveData() + + val numberOfJokesString = Transformations.map(numberOfJokes){ + number -> number.toString() + } private val _currentJoke = MutableLiveData() val currentJoke: LiveData @@ -35,9 +47,16 @@ class JokeViewModel: ViewModel() { init { Timber.i("init is called") + initializeLiveDataFields() changeCurrentJoke() } + private fun initializeLiveDataFields(){ + viewModelScope.launch{ + numberOfJokes.value = getNumberOfJokesFromDatabase() + } + } + fun changeCurrentJoke() { //Check for evaluation: if (happyJokes + badJokes == 3){ @@ -46,10 +65,16 @@ class JokeViewModel: ViewModel() { return } - var randomListNumber = Random.nextInt(jokes.size) - if(_currentJoke.value == jokes[randomListNumber]) randomListNumber = randomListNumber.plus(1).mod(jokes.size) + if(numberOfJokes.value == null) return + + //don't change the joke if there are no jokes + if(numberOfJokes.value!! == 0) return + + var randomListNumber = Random.nextInt(numberOfJokes.value!!) + //use the livedata joke list to get a random joke + if(_currentJoke.value == jokes.value?.get(randomListNumber)?.punchline) randomListNumber = randomListNumber.plus(1).mod(numberOfJokes.value!!) //use mod to stay in the correct range - _currentJoke.value = jokes[randomListNumber] + _currentJoke.value = jokes.value?.get(randomListNumber)?.punchline } fun evaluationComplete(){ @@ -84,4 +109,8 @@ class JokeViewModel: ViewModel() { + //Suspend functions + private suspend fun getNumberOfJokesFromDatabase(): Int{ + return database.numberOfJokes() + } } \ No newline at end of file diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModelFactory.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModelFactory.kt new file mode 100644 index 0000000..fb820ef --- /dev/null +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModelFactory.kt @@ -0,0 +1,15 @@ +package com.example.jokeapp.screens.jokes + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.jokeapp.database.jokes.JokeDatabaseDao + +class JokeViewModelFactory(private val dataSource: JokeDatabaseDao, private val application: Application): ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if(modelClass.isAssignableFrom(JokeViewModel::class.java)) { + return JokeViewModel(dataSource, application) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/JokeApp/app/src/main/res/layout/fragment_joke.xml b/JokeApp/app/src/main/res/layout/fragment_joke.xml index 5b1eb35..f7f133d 100644 --- a/JokeApp/app/src/main/res/layout/fragment_joke.xml +++ b/JokeApp/app/src/main/res/layout/fragment_joke.xml @@ -73,6 +73,16 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/nextjoke_button" /> + + From 684edc6767a749d412a6a4ebf98c0a33306e224e Mon Sep 17 00:00:00 2001 From: Gertjan Bosteels Date: Mon, 15 Nov 2021 13:12:34 +0100 Subject: [PATCH 2/6] adds addJokeFragment + adds reading joke from database --- JokeApp/app/build.gradle | 2 +- .../jokeapp/database/jokes/JokeDatabaseDao.kt | 2 +- .../screens/addJoke/AddJokeFragment.kt | 64 +++++++++++++++++++ .../screens/addJoke/AddJokeViewModel.kt | 39 +++++++++++ .../addJoke/AddJokeViewModelFactory.kt | 16 +++++ .../jokeapp/screens/jokes/JokeFragment.kt | 6 +- .../jokeapp/screens/jokes/JokeViewModel.kt | 32 ++++++++-- .../src/main/res/layout/fragment_add_joke.xml | 50 +++++++++++++++ .../app/src/main/res/layout/fragment_joke.xml | 13 ++++ .../src/main/res/navigation/navigation.xml | 11 ++++ JokeApp/build.gradle | 2 +- 11 files changed, 226 insertions(+), 11 deletions(-) create mode 100644 JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeFragment.kt create mode 100644 JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModel.kt create mode 100644 JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModelFactory.kt create mode 100644 JokeApp/app/src/main/res/layout/fragment_add_joke.xml diff --git a/JokeApp/app/build.gradle b/JokeApp/app/build.gradle index 0730b58..85e4bc2 100644 --- a/JokeApp/app/build.gradle +++ b/JokeApp/app/build.gradle @@ -19,7 +19,7 @@ android { targetSdk 30 versionCode 1 versionName "1.0" - + multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt index 79c23a1..5af5b0c 100644 --- a/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt +++ b/JokeApp/app/src/main/java/com/example/jokeapp/database/jokes/JokeDatabaseDao.kt @@ -26,7 +26,7 @@ interface JokeDatabaseDao { suspend fun clear() @Query("SELECT * FROM custom_joke_table ORDER BY jokeId DESC") - fun getAllJokes(): LiveData> + suspend fun getAllJokes(): List @Query("SELECT * FROM custom_joke_table ORDER BY jokeId DESC LIMIT 1") suspend fun getLastJoke(): Joke? diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeFragment.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeFragment.kt new file mode 100644 index 0000000..115b485 --- /dev/null +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeFragment.kt @@ -0,0 +1,64 @@ +package com.example.jokeapp.screens.addJoke + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.findNavController +import com.example.jokeapp.R +import com.example.jokeapp.database.jokes.JokeDatabase +import com.example.jokeapp.databinding.FragmentAddJokeBinding +import com.example.jokeapp.screens.jokes.JokeFragmentDirections +import com.example.jokeapp.screens.jokes.JokeViewModelFactory + +class AddJokeFragment : Fragment() { + + lateinit var binding : FragmentAddJokeBinding + lateinit var viewModel : AddJokeViewModel + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_add_joke, container, false) + + //Not OK: don't call the viewModel like a normal class. + //It needs to be special to survive e.g. config changes + //viewModel = JokeViewModel() + + //Get an instance of the appContext to setup the database + val appContext = requireNotNull(this.activity).application + val dataSource = JokeDatabase.getInstance(appContext).jokeDatabaseDao + + //use a factory to pass the database reference to the viewModel + val viewModelFactory = AddJokeViewModelFactory(dataSource, appContext) + viewModel = ViewModelProvider(this, viewModelFactory).get(AddJokeViewModel::class.java) + + binding.viewModel = viewModel + + //this call allows to automatically update the livedata + //Meaning: no more resets or whatsoever + binding.setLifecycleOwner (this) + + viewModel.saveEvent.observe(viewLifecycleOwner, Observer { + saveEvent -> if(saveEvent){ + viewModel.saveJoke(binding.editTextTextPersonName.text.toString()) + //navigate back to the joke screen + view?.findNavController()?.navigate(AddJokeFragmentDirections.actionAddJokeFragmentToJokeFragment()) + + viewModel.saveEventDone() + } + }) + + + return binding.root + + } + +} \ No newline at end of file diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModel.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModel.kt new file mode 100644 index 0000000..e8ac59e --- /dev/null +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModel.kt @@ -0,0 +1,39 @@ +package com.example.jokeapp.screens.addJoke + +import android.app.Application +import androidx.lifecycle.* +import com.example.jokeapp.database.jokes.Joke +import com.example.jokeapp.database.jokes.JokeDatabaseDao +import kotlinx.coroutines.launch + +class AddJokeViewModel(val database: JokeDatabaseDao, application: Application): AndroidViewModel(application) { + + private val _saveEvent = MutableLiveData() + val saveEvent: LiveData + get() = _saveEvent + + init { + _saveEvent.value = false + } + + fun saveJokeClick(){ + _saveEvent.value = true + } + + fun saveEventDone(){ + _saveEvent.value = false + } + + fun saveJoke(newJoke : String){ + viewModelScope.launch{ + val joke = Joke() + joke.punchline = newJoke + saveJokeToDatabase(joke) + } + } + + //suspend methods + suspend fun saveJokeToDatabase(newJoke: Joke){ + database.insert(newJoke) + } +} \ No newline at end of file diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModelFactory.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModelFactory.kt new file mode 100644 index 0000000..f70551a --- /dev/null +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/addJoke/AddJokeViewModelFactory.kt @@ -0,0 +1,16 @@ +package com.example.jokeapp.screens.addJoke + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.jokeapp.database.jokes.JokeDatabaseDao + +class AddJokeViewModelFactory (private val dataSource: JokeDatabaseDao, private val application: Application): ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if(modelClass.isAssignableFrom(AddJokeViewModel::class.java)) { + return AddJokeViewModel(dataSource, application) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } + +} \ No newline at end of file diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt index 74242b3..ba6127e 100644 --- a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeFragment.kt @@ -9,6 +9,7 @@ import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider +import androidx.navigation.Navigation import androidx.navigation.findNavController import com.example.jokeapp.R import com.example.jokeapp.database.jokes.JokeDatabase @@ -32,7 +33,6 @@ class JokeFragment : Fragment() { - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -82,6 +82,10 @@ class JokeFragment : Fragment() { } }) + binding.addJokeButton.setOnClickListener( + Navigation.createNavigateOnClickListener(R.id.addJokeFragment) + ) + return binding.root } diff --git a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt index 14ca995..a148370 100644 --- a/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt +++ b/JokeApp/app/src/main/java/com/example/jokeapp/screens/jokes/JokeViewModel.kt @@ -3,6 +3,7 @@ package com.example.jokeapp.screens.jokes import android.app.Activity import android.app.Application import androidx.lifecycle.* +import com.example.jokeapp.database.jokes.Joke import com.example.jokeapp.database.jokes.JokeDatabase import com.example.jokeapp.database.jokes.JokeDatabaseDao import kotlinx.coroutines.launch @@ -25,7 +26,7 @@ class JokeViewModel(val database: JokeDatabaseDao, application: Application): An )*/ //Jokes will be a livedata field because the db returns it as livedata - private val jokes = database.getAllJokes() + private lateinit var jokes: List //numberOfJokes is no livedata yet --> wrap it in livedata here. private val numberOfJokes = MutableLiveData() @@ -33,6 +34,7 @@ class JokeViewModel(val database: JokeDatabaseDao, application: Application): An number -> number.toString() } + private val _currentJoke = MutableLiveData() val currentJoke: LiveData get() = _currentJoke @@ -47,11 +49,17 @@ class JokeViewModel(val database: JokeDatabaseDao, application: Application): An init { Timber.i("init is called") - initializeLiveDataFields() - changeCurrentJoke() + initializeLiveData() + + viewModelScope.launch{ + jokes = getAllJokes() + changeCurrentJoke() + } + + } - private fun initializeLiveDataFields(){ + private fun initializeLiveData(){ viewModelScope.launch{ numberOfJokes.value = getNumberOfJokesFromDatabase() } @@ -64,19 +72,25 @@ class JokeViewModel(val database: JokeDatabaseDao, application: Application): An startOver() return } - + viewModelScope.launch { + getAllJokes() + } + _currentJoke.value = "Create some jokes first" if(numberOfJokes.value == null) return //don't change the joke if there are no jokes if(numberOfJokes.value!! == 0) return var randomListNumber = Random.nextInt(numberOfJokes.value!!) + //use the livedata joke list to get a random joke - if(_currentJoke.value == jokes.value?.get(randomListNumber)?.punchline) randomListNumber = randomListNumber.plus(1).mod(numberOfJokes.value!!) + if(_currentJoke.value == jokes.get(randomListNumber).punchline) randomListNumber = randomListNumber.plus(1).mod(numberOfJokes.value!!) //use mod to stay in the correct range - _currentJoke.value = jokes.value?.get(randomListNumber)?.punchline + _currentJoke.value = jokes.get(randomListNumber).punchline + } + fun evaluationComplete(){ _shouldEvaluate.value = false } @@ -113,4 +127,8 @@ class JokeViewModel(val database: JokeDatabaseDao, application: Application): An private suspend fun getNumberOfJokesFromDatabase(): Int{ return database.numberOfJokes() } + + private suspend fun getAllJokes(): List{ + return database.getAllJokes() + } } \ No newline at end of file diff --git a/JokeApp/app/src/main/res/layout/fragment_add_joke.xml b/JokeApp/app/src/main/res/layout/fragment_add_joke.xml new file mode 100644 index 0000000..440496f --- /dev/null +++ b/JokeApp/app/src/main/res/layout/fragment_add_joke.xml @@ -0,0 +1,50 @@ + + + + + + + + + + +