hltb example: backlink hltb result to game list
This commit is contained in:
parent
5b5810c35d
commit
adde1e8e70
|
@ -4,15 +4,26 @@ import android.app.Activity
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import java.net.URL
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
fun Uri.toBitmap(activity: Activity): Bitmap {
|
fun Uri.toBitmap(activity: Activity): Bitmap
|
||||||
return BitmapFactory.decodeStream(activity.contentResolver.openInputStream(this))
|
= BitmapFactory.decodeStream(activity.contentResolver.openInputStream(this))
|
||||||
}
|
|
||||||
|
fun URL.downloadAsImage(): Bitmap =
|
||||||
|
BitmapFactory.decodeStream(this.openConnection().getInputStream())
|
||||||
|
|
||||||
fun Bitmap.scaleToWidth(width: Int): Bitmap {
|
fun Bitmap.scaleToWidth(width: Int): Bitmap {
|
||||||
val aspectRatio = this.width.toFloat() / this.height.toFloat()
|
val aspectRatio = this.width.toFloat() / this.height.toFloat()
|
||||||
val height = (width / aspectRatio).roundToInt()
|
val height = (width / aspectRatio).roundToInt()
|
||||||
|
|
||||||
return Bitmap.createScaledBitmap(this, width, height, false)
|
return Bitmap.createScaledBitmap(this, width, height, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.ensureVisible() {
|
||||||
|
if(!this.isVisible) {
|
||||||
|
this.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import be.kuleuven.howlongtobeat.databinding.FragmentGamelistBinding
|
import be.kuleuven.howlongtobeat.databinding.FragmentGamelistBinding
|
||||||
import be.kuleuven.howlongtobeat.model.Game
|
import be.kuleuven.howlongtobeat.model.Game
|
||||||
import be.kuleuven.howlongtobeat.model.GameRepository
|
import be.kuleuven.howlongtobeat.model.GameRepository
|
||||||
import be.kuleuven.howlongtobeat.model.room.GameRepositoryRoomImpl
|
|
||||||
|
|
||||||
class GameListFragment : Fragment(R.layout.fragment_gamelist) {
|
class GameListFragment : Fragment(R.layout.fragment_gamelist) {
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ class GameListFragment : Fragment(R.layout.fragment_gamelist) {
|
||||||
): View? {
|
): View? {
|
||||||
binding = FragmentGamelistBinding.inflate(layoutInflater)
|
binding = FragmentGamelistBinding.inflate(layoutInflater)
|
||||||
main = activity as MainActivity
|
main = activity as MainActivity
|
||||||
gameRepository = GameRepositoryRoomImpl(main.applicationContext)
|
gameRepository = GameRepository.defaultImpl(main.applicationContext)
|
||||||
loadGames()
|
loadGames()
|
||||||
|
|
||||||
adapter = GameListAdapter(gameList)
|
adapter = GameListAdapter(gameList)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package be.kuleuven.howlongtobeat
|
package be.kuleuven.howlongtobeat
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.findFragment
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import be.kuleuven.howlongtobeat.hltb.HowLongToBeatResult
|
import be.kuleuven.howlongtobeat.hltb.HowLongToBeatResult
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -19,8 +19,11 @@ class HltbResultsAdapter(private val items: List<HowLongToBeatResult>) : Recycle
|
||||||
|
|
||||||
inner class HltbResultsViewHolder(currentItemView: View) : RecyclerView.ViewHolder(currentItemView)
|
inner class HltbResultsViewHolder(currentItemView: View) : RecyclerView.ViewHolder(currentItemView)
|
||||||
|
|
||||||
|
private lateinit var parentFragment: HltbResultsFragment
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HltbResultsViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HltbResultsViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_hltbresult, parent, false)
|
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_hltbresult, parent, false)
|
||||||
|
parentFragment = parent.findFragment()
|
||||||
return HltbResultsViewHolder(view)
|
return HltbResultsViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +31,10 @@ class HltbResultsAdapter(private val items: List<HowLongToBeatResult>) : Recycle
|
||||||
val itm = items[position]
|
val itm = items[position]
|
||||||
|
|
||||||
holder.itemView.apply {
|
holder.itemView.apply {
|
||||||
|
setOnClickListener {
|
||||||
|
parentFragment.addResultToGameLibrary(itm)
|
||||||
|
}
|
||||||
|
|
||||||
findViewById<TextView>(R.id.txtHltbItemResult).text = itm.toString()
|
findViewById<TextView>(R.id.txtHltbItemResult).text = itm.toString()
|
||||||
val boxArtView = findViewById<ImageView>(R.id.imgHltbItemResult)
|
val boxArtView = findViewById<ImageView>(R.id.imgHltbItemResult)
|
||||||
|
|
||||||
|
@ -35,7 +42,7 @@ class HltbResultsAdapter(private val items: List<HowLongToBeatResult>) : Recycle
|
||||||
MainScope().launch{
|
MainScope().launch{
|
||||||
var art: Bitmap? = null
|
var art: Bitmap? = null
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
art = BitmapFactory.decodeStream(itm.boxartUrl().openConnection().getInputStream())
|
art = itm.boxartUrl().downloadAsImage()
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
boxArtView.setImageBitmap(art)
|
boxArtView.setImageBitmap(art)
|
||||||
|
|
|
@ -5,13 +5,18 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import be.kuleuven.howlongtobeat.databinding.FragmentHltbresultsBinding
|
import be.kuleuven.howlongtobeat.databinding.FragmentHltbresultsBinding
|
||||||
import be.kuleuven.howlongtobeat.hltb.HowLongToBeatResult
|
import be.kuleuven.howlongtobeat.hltb.HowLongToBeatResult
|
||||||
|
import be.kuleuven.howlongtobeat.model.Game
|
||||||
|
import be.kuleuven.howlongtobeat.model.GameRepository
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
|
||||||
class HltbResultsFragment : Fragment(R.layout.fragment_hltbresults) {
|
class HltbResultsFragment : Fragment(R.layout.fragment_hltbresults) {
|
||||||
private lateinit var binding: FragmentHltbresultsBinding
|
private lateinit var binding: FragmentHltbresultsBinding
|
||||||
private lateinit var adapter: HltbResultsAdapter
|
private lateinit var adapter: HltbResultsAdapter
|
||||||
|
private lateinit var gameRepository: GameRepository
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -22,10 +27,18 @@ class HltbResultsFragment : Fragment(R.layout.fragment_hltbresults) {
|
||||||
|
|
||||||
val resultFromLoadingFragment = arguments?.getSerializable(HowLongToBeatResult.RESULT) as List<HowLongToBeatResult>
|
val resultFromLoadingFragment = arguments?.getSerializable(HowLongToBeatResult.RESULT) as List<HowLongToBeatResult>
|
||||||
|
|
||||||
|
gameRepository = GameRepository.defaultImpl(requireContext())
|
||||||
|
|
||||||
adapter = HltbResultsAdapter(resultFromLoadingFragment)
|
adapter = HltbResultsAdapter(resultFromLoadingFragment)
|
||||||
binding.rvHltbResult.adapter = adapter
|
binding.rvHltbResult.adapter = adapter
|
||||||
binding.rvHltbResult.layoutManager = LinearLayoutManager(this.context)
|
binding.rvHltbResult.layoutManager = LinearLayoutManager(this.context)
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addResultToGameLibrary(hltbResult: HowLongToBeatResult) {
|
||||||
|
gameRepository.save(Game(hltbResult))
|
||||||
|
Snackbar.make(requireView(), "Added ${hltbResult.title} to library!", Snackbar.LENGTH_LONG).show()
|
||||||
|
findNavController().navigate(R.id.action_hltbResultsFragment_to_gameListFragment)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package be.kuleuven.howlongtobeat
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
|
||||||
|
interface ImageRecognizer {
|
||||||
|
suspend fun recognizeCartCode(image: Bitmap): String?
|
||||||
|
}
|
|
@ -12,7 +12,6 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.content.PermissionChecker
|
import androidx.core.content.PermissionChecker
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import be.kuleuven.howlongtobeat.cartridges.Cartridge
|
import be.kuleuven.howlongtobeat.cartridges.Cartridge
|
||||||
|
@ -26,12 +25,11 @@ import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||||
|
|
||||||
private lateinit var hltbClient: HLTBClient
|
private lateinit var hltbClient: HLTBClient
|
||||||
private lateinit var cartRepo: CartridgesRepository
|
private lateinit var cartRepo: CartridgesRepository
|
||||||
private lateinit var visionClient: GoogleVisionClient
|
private lateinit var imageRecognizer: ImageRecognizer
|
||||||
|
|
||||||
private lateinit var cameraPermissionActivityResult: ActivityResultLauncher<String>
|
private lateinit var cameraPermissionActivityResult: ActivityResultLauncher<String>
|
||||||
private lateinit var cameraActivityResult: ActivityResultLauncher<Uri>
|
private lateinit var cameraActivityResult: ActivityResultLauncher<Uri>
|
||||||
|
@ -49,7 +47,7 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||||
main = activity as MainActivity
|
main = activity as MainActivity
|
||||||
|
|
||||||
cartRepo = CartridgesRepository.fromAsset(main.applicationContext)
|
cartRepo = CartridgesRepository.fromAsset(main.applicationContext)
|
||||||
visionClient = GoogleVisionClient()
|
imageRecognizer = GoogleVisionClient()
|
||||||
hltbClient = HLTBClient(main.applicationContext)
|
hltbClient = HLTBClient(main.applicationContext)
|
||||||
|
|
||||||
cameraActivityResult = registerForActivityResult(ActivityResultContracts.TakePicture(), this::cameraSnapTaken)
|
cameraActivityResult = registerForActivityResult(ActivityResultContracts.TakePicture(), this::cameraSnapTaken)
|
||||||
|
@ -77,11 +75,12 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun findGameBasedOnCameraSnap(pic: Bitmap) {
|
private suspend fun findGameBasedOnCameraSnap(pic: Bitmap) {
|
||||||
progress("Unleashing Google Vision on the pic...")
|
/*
|
||||||
val cartCode = visionClient.findCartCodeViaGoogleVision(pic)
|
progress("Recognizing game cart from picture...")
|
||||||
|
val cartCode = imageRecognizer.recognizeCartCode(pic)
|
||||||
|
|
||||||
if (cartCode == null) {
|
if (cartCode == null) {
|
||||||
errorInProgress("Unable to find a code in your pic. Retry?")
|
errorInProgress("No cart code in your pic found. Retry?")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,16 +88,19 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||||
val foundCart = cartRepo.find(cartCode)
|
val foundCart = cartRepo.find(cartCode)
|
||||||
|
|
||||||
if (foundCart == Cartridge.UNKNOWN_CART) {
|
if (foundCart == Cartridge.UNKNOWN_CART) {
|
||||||
errorInProgress("$cartCode is an unknown game cartridge. Retry?")
|
errorInProgress("$cartCode is an unknown game cart. Retry?")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
progress("Valid cart code $cartCode, looking in HLTB...")
|
progress("Valid cart code $cartCode, looking in HLTB...")
|
||||||
|
|
||||||
|
*/
|
||||||
|
val foundCart = Cartridge("DMG", "Super Mario Land", "DMG-something")
|
||||||
hltbClient.find(foundCart.title) {
|
hltbClient.find(foundCart.title) {
|
||||||
Snackbar.make(requireView(), "Found ${it.size} game(s) for cart $cartCode", Snackbar.LENGTH_LONG).show()
|
Snackbar.make(requireView(), "Found ${it.size} game(s) for cart ${foundCart.code}", Snackbar.LENGTH_LONG).show()
|
||||||
|
|
||||||
// TODO wat als geen hltb results gevonden?
|
// TODO wat als geen hltb results gevonden?
|
||||||
val bundle = bundleOf(HowLongToBeatResult.RESULT to it, HowLongToBeatResult.CODE to cartCode)
|
val bundle = bundleOf(HowLongToBeatResult.RESULT to it)
|
||||||
findNavController().navigate(R.id.action_loadingFragment_to_hltbResultsFragment, bundle)
|
findNavController().navigate(R.id.action_loadingFragment_to_hltbResultsFragment, bundle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +125,7 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNewTempCameraFile() {
|
private fun createNewTempCameraFile() {
|
||||||
|
// a <Provider/> should be present in the manifest file.
|
||||||
val tempFile = File.createTempFile("hltbCameraSnap", ".png", main.cacheDir).apply {
|
val tempFile = File.createTempFile("hltbCameraSnap", ".png", main.cacheDir).apply {
|
||||||
createNewFile()
|
createNewFile()
|
||||||
deleteOnExit()
|
deleteOnExit()
|
||||||
|
@ -136,9 +139,7 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun progress(msg: String) {
|
private fun progress(msg: String) {
|
||||||
if(!binding.indeterminateBar.isVisible) {
|
binding.indeterminateBar.ensureVisible()
|
||||||
binding.indeterminateBar.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
binding.txtLoading.text = msg
|
binding.txtLoading.text = msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package be.kuleuven.howlongtobeat.google
|
package be.kuleuven.howlongtobeat.google
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import be.kuleuven.howlongtobeat.ImageRecognizer
|
||||||
import be.kuleuven.howlongtobeat.asEncodedGoogleVisionImage
|
import be.kuleuven.howlongtobeat.asEncodedGoogleVisionImage
|
||||||
import be.kuleuven.howlongtobeat.cartridges.Cartridge
|
import be.kuleuven.howlongtobeat.cartridges.Cartridge
|
||||||
import com.google.api.client.http.javanet.NetHttpTransport
|
import com.google.api.client.http.javanet.NetHttpTransport
|
||||||
|
@ -14,7 +15,7 @@ import com.google.api.services.vision.v1.model.Feature
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class GoogleVisionClient {
|
class GoogleVisionClient : ImageRecognizer {
|
||||||
|
|
||||||
// TODO encrypt and store externally: https://cloud.google.com/docs/authentication/api-keys?hl=en&visit_id=637642790375688006-1838986332&rd=1
|
// TODO encrypt and store externally: https://cloud.google.com/docs/authentication/api-keys?hl=en&visit_id=637642790375688006-1838986332&rd=1
|
||||||
private val vision = Vision.Builder(NetHttpTransport(), GsonFactory.getDefaultInstance(), null)
|
private val vision = Vision.Builder(NetHttpTransport(), GsonFactory.getDefaultInstance(), null)
|
||||||
|
@ -22,7 +23,7 @@ class GoogleVisionClient {
|
||||||
.setApplicationName("How Long To Beat")
|
.setApplicationName("How Long To Beat")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
suspend fun findCartCodeViaGoogleVision(cameraSnap: Bitmap): String? {
|
private suspend fun findCartCodeViaGoogleVision(cameraSnap: Bitmap): String? {
|
||||||
var response: BatchAnnotateImagesResponse
|
var response: BatchAnnotateImagesResponse
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val sml2Data = cameraSnap.asEncodedGoogleVisionImage()
|
val sml2Data = cameraSnap.asEncodedGoogleVisionImage()
|
||||||
|
@ -51,4 +52,6 @@ class GoogleVisionClient {
|
||||||
}.firstOrNull()
|
}.firstOrNull()
|
||||||
return gbId?.description ?: null
|
return gbId?.description ?: null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun recognizeCartCode(image: Bitmap): String? = findCartCodeViaGoogleVision(image)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import java.net.URL
|
||||||
data class HowLongToBeatResult(val title: String, val howlong: Double, val boxart: String = "") : java.io.Serializable {
|
data class HowLongToBeatResult(val title: String, val howlong: Double, val boxart: String = "") : java.io.Serializable {
|
||||||
companion object {
|
companion object {
|
||||||
const val RESULT = "HowLongToBeatResult"
|
const val RESULT = "HowLongToBeatResult"
|
||||||
const val CODE = "CartCode"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasBoxart(): Boolean = boxart.startsWith(HLTBClient.DOMAIN)
|
fun hasBoxart(): Boolean = boxart.startsWith(HLTBClient.DOMAIN)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package be.kuleuven.howlongtobeat.model
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import be.kuleuven.howlongtobeat.hltb.HowLongToBeatResult
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
data class Game(
|
data class Game(
|
||||||
|
@ -10,6 +11,10 @@ data class Game(
|
||||||
@ColumnInfo(name = "is_done") var isDone: Boolean = false,
|
@ColumnInfo(name = "is_done") var isDone: Boolean = false,
|
||||||
@PrimaryKey(autoGenerate = true) var id: Int = 0) : java.io.Serializable {
|
@PrimaryKey(autoGenerate = true) var id: Int = 0) : java.io.Serializable {
|
||||||
|
|
||||||
|
constructor(result: HowLongToBeatResult) : this(result.title)
|
||||||
|
|
||||||
|
// TODO more columns (platform? hours, paths of images?)
|
||||||
|
|
||||||
fun check() {
|
fun check() {
|
||||||
isDone = true
|
isDone = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
package be.kuleuven.howlongtobeat.model
|
package be.kuleuven.howlongtobeat.model
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import be.kuleuven.howlongtobeat.model.room.GameRepositoryRoomImpl
|
||||||
|
|
||||||
interface GameRepository {
|
interface GameRepository {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* This makes it easier to switch between implementations if needed and does not expose the RoomImpl
|
||||||
|
* Dependency Injection is the better alternative.
|
||||||
|
*/
|
||||||
|
fun defaultImpl(appContext: Context): GameRepository = GameRepositoryRoomImpl(appContext)
|
||||||
|
}
|
||||||
|
|
||||||
fun load(): List<Game>
|
fun load(): List<Game>
|
||||||
|
|
||||||
fun save(items: List<Game>)
|
fun save(game: Game)
|
||||||
|
|
||||||
|
fun overwrite(items: List<Game>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,13 @@ class GameRepositoryRoomImpl(appContext: Context) :
|
||||||
|
|
||||||
override fun load(): List<Game> = dao.query()
|
override fun load(): List<Game> = dao.query()
|
||||||
|
|
||||||
override fun save(items: List<Game>) {
|
override fun save(game: Game) {
|
||||||
|
db.runInTransaction {
|
||||||
|
dao.insert(listOf(game))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun overwrite(items: List<Game>) {
|
||||||
// You'll learn more about transactions in the database course in the 3rd academic year.
|
// You'll learn more about transactions in the database course in the 3rd academic year.
|
||||||
db.runInTransaction {
|
db.runInTransaction {
|
||||||
dao.deleteAll()
|
dao.deleteAll()
|
||||||
|
|
|
@ -23,5 +23,9 @@
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/hltbResultsFragment"
|
android:id="@+id/hltbResultsFragment"
|
||||||
android:name="be.kuleuven.howlongtobeat.HltbResultsFragment"
|
android:name="be.kuleuven.howlongtobeat.HltbResultsFragment"
|
||||||
android:label="HltbResultsFragment" />
|
android:label="HltbResultsFragment" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_hltbResultsFragment_to_gameListFragment"
|
||||||
|
app:destination="@id/gameListFragment" />
|
||||||
|
</fragment>
|
||||||
</navigation>
|
</navigation>
|
Loading…
Reference in New Issue