diff --git a/app/src/main/java/com/denizk0461/weserplaner/data/Extensions.kt b/app/src/main/java/com/denizk0461/weserplaner/data/Extensions.kt index 2c41746..181fda4 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/data/Extensions.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/data/Extensions.kt @@ -14,6 +14,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.denizk0461.weserplaner.R import com.denizk0461.weserplaner.exception.AcademicQuarterNotApplicableException import com.denizk0461.weserplaner.exception.ParcelNotFoundException +import com.denizk0461.weserplaner.model.TextSheetContentId import com.denizk0461.weserplaner.sheet.TextSheet import com.google.android.material.snackbar.Snackbar import kotlin.jvm.Throws @@ -72,10 +73,15 @@ fun Resources.Theme.showErrorSnackBar(view: CoordinatorLayout, text: String, anc * @param content text content of the sheet * @return sheet with text added */ -fun getTextSheet(header: String, content: String): TextSheet = TextSheet().also { sheet -> +fun getTextSheet( + header: String, + content: String = "", + contentId: Int = TextSheetContentId.PASS_RAW_STRING +): TextSheet = TextSheet().also { sheet -> val bundle = Bundle() bundle.putString("header", header) bundle.putString("content", content) + bundle.putInt("contentId", contentId) bundle.putBoolean("isCancellable", true) sheet.arguments = bundle } diff --git a/app/src/main/java/com/denizk0461/weserplaner/db/AppDAO.kt b/app/src/main/java/com/denizk0461/weserplaner/db/AppDAO.kt index de8d433..6814845 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/db/AppDAO.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/db/AppDAO.kt @@ -194,4 +194,20 @@ interface AppDAO { */ @Query("SELECT openingHours, news FROM offer_canteen LIMIT 1") fun getCanteenInfo(): CanteenOfferTuple + + /** + * Retrieve opening hours for the fetched canteen. + * + * @return opening hours for the canteen + */ + @Query("SELECT openingHours FROM offer_canteen LIMIT 1") + fun getCanteenOpeningHours(): LiveData + + /** + * Retrieve news for the fetched canteen. + * + * @return news for the canteen + */ + @Query("SELECT news FROM offer_canteen LIMIT 1") + fun getCanteenNews(): LiveData } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt b/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt index f95e3a4..7e953e7 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt @@ -78,6 +78,20 @@ class AppRepository(app: Application) { */ fun getCanteenInfo(): CanteenOfferTuple = dao.getCanteenInfo() + /** + * Retrieve opening hours for the fetched canteen. + * + * @return opening hours for the canteen + */ + fun getCanteenOpeningHours(): LiveData = dao.getCanteenOpeningHours() + + /** + * Retrieve news for the fetched canteen. + * + * @return news for the canteen + */ + fun getCanteenNews(): LiveData = dao.getCanteenNews() + /** * Retrieves all canteen offers that match given day. * diff --git a/app/src/main/java/com/denizk0461/weserplaner/exception/InvalidContentIdException.kt b/app/src/main/java/com/denizk0461/weserplaner/exception/InvalidContentIdException.kt new file mode 100644 index 0000000..b1cb5db --- /dev/null +++ b/app/src/main/java/com/denizk0461/weserplaner/exception/InvalidContentIdException.kt @@ -0,0 +1,6 @@ +package com.denizk0461.weserplaner.exception + +import java.io.IOException + +class InvalidContentIdException : IOException() { +} \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/fragment/CanteenFragment.kt b/app/src/main/java/com/denizk0461/weserplaner/fragment/CanteenFragment.kt index 100ecc3..523be60 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/fragment/CanteenFragment.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/fragment/CanteenFragment.kt @@ -41,13 +41,13 @@ class CanteenFragment : AppFragment() { * Locally saved opening hours to quickly access them without querying the database on every * opening of the bottom sheet. */ - private var openingHours: String = "" +// private var openingHours: String = "" /** * Locally saved news to quickly access them without querying the database on every opening of * the corresponding bottom sheet. */ - private var news: String = "" +// private var news: String = "" /** * Locally stored dates to populate the TabLayout with. @@ -76,7 +76,7 @@ class CanteenFragment : AppFragment() { binding.buttonNotifications.setOnClickListener { openBottomSheet(getTextSheet( getString(R.string.canteen_news_sheet_title), - news, + contentId = TextSheetContentId.NEWS, )) } @@ -114,7 +114,7 @@ class CanteenFragment : AppFragment() { R.string.canteen_opening_hours, getCurrentlySelectedCanteenName() ), - openingHours + contentId = TextSheetContentId.OPENING_HOURS, ) ) } @@ -181,10 +181,11 @@ class CanteenFragment : AppFragment() { // Retrieve further information about this canteen from the database viewModel.getCanteenInfo().also { info -> - openingHours = info.openingHours - news = info.news - - binding.buttonNotifications.visibility = if (news.isBlank()) { + /* + * Set visibility of the notifications icon depending on whether news are available. + * TODO change this to a BadgeDrawable later + */ + binding.buttonNotifications.visibility = if (info.news.isBlank()) { View.GONE } else { View.VISIBLE diff --git a/app/src/main/java/com/denizk0461/weserplaner/model/TextSheetContentId.kt b/app/src/main/java/com/denizk0461/weserplaner/model/TextSheetContentId.kt new file mode 100644 index 0000000..6c8e515 --- /dev/null +++ b/app/src/main/java/com/denizk0461/weserplaner/model/TextSheetContentId.kt @@ -0,0 +1,8 @@ +package com.denizk0461.weserplaner.model + +object TextSheetContentId { + + const val PASS_RAW_STRING = -1 + const val OPENING_HOURS = 0 + const val NEWS = 1 +} \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/sheet/TextSheet.kt b/app/src/main/java/com/denizk0461/weserplaner/sheet/TextSheet.kt index d509eb7..968218d 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/sheet/TextSheet.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/sheet/TextSheet.kt @@ -2,9 +2,13 @@ package com.denizk0461.weserplaner.sheet import android.os.Bundle import android.view.View +import androidx.fragment.app.viewModels import com.denizk0461.weserplaner.R import com.denizk0461.weserplaner.data.viewBinding import com.denizk0461.weserplaner.databinding.SheetTextBinding +import com.denizk0461.weserplaner.exception.InvalidContentIdException +import com.denizk0461.weserplaner.model.TextSheetContentId +import com.denizk0461.weserplaner.viewmodel.TextSheetViewModel /** * Bottom sheet used for displaying any sort of text to the user. @@ -14,22 +18,49 @@ class TextSheet : AppSheet(R.layout.sheet_text) { // View binding private val binding: SheetTextBinding by viewBinding(SheetTextBinding::bind) + // View model; used to retrieve certain texts as LiveData rather than receiving the raw string + private val viewModel: TextSheetViewModel by viewModels() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Retrieve headline for the window val header = arguments?.getString("header") ?: "" - // Retrieve content for the window - val content = arguments?.getString("content") ?: "" + /* + * Retrieve certain ID to denote which text content LiveData should be observed; if this is + * -1, assume that a raw string has been passed instead + */ + val contentId = arguments?.getInt("contentId") ?: TextSheetContentId.PASS_RAW_STRING + + // Check whether an ID has passed to use LiveData + val content = if (contentId == TextSheetContentId.PASS_RAW_STRING) { + // Retrieve content for the window as raw string if this has been picked + arguments?.getString("content") ?: "" + } else "" // This empty string will be unused // Set whether the sheet should be cancellable by actions such as swiping val isSheetCancellable = arguments?.getBoolean("isCancellable") == true - // Set text values - binding.apply { - textHeader.text = header - textContent.text = content + /* + * Set text header. + * TODO update this when contentId is set and canteen could change while the sheet is open! + */ + binding.textHeader.text = header + + // Set content to raw string passed if ID says so + if (contentId == -1) { + binding.textContent.text = content + } else (when (contentId) { + // Observe LiveData if corresponding ID has been passed + TextSheetContentId.OPENING_HOURS -> viewModel.getCanteenOpeningHours() + TextSheetContentId.NEWS -> viewModel.getCanteenNews() + else -> throw InvalidContentIdException() + }).observe(viewLifecycleOwner) { observedContent -> + // Show the content + binding.textContent.text = (observedContent ?: "") + // If the content is empty, tell the user + .ifBlank { emptyContentStringFor(contentId) } } // Set up an appropriate close button depending on whether the sheet is cancellable @@ -45,4 +76,16 @@ class TextSheet : AppSheet(R.layout.sheet_text) { binding.buttonCancel.visibility = View.GONE } } + + /** + * Retrieves a string to show to the user if the content is empty. + * + * @param contentId used to determine which string res should be used + * @return localised string to show the user + */ + private fun emptyContentStringFor(contentId: Int) = getString(when (contentId) { + TextSheetContentId.OPENING_HOURS -> R.string.text_sheet_empty_opening_hours + TextSheetContentId.NEWS -> R.string.text_sheet_empty_news + else -> R.string.error_generic + }) } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/TextSheetViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/TextSheetViewModel.kt new file mode 100644 index 0000000..43d6d19 --- /dev/null +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/TextSheetViewModel.kt @@ -0,0 +1,23 @@ +package com.denizk0461.weserplaner.viewmodel + +import android.app.Application +import androidx.lifecycle.LiveData + +class TextSheetViewModel(application: Application) : AppViewModel(application) { + + /** + * Retrieve opening hours for the fetched canteen. + * Used when contentId = [com.denizk0461.weserplaner.model.TextSheetContentId.OPENING_HOURS] + * + * @return opening hours for the canteen + */ + fun getCanteenOpeningHours(): LiveData = repo.getCanteenOpeningHours() + + /** + * Retrieve news for the fetched canteen. + * Used when contentId = [com.denizk0461.weserplaner.model.TextSheetContentId.NEWS] + * + * @return news for the canteen + */ + fun getCanteenNews(): LiveData = repo.getCanteenNews() +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_canteen.xml b/app/src/main/res/layout/fragment_canteen.xml index 1c5fdc7..7bc3310 100644 --- a/app/src/main/res/layout/fragment_canteen.xml +++ b/app/src/main/res/layout/fragment_canteen.xml @@ -31,7 +31,7 @@ android:layout_height="wrap_content" android:text="@string/title_food" android:textSize="28sp" - android:fontFamily="@font/lato_bolditalic" + android:fontFamily="@font/lato_blackitalic" android:singleLine="true" android:ellipsize="marquee" android:marqueeRepeatLimit="marquee_forever" diff --git a/app/src/main/res/layout/fragment_event.xml b/app/src/main/res/layout/fragment_event.xml index aee3840..c3c99e1 100644 --- a/app/src/main/res/layout/fragment_event.xml +++ b/app/src/main/res/layout/fragment_event.xml @@ -18,7 +18,7 @@ android:layout_height="wrap_content" android:text="@string/title_schedule" android:textSize="28sp" - android:fontFamily="@font/lato_bolditalic" + android:fontFamily="@font/lato_blackitalic" android:layout_marginHorizontal="16dp" android:layout_marginTop="16dp" android:layout_marginBottom="8dp" diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 83806bd..de6ad4a 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -20,7 +20,7 @@ android:layout_marginHorizontal="16dp" android:layout_marginTop="16dp" android:layout_marginBottom="8dp" - android:fontFamily="@font/lato_bolditalic" + android:fontFamily="@font/lato_blackitalic" android:text="@string/title_settings" app:layout_scrollFlags="scroll|exitUntilCollapsed" android:textSize="28sp"/> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 320dbb4..b821f4f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,7 +1,8 @@ - + Hey, danke, dass Du meine App ausprobierst! ~Deniz + Ein Fehler ist aufgetreten. Montag Dienstag @@ -68,6 +69,10 @@ Wechsle Mensa Aktualisiere Angebote + + The Öffnungszeiten für diese Mensa können nicht angezeigt werden. + Es sind keine Neuigkeiten verfügbar. + Lizenzen Dein Stundenplan @@ -79,7 +84,7 @@ Uni-Mensa Café Central - Mensa NW1 + Mensa NW1 Cafeteria GW2 Mensa Neustadtswall Mensa Werderstraße diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e819034..27a7589 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,8 @@ - + WeserPlaner Hey, thank you for trying out my app! ~Deniz + An error occurred. Monday Tuesday @@ -69,6 +70,10 @@ Switch canteen Refresh offers + + The opening hours for this canteen could not be downloaded. + No news are available. + Licences Android developer resources by Google.\nhttps://developer.android.com/\nandroidx.appcompat:appcompat:1.6.1\nandroidx.constraintlayout:constraintlayout:2.1.4\nandroidx.core:core-ktx:1.10.0\nandroidx.fragment:fragment-ktx:1.6.0-beta01\nandroidx.navigation:navigation-fragment-ktx:2.5.3\nandroidx.navigation:navigation-ui-ktx:2.5.3\nandroidx.preference:preference-ktx:1.2.0\nandroidx.room:room-runtime:2.5.1\nandroidx.room:room-compiler:2.5.1\nandroidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01\n\nDesign guidelines, icons, and colour palette by Google.\nhttps://m3.material.io/\ncom.google.android.material:material:1.9.0\n\nAdditional icons by Flaticon.\nhttps://www.flaticon.com/\n\nWeb scraping functionality by Jonathan Hedley.\nhttps://jhy.io/\nhttps://jsoup.org/\norg.jsoup:jsoup:1.15.4\n\nApp developed by Deniz Düzgören.\ndenizk0461@gmail.com\ndeniz7@uni-bremen.de @@ -81,7 +86,7 @@ Uni-Mensa Café Central - Mensa NW1 + Mensa NW1 Cafeteria GW2 Mensa Neustadtswall Mensa Werderstraße