diff --git a/app/src/main/java/com/denizk0461/studip/activity/FetcherActivity.kt b/app/src/main/java/com/denizk0461/studip/activity/FetcherActivity.kt index 84ae114..b48c279 100644 --- a/app/src/main/java/com/denizk0461/studip/activity/FetcherActivity.kt +++ b/app/src/main/java/com/denizk0461/studip/activity/FetcherActivity.kt @@ -6,10 +6,8 @@ import android.os.Bundle import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient -import android.widget.Toast import androidx.lifecycle.ViewModelProvider import com.denizk0461.studip.R -import com.denizk0461.studip.data.StudIPParser import com.denizk0461.studip.data.getThemedColor import com.denizk0461.studip.databinding.ActivityFetcherBinding import com.denizk0461.studip.viewmodel.FetcherViewModel @@ -72,21 +70,25 @@ class FetcherActivity : Activity() { ) { p0 -> try { // Decode HTML and parse it into a list of StudIPEvent.kt - StudIPParser().parse(URLDecoder.decode(p0, "UTF-8")) { events -> - // Delete all previously fetched elements - viewModel.nukeEvents() - - // Insert the list into the database - viewModel.insertEvents(events) - - // Notify the user that the fetch was successful - Toast.makeText( - this, R.string.toast_fetch_finished, Toast.LENGTH_SHORT - ).show() - - // Close the activity - finish() - } + // TODO this exception handling and finish() is broken + viewModel.parse(URLDecoder.decode(p0, "UTF-8")) +// StudIPParser(application).parse(URLDecoder.decode(p0, "UTF-8")) { events -> +// +// // Delete all previously fetched elements +//// viewModel.nukeEvents() +//// viewModel.replaceEvents(events) +// +// // Insert the list into the database +//// viewModel.insertEvents(events) +// +// // Notify the user that the fetch was successful +// Toast.makeText( +// this, R.string.toast_fetch_finished, Toast.LENGTH_SHORT +// ).show() +// +// // Close the activity +// finish() +// } } catch (e: IOException) { // Let the user know that an error occurred diff --git a/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt b/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt index c9dabbc..05ac569 100644 --- a/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt +++ b/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt @@ -1,12 +1,11 @@ package com.denizk0461.studip.activity import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat +import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentTransaction import androidx.lifecycle.Lifecycle import com.denizk0461.studip.R -import com.denizk0461.studip.data.Dependencies import com.denizk0461.studip.databinding.ActivityMainBinding import com.denizk0461.studip.db.AppRepository import com.denizk0461.studip.fragment.EventFragment @@ -17,7 +16,7 @@ import com.denizk0461.studip.model.SettingsPreferences /** * Main activity that handles all common fragments. This is opened on app launch. */ -class MainActivity : AppCompatActivity() { +class MainActivity : FragmentActivity() { // View binding private lateinit var binding: ActivityMainBinding @@ -36,7 +35,7 @@ class MainActivity : AppCompatActivity() { * Instantiate repository object that is accessed by the fragments' view models to retrieve * data. */ - Dependencies.repo = AppRepository(application) +// Dependencies.repo = AppRepository(application) // Inflate view binding and bind to this activity binding = ActivityMainBinding.inflate(layoutInflater) @@ -44,7 +43,8 @@ class MainActivity : AppCompatActivity() { // Open the fragment that the user specified to open on app start if ( - Dependencies.repo.getBooleanPreference(SettingsPreferences.LAUNCH_CANTEEN_ON_START) + AppRepository.getRepositoryInstance(application) + .getBooleanPreference(SettingsPreferences.LAUNCH_CANTEEN_ON_START) ) { // Open canteen fragment binding.contentMain.navView.selectedItemId = R.id.food diff --git a/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt b/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt index d54122f..02c3cdd 100644 --- a/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt +++ b/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt @@ -27,7 +27,7 @@ class StudIPEventItemAdapter( ) : RecyclerView.Adapter() { /** - * List of all events (still not filtered by day at this point) + * List of all events. */ private var events: MutableList = mutableListOf() diff --git a/app/src/main/java/com/denizk0461/studip/data/Dependencies.kt b/app/src/main/java/com/denizk0461/studip/data/Dependencies.kt deleted file mode 100644 index 0c38b68..0000000 --- a/app/src/main/java/com/denizk0461/studip/data/Dependencies.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.denizk0461.studip.data - -import com.denizk0461.studip.db.AppRepository - -/** - * Static object that holds a reference to the app's repository to provide abstracted access to the - * app database. - */ -object Dependencies { - /** - * Reference to the app's repository. Since it instantiated once by the main activity, it can be - * accessed statically by all other classes. Used for database transactions. - */ - lateinit var repo: AppRepository -} \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/data/StudIPParser.kt b/app/src/main/java/com/denizk0461/studip/data/StudIPParser.kt index adb576e..caef527 100644 --- a/app/src/main/java/com/denizk0461/studip/data/StudIPParser.kt +++ b/app/src/main/java/com/denizk0461/studip/data/StudIPParser.kt @@ -1,5 +1,7 @@ package com.denizk0461.studip.data +import android.app.Application +import com.denizk0461.studip.db.AppRepository import com.denizk0461.studip.model.StudIPEvent import org.jsoup.Jsoup import java.io.IOException @@ -7,7 +9,9 @@ import java.io.IOException /** * Parser class used for fetching and collecting scheduled events from a Stud.IP timetable. */ -class StudIPParser { +class StudIPParser(application: Application) { + + private val repo: AppRepository = AppRepository.getRepositoryInstance(application) /** * Parse a given HTML string. HTML must be of a Stud.IP timetable. @@ -84,7 +88,7 @@ class StudIPParser { // Construct the newly scraped Stud.IP event val event = StudIPEvent( - id = id, + eventId = id, title = parsedTitle, lecturer = parsedLecturers, room = entryInfo[1], @@ -102,7 +106,10 @@ class StudIPParser { } } + // Delete all previously saved events + repo.nukeEvents() + // After fetching has finished, save the list of new items into persistent storage - insert(newEvents) + repo.insertEvents(newEvents) } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/data/StwParser.kt b/app/src/main/java/com/denizk0461/studip/data/StwParser.kt index 4918626..e1b0ef1 100644 --- a/app/src/main/java/com/denizk0461/studip/data/StwParser.kt +++ b/app/src/main/java/com/denizk0461/studip/data/StwParser.kt @@ -1,5 +1,7 @@ package com.denizk0461.studip.data +import android.app.Application +import com.denizk0461.studip.db.AppRepository import com.denizk0461.studip.model.* import org.jsoup.Jsoup import org.jsoup.nodes.Element @@ -9,7 +11,7 @@ import org.jsoup.select.Elements * Parser class used for fetching and collecting canteen offers from the website of the * Studierendenwerk Bremen. */ -class StwParser { +class StwParser(application: Application) { // Unique primary key value for the date elements private var dateId = 0 @@ -26,6 +28,11 @@ class StwParser { // Determine whether there are offers for a given date private var dateHasItems = false + /** + * Static instance of the app's repository. + */ + private val repo: AppRepository = AppRepository.getRepositoryInstance(application) + /** * Parses through a list of canteen plans and saves them to persistent storage. * @@ -59,13 +66,13 @@ class StwParser { } // Delete all previous entries and start afresh - Dependencies.repo.nukeOffers() + repo.nukeOffers() // Fetch offers from the chosen canteen val (dates, canteens, categories, items) = parseFromPage(link) // Save everything all at once into the database - with (Dependencies.repo) { + with (repo) { insertDates(dates) insertCanteens(canteens) insertCategories(categories) diff --git a/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt b/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt index 3b54b69..cd4664e 100644 --- a/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt +++ b/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt @@ -18,7 +18,7 @@ interface AppDAO { * * @return all Stud.IP events exposed through a LiveData object */ - @get:Query("SELECT * FROM studipevents ORDER BY timeslotId, id") + @get:Query("SELECT * FROM studip_events ORDER BY timeslotId, eventId") val allEvents: LiveData> /** @@ -26,7 +26,7 @@ interface AppDAO { * * @return Stud.IP events for a certain day exposed through a LiveData object */ - @Query("SELECT * FROM studipevents WHERE day = :day ORDER BY timeslotId, id") + @Query("SELECT * FROM studip_events WHERE day = :day ORDER BY timeslotId, eventId") fun getEventsForDay(day: Int): LiveData> /** @@ -62,7 +62,7 @@ interface AppDAO { /** * Deletes all Stud.IP events from the database. */ - @Query("DELETE FROM studipevents") + @Query("DELETE FROM studip_events") fun nukeEvents() /* --- canteen offers --- */ diff --git a/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt b/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt index e0ac125..8e682cd 100644 --- a/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt +++ b/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt @@ -17,7 +17,7 @@ import com.denizk0461.studip.model.* OfferCategory::class, OfferItem::class, ], - version = 16, + version = 18, ) abstract class AppDatabase : RoomDatabase() { diff --git a/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt b/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt index a7d88be..c8cc4ec 100644 --- a/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt +++ b/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt @@ -25,6 +25,27 @@ class AppRepository(app: Application) { // Blank dietary preference regular expression private val blankDietaryPrefs: String = DietaryPreferences.C_FALSE.toString().repeat(10) + companion object { + /** + * Reference to the app's repository. It is only instantiated once because it can only be + * accessed by [getRepositoryInstance]. + */ + private lateinit var repo: AppRepository + + /** + * Get a static instance of the repository. If none has been instantiated, one will be created + * and saved into [repo]. + * + * @return static instance of the repository + */ + fun getRepositoryInstance(app: Application): AppRepository { + if (!::repo.isInitialized) { + repo = AppRepository(app) + } + return repo + } + } + /** * Retrieves Stud.IP events for a specific day, ordered by their timeslots, then their IDs. * diff --git a/app/src/main/java/com/denizk0461/studip/fragment/EventPageFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/EventPageFragment.kt index a3bd2c4..3d9866b 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/EventPageFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/EventPageFragment.kt @@ -66,7 +66,7 @@ class EventPageFragment( // Set up LiveData observer to refresh the view on update viewModel.getEventsForDay(currentDay).observe(viewLifecycleOwner) { events -> -// eventAdapter.setNewItems(events) + eventAdapter.setNewData(events) } } diff --git a/app/src/main/java/com/denizk0461/studip/model/StudIPEvent.kt b/app/src/main/java/com/denizk0461/studip/model/StudIPEvent.kt index 37c8fea..792bffe 100644 --- a/app/src/main/java/com/denizk0461/studip/model/StudIPEvent.kt +++ b/app/src/main/java/com/denizk0461/studip/model/StudIPEvent.kt @@ -6,7 +6,7 @@ import androidx.room.PrimaryKey /** * Entity for storing entries of the user's Stud.IP schedule. Registered in the app database. * - * @param id primary key that uniquely identifies the entry + * @param eventId primary key that uniquely identifies the entry * @param title title of the event * @param lecturer lecturer(s) organising the event * @param room room the event takes place in @@ -16,9 +16,9 @@ import androidx.room.PrimaryKey * @param timeslotId minute the event starts at - used for ordering * @param colour user-defined colour the event will be shown in - UNIMPLEMENTED */ -@Entity(tableName = "studipevents") +@Entity(tableName = "studip_events") data class StudIPEvent( - @PrimaryKey val id: Int, + @PrimaryKey val eventId: Int, val title: String, val lecturer: String, val room: String, @@ -45,7 +45,7 @@ data class StudIPEvent( other as StudIPEvent - if (id != other.id) return false + if (eventId != other.eventId) return false if (title != other.title) return false if (lecturer != other.lecturer) return false if (room != other.room) return false @@ -59,7 +59,7 @@ data class StudIPEvent( } override fun hashCode(): Int { - var result = id + var result = eventId result = 31 * result + title.hashCode() result = 31 * result + lecturer.hashCode() result = 31 * result + room.hashCode() diff --git a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt index 2b1ec6b..8327611 100644 --- a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt +++ b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt @@ -133,7 +133,7 @@ class ScheduleUpdateSheet( onUpdate( // construct new StudIPEvent from the data the user may have edited StudIPEvent( - id = event.id, + eventId = event.eventId, title = binding.editTextTitle.text.toString(), lecturer = binding.editTextLecturers.text.toString(), room = binding.editTextRoom.text.toString(), diff --git a/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt b/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt index 5dc9ef6..62b2f12 100644 --- a/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt +++ b/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt @@ -3,7 +3,6 @@ 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.AppRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -21,7 +20,7 @@ open class AppViewModel(app: Application) : AndroidViewModel(app) { /** * Reference to the app's repository for database transactions. */ - protected val repo: AppRepository = Dependencies.repo + protected val repo: AppRepository = AppRepository.getRepositoryInstance(app) /** * Execute a function asynchronously on the I/O thread. Be careful not to execute UI commands diff --git a/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt b/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt index 2a4ac1c..7a44fee 100644 --- a/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt +++ b/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt @@ -13,7 +13,7 @@ import com.denizk0461.studip.model.* class CanteenViewModel(app: Application) : AppViewModel(app) { // Instantiate a parser, should the user want to refresh the canteen offers - private val parser = StwParser() + private val parser = StwParser(app) /** * Retrieves all Stud.IP events. diff --git a/app/src/main/java/com/denizk0461/studip/viewmodel/FetcherViewModel.kt b/app/src/main/java/com/denizk0461/studip/viewmodel/FetcherViewModel.kt index b02d198..47f189b 100644 --- a/app/src/main/java/com/denizk0461/studip/viewmodel/FetcherViewModel.kt +++ b/app/src/main/java/com/denizk0461/studip/viewmodel/FetcherViewModel.kt @@ -1,7 +1,7 @@ package com.denizk0461.studip.viewmodel import android.app.Application -import com.denizk0461.studip.model.StudIPEvent +import com.denizk0461.studip.data.StudIPParser /** * View model for [com.denizk0461.studip.activity.FetcherActivity] @@ -10,15 +10,7 @@ import com.denizk0461.studip.model.StudIPEvent */ class FetcherViewModel(app: Application) : AppViewModel(app) { - /** - * Save a list of Stud.IP events to persistent storage asynchronously. - * - * @param events list of events to be saved - */ - fun insertEvents(events: List) { doAsync { repo.insertEvents(events) }} + private val parser: StudIPParser = StudIPParser(app) - /** - * Delete all Stud.IP events from the database asynchronously. - */ - fun nukeEvents() { doAsync { repo.nukeEvents() } } + fun parse(html: String) { doAsync { parser.parse(html, {}) }} } \ No newline at end of file