Added database persistence ability

This commit is contained in:
denizk0461
2023-04-08 17:30:05 +02:00
parent 9accebc68c
commit 3c65ccddb1
15 changed files with 176 additions and 68 deletions
+4
View File
@@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
android {
@@ -47,4 +48,7 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "androidx.room:room-runtime:2.5.1"
kapt "androidx.room:room-compiler:2.5.1"
}
@@ -11,7 +11,9 @@ import androidx.navigation.ui.setupActionBarWithNavController
import android.view.Menu
import android.view.MenuItem
import com.denizk0461.studip.R
import com.denizk0461.studip.data.Dependencies
import com.denizk0461.studip.databinding.ActivityMainBinding
import com.denizk0461.studip.db.EventRepository
class MainActivity : AppCompatActivity() {
@@ -22,9 +24,12 @@ class MainActivity : AppCompatActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
Dependencies.repo = EventRepository(application)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
val navController = findNavController(R.id.nav_host_fragment_content_main)
@@ -1,12 +1,10 @@
package com.denizk0461.studip.adapter
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.denizk0461.studip.data.StudIPEvent
import com.denizk0461.studip.databinding.ItemEventBinding
import com.denizk0461.studip.databinding.ItemEventPageBinding
class StudIPEventAdapter(private val events: List<StudIPEvent>) : RecyclerView.Adapter<StudIPEventAdapter.EventViewHolder>() {
@@ -24,24 +22,13 @@ class StudIPEventAdapter(private val events: List<StudIPEvent>) : RecyclerView.A
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
val currentItem = events[position]
// var itemCount = 0
// events.filter { it.day == position }.forEach { event ->
// val newView = ItemEventBinding.inflate(
// LayoutInflater.from(holder.binding.root.context),
// holder.binding.root,
// false
// ).also { item ->
// Log.d("HELLO", "generating ${event.title}...2")
// itemCount += 1
holder.binding.textTitle.text = currentItem.title
holder.binding.textLecturers.text = currentItem.lecturer.joinToString(", ")
holder.binding.textLecturers.text = currentItem.lecturer
holder.binding.textRoom.text = currentItem.room
holder.binding.textTimeslot.text = currentItem.timeslot
// }
// holder.binding.pageLayout.addView(newView.root)
// }
// if (itemCount == 0) {
// // TODO inflate view saying "no events!" or sth
// }
// TODO inflate view saying "no events!" or sth
}
}
@@ -1,13 +1,10 @@
package com.denizk0461.studip.adapter
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.denizk0461.studip.data.StudIPEvent
import com.denizk0461.studip.databinding.ItemEventBinding
import com.denizk0461.studip.databinding.ItemEventPageBinding
class StudIPEventPageAdapter(private val events: List<StudIPEvent>) : RecyclerView.Adapter<StudIPEventPageAdapter.EventPageViewHolder>() {
@@ -29,26 +26,7 @@ class StudIPEventPageAdapter(private val events: List<StudIPEvent>) : RecyclerVi
holder.binding.pageRecyclerView.apply {
layoutManager = LinearLayoutManager(holder.binding.root.context, LinearLayoutManager.VERTICAL, false)
adapter = StudIPEventAdapter(events.filter { it.day == position }) // TODO check if empty
scheduleLayoutAnimation()
}
// var itemCount = 0
// events.filter { it.day == position }.forEach { event ->
// val newView = ItemEventBinding.inflate(
// LayoutInflater.from(holder.binding.root.context),
// holder.binding.root,
// false
// ).also { item ->
// Log.d("HELLO", "generating ${event.title}...2")
// itemCount += 1
// item.textTitle.text = event.title
// item.textLecturers.text = event.lecturer.joinToString(", ")
// item.textRoom.text = event.room
// item.textTimeslot.text = event.timeslot
// }
// holder.binding.pageLayout.addView(newView.root)
// }
// if (itemCount == 0) {
// // TODO inflate view saying "no events!" or sth
// }
}
}
@@ -0,0 +1,7 @@
package com.denizk0461.studip.data
import com.denizk0461.studip.db.EventRepository
object Dependencies {
lateinit var repo: EventRepository
}
@@ -3,12 +3,12 @@ package com.denizk0461.studip.data
object DummyData {
val events: Array<StudIPEvent> = arrayOf(
StudIPEvent("Literatures", arrayOf("Nittel"), "MZH 1380/1400", 0, 3, 1),
StudIPEvent("Linguistics", arrayOf("Du Bois"), "SFG 1020", 1, 1, 1),
StudIPEvent("System Erde", arrayOf("Zolitschka", "Labuhn-Deroubaix"), "GW2 B1410", 1, 3, 1),
StudIPEvent("Key Moments", arrayOf("Esders-Angermund"), "GW2 B2890", 2, 2, 1),
StudIPEvent("ULS-1", arrayOf("Herrmann"), "GW2 B2890", 2, 3, 1),
StudIPEvent("Gesellschaft und Raum", arrayOf("Lossau", "Mossig"), "GW2 B1820", 3, 1, 1),
StudIPEvent("Gesellschaft und Raum2", arrayOf("Lossau", "Mossig"), "GW2 B1820", 4, 4, 2),
StudIPEvent(1, "Literatures", "Nittel", "MZH 1380/1400", 0, 3, 1),
StudIPEvent(2, "Linguistics", "Du Bois", "SFG 1020", 1, 1, 1),
StudIPEvent(3, "System Erde", "Zolitschka, Labuhn-Deroubaix", "GW2 B1410", 1, 3, 1),
StudIPEvent(4, "Key Moments", "Esders-Angermund", "GW2 B2890", 2, 2, 1),
StudIPEvent(5, "ULS-1", "Herrmann", "GW2 B2890", 2, 3, 1),
StudIPEvent(6, "Gesellschaft und Raum", "Lossau, Mossig", "GW2 B1820", 3, 1, 1),
StudIPEvent(7, "Gesellschaft und Raum2", "Lossau, Mossig", "GW2 B1820", 4, 4, 2),
)
}
@@ -1,18 +1,24 @@
package com.denizk0461.studip.data
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
@Entity(tableName = "events")
data class StudIPEvent(
@PrimaryKey val id: Int,
val title: String, // the name of the event
val lecturer: Array<String>, // the lecturer(s)
val room: String, // the room the event takes place in; assumes that the room doesn't change
val lecturer: String, // the lecturer(s)
val room: String, // the room the event takes place in
val day: Int, // 0 = Monday, 1 = Tuesday, 2 = Wednesday, 3 = Thursday, 4 = Friday
val timeslotStart: Int, // 0 = 08:15, 1 = 10:15, 2 = 12:15, 3 = 14:15, 4 = 16:15, 5 = 18:15
val timeslots: Int, // the amount of timeslots the course takes place over (1 timeslot = 90min)
) {
private val timeSlotStartTimes: List<String> = listOf("08:15", "10:15", "12:15", "14:15", "16:15", "18:15")
private val timeSlotEndTimes: List<String> = listOf("09:45", "11:45", "13:45", "15:45", "17:45", "19:45")
@Ignore private val timeSlotStartTimes: List<String> = listOf("08:15", "10:15", "12:15", "14:15", "16:15", "18:15")
@Ignore private val timeSlotEndTimes: List<String> = listOf("09:45", "11:45", "13:45", "15:45", "17:45", "19:45")
val timeslot: String =
@Ignore val timeslot: String =
"${timeSlotStartTimes[timeslotStart]} ${timeSlotEndTimes[timeslotStart + timeslots - 1]}"
override fun equals(other: Any?): Boolean {
@@ -26,9 +32,18 @@ data class StudIPEvent(
return true
}
override fun hashCode(): Int {
var result = title.hashCode()
result = 31 * result + lecturer.contentHashCode()
var result = id
result = 31 * result + title.hashCode()
result = 31 * result + lecturer.hashCode()
result = 31 * result + room.hashCode()
result = 31 * result + day
result = 31 * result + timeslotStart
result = 31 * result + timeslots
result = 31 * result + timeSlotStartTimes.hashCode()
result = 31 * result + timeSlotEndTimes.hashCode()
result = 31 * result + timeslot.hashCode()
return result
}
}
@@ -0,0 +1,20 @@
package com.denizk0461.studip.db
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.denizk0461.studip.data.StudIPEvent
@Dao
interface EventDAO {
@get:Query("SELECT * FROM events ORDER BY id")
val allEvents: LiveData<List<StudIPEvent>>
@Insert
fun insertEvent(event: StudIPEvent)
@Query("DELETE FROM events")
fun nukeEvents()
}
@@ -0,0 +1,30 @@
package com.denizk0461.studip.db
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.denizk0461.studip.data.StudIPEvent
@Database(entities = [StudIPEvent::class], version = 1)
abstract class EventDatabase : RoomDatabase() {
abstract fun dao(): EventDAO
companion object {
private var instance: EventDatabase? = null
fun getInstance(context: Context): EventDatabase {
if (instance == null) {
synchronized(EventDatabase::class) {
instance = Room.databaseBuilder(
context.applicationContext,
EventDatabase::class.java,
"event_db"
).build()
}
}
return instance!!
}
}
}
@@ -0,0 +1,15 @@
package com.denizk0461.studip.db
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizk0461.studip.data.StudIPEvent
class EventRepository(app: Application) {
private val dao: EventDAO = EventDatabase.getInstance(app.applicationContext).dao()
val allEvents: LiveData<List<StudIPEvent>> = dao.allEvents
fun nukeEvents() { dao.nukeEvents() }
fun insertEvent(event: StudIPEvent) { dao.insertEvent(event) }
}
@@ -5,18 +5,21 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
import com.denizk0461.studip.data.DummyData
import com.denizk0461.studip.databinding.FragmentFirstBinding
import com.denizk0461.studip.databinding.FragmentEventBinding
import com.denizk0461.studip.viewmodel.EventViewModel
/**
* A simple [Fragment] subclass as the default destination in the navigation.
*/
class FirstFragment : Fragment() {
class EventFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
private var _binding: FragmentEventBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
@@ -24,19 +27,25 @@ class FirstFragment : Fragment() {
private lateinit var recyclerViewAdapter: StudIPEventPageAdapter
private lateinit var recyclerViewLayoutManager: LinearLayoutManager
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
private val viewModel: EventViewModel by viewModels()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentEventBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerViewAdapter = StudIPEventPageAdapter(DummyData.events.toList())
binding.recyclerView.adapter = recyclerViewAdapter
recyclerViewLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
binding.recyclerView.layoutManager = recyclerViewLayoutManager
PagerSnapHelper().attachToRecyclerView(binding.recyclerView)
viewModel.allEvents.observe(viewLifecycleOwner) { events ->
recyclerViewAdapter = StudIPEventPageAdapter(DummyData.events.toList())
binding.recyclerView.adapter = recyclerViewAdapter
recyclerViewLayoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
binding.recyclerView.layoutManager = recyclerViewLayoutManager
PagerSnapHelper().attachToRecyclerView(binding.recyclerView)
binding.recyclerView.scheduleLayoutAnimation()
}
// binding.buttonFirst.setOnClickListener {
// findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
@@ -0,0 +1,13 @@
package com.denizk0461.studip.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizk0461.studip.data.StudIPEvent
class EventViewModel(app: Application) : TemplateViewModel(app) {
val allEvents: LiveData<List<StudIPEvent>> = repo.allEvents
fun insertEvent(event: StudIPEvent) { repo.insertEvent(event) }
fun nukeEvents() { repo.nukeEvents() }
}
@@ -0,0 +1,25 @@
package com.denizk0461.studip.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.denizk0461.studip.data.Dependencies
import com.denizk0461.studip.db.EventRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
open class TemplateViewModel(app: Application) : AndroidViewModel(app) {
protected val repo: EventRepository = Dependencies.repo
fun doAsync(function: () -> Unit) {
viewModelScope.launch(Dispatchers.IO) {
function()
}
}
fun <T> returnBlocking(function: () -> T): T = runBlocking(Dispatchers.IO) {
function()
}
}
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.FirstFragment">
tools:context=".fragment.EventFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
+2 -2
View File
@@ -7,9 +7,9 @@
<fragment
android:id="@+id/FirstFragment"
android:name="com.denizk0461.studip.fragment.FirstFragment"
android:name="com.denizk0461.studip.fragment.EventFragment"
android:label="@string/first_fragment_label"
tools:layout="@layout/fragment_first">
tools:layout="@layout/fragment_event">
<action
android:id="@+id/action_FirstFragment_to_SecondFragment"