Archived
Changed TextSheet to use a ViewModel for showing content that is fetched from the database. Uses TextSheetContentId to determine which LiveData to observe.
This commit is contained in:
@@ -14,6 +14,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|||||||
import com.denizk0461.weserplaner.R
|
import com.denizk0461.weserplaner.R
|
||||||
import com.denizk0461.weserplaner.exception.AcademicQuarterNotApplicableException
|
import com.denizk0461.weserplaner.exception.AcademicQuarterNotApplicableException
|
||||||
import com.denizk0461.weserplaner.exception.ParcelNotFoundException
|
import com.denizk0461.weserplaner.exception.ParcelNotFoundException
|
||||||
|
import com.denizk0461.weserplaner.model.TextSheetContentId
|
||||||
import com.denizk0461.weserplaner.sheet.TextSheet
|
import com.denizk0461.weserplaner.sheet.TextSheet
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlin.jvm.Throws
|
import kotlin.jvm.Throws
|
||||||
@@ -72,10 +73,15 @@ fun Resources.Theme.showErrorSnackBar(view: CoordinatorLayout, text: String, anc
|
|||||||
* @param content text content of the sheet
|
* @param content text content of the sheet
|
||||||
* @return sheet with text added
|
* @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()
|
val bundle = Bundle()
|
||||||
bundle.putString("header", header)
|
bundle.putString("header", header)
|
||||||
bundle.putString("content", content)
|
bundle.putString("content", content)
|
||||||
|
bundle.putInt("contentId", contentId)
|
||||||
bundle.putBoolean("isCancellable", true)
|
bundle.putBoolean("isCancellable", true)
|
||||||
sheet.arguments = bundle
|
sheet.arguments = bundle
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,4 +194,20 @@ interface AppDAO {
|
|||||||
*/
|
*/
|
||||||
@Query("SELECT openingHours, news FROM offer_canteen LIMIT 1")
|
@Query("SELECT openingHours, news FROM offer_canteen LIMIT 1")
|
||||||
fun getCanteenInfo(): CanteenOfferTuple
|
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<String>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve news for the fetched canteen.
|
||||||
|
*
|
||||||
|
* @return news for the canteen
|
||||||
|
*/
|
||||||
|
@Query("SELECT news FROM offer_canteen LIMIT 1")
|
||||||
|
fun getCanteenNews(): LiveData<String>
|
||||||
}
|
}
|
||||||
@@ -78,6 +78,20 @@ class AppRepository(app: Application) {
|
|||||||
*/
|
*/
|
||||||
fun getCanteenInfo(): CanteenOfferTuple = dao.getCanteenInfo()
|
fun getCanteenInfo(): CanteenOfferTuple = dao.getCanteenInfo()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve opening hours for the fetched canteen.
|
||||||
|
*
|
||||||
|
* @return opening hours for the canteen
|
||||||
|
*/
|
||||||
|
fun getCanteenOpeningHours(): LiveData<String> = dao.getCanteenOpeningHours()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve news for the fetched canteen.
|
||||||
|
*
|
||||||
|
* @return news for the canteen
|
||||||
|
*/
|
||||||
|
fun getCanteenNews(): LiveData<String> = dao.getCanteenNews()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all canteen offers that match given day.
|
* Retrieves all canteen offers that match given day.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.denizk0461.weserplaner.exception
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class InvalidContentIdException : IOException() {
|
||||||
|
}
|
||||||
@@ -41,13 +41,13 @@ class CanteenFragment : AppFragment() {
|
|||||||
* Locally saved opening hours to quickly access them without querying the database on every
|
* Locally saved opening hours to quickly access them without querying the database on every
|
||||||
* opening of the bottom sheet.
|
* 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
|
* Locally saved news to quickly access them without querying the database on every opening of
|
||||||
* the corresponding bottom sheet.
|
* the corresponding bottom sheet.
|
||||||
*/
|
*/
|
||||||
private var news: String = ""
|
// private var news: String = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locally stored dates to populate the TabLayout with.
|
* Locally stored dates to populate the TabLayout with.
|
||||||
@@ -76,7 +76,7 @@ class CanteenFragment : AppFragment() {
|
|||||||
binding.buttonNotifications.setOnClickListener {
|
binding.buttonNotifications.setOnClickListener {
|
||||||
openBottomSheet(getTextSheet(
|
openBottomSheet(getTextSheet(
|
||||||
getString(R.string.canteen_news_sheet_title),
|
getString(R.string.canteen_news_sheet_title),
|
||||||
news,
|
contentId = TextSheetContentId.NEWS,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ class CanteenFragment : AppFragment() {
|
|||||||
R.string.canteen_opening_hours,
|
R.string.canteen_opening_hours,
|
||||||
getCurrentlySelectedCanteenName()
|
getCurrentlySelectedCanteenName()
|
||||||
),
|
),
|
||||||
openingHours
|
contentId = TextSheetContentId.OPENING_HOURS,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -181,10 +181,11 @@ class CanteenFragment : AppFragment() {
|
|||||||
|
|
||||||
// Retrieve further information about this canteen from the database
|
// Retrieve further information about this canteen from the database
|
||||||
viewModel.getCanteenInfo().also { info ->
|
viewModel.getCanteenInfo().also { info ->
|
||||||
openingHours = info.openingHours
|
/*
|
||||||
news = info.news
|
* Set visibility of the notifications icon depending on whether news are available.
|
||||||
|
* TODO change this to a BadgeDrawable later
|
||||||
binding.buttonNotifications.visibility = if (news.isBlank()) {
|
*/
|
||||||
|
binding.buttonNotifications.visibility = if (info.news.isBlank()) {
|
||||||
View.GONE
|
View.GONE
|
||||||
} else {
|
} else {
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -2,9 +2,13 @@ package com.denizk0461.weserplaner.sheet
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
import com.denizk0461.weserplaner.R
|
import com.denizk0461.weserplaner.R
|
||||||
import com.denizk0461.weserplaner.data.viewBinding
|
import com.denizk0461.weserplaner.data.viewBinding
|
||||||
import com.denizk0461.weserplaner.databinding.SheetTextBinding
|
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.
|
* 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
|
// View binding
|
||||||
private val binding: SheetTextBinding by viewBinding(SheetTextBinding::bind)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
// Retrieve headline for the window
|
// Retrieve headline for the window
|
||||||
val header = arguments?.getString("header") ?: ""
|
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
|
// Set whether the sheet should be cancellable by actions such as swiping
|
||||||
val isSheetCancellable = arguments?.getBoolean("isCancellable") == true
|
val isSheetCancellable = arguments?.getBoolean("isCancellable") == true
|
||||||
|
|
||||||
// Set text values
|
/*
|
||||||
binding.apply {
|
* Set text header.
|
||||||
textHeader.text = header
|
* TODO update this when contentId is set and canteen could change while the sheet is open!
|
||||||
textContent.text = content
|
*/
|
||||||
|
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
|
// 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
|
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
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -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<String> = 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<String> = repo.getCanteenNews()
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/title_food"
|
android:text="@string/title_food"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp"
|
||||||
android:fontFamily="@font/lato_bolditalic"
|
android:fontFamily="@font/lato_blackitalic"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:marqueeRepeatLimit="marquee_forever"
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/title_schedule"
|
android:text="@string/title_schedule"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp"
|
||||||
android:fontFamily="@font/lato_bolditalic"
|
android:fontFamily="@font/lato_blackitalic"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:fontFamily="@font/lato_bolditalic"
|
android:fontFamily="@font/lato_blackitalic"
|
||||||
android:text="@string/title_settings"
|
android:text="@string/title_settings"
|
||||||
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
||||||
android:textSize="28sp"/>
|
android:textSize="28sp"/>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<resources>
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<!-- <string name="app_name">sixminutes</string>-->
|
<!-- <string name="app_name">sixminutes</string>-->
|
||||||
|
|
||||||
<string name="toast_first_launch">Hey, danke, dass Du meine App ausprobierst! ~Deniz</string>
|
<string name="toast_first_launch">Hey, danke, dass Du meine App ausprobierst! ~Deniz</string>
|
||||||
|
<string name="error_generic">Ein Fehler ist aufgetreten.</string>
|
||||||
|
|
||||||
<string name="monday">Montag</string>
|
<string name="monday">Montag</string>
|
||||||
<string name="tuesday">Dienstag</string>
|
<string name="tuesday">Dienstag</string>
|
||||||
@@ -68,6 +69,10 @@
|
|||||||
<string name="canteen_fab_switch_canteen_content_desc">Wechsle Mensa</string>
|
<string name="canteen_fab_switch_canteen_content_desc">Wechsle Mensa</string>
|
||||||
<string name="canteen_fab_refresh_content_desc">Aktualisiere Angebote</string>
|
<string name="canteen_fab_refresh_content_desc">Aktualisiere Angebote</string>
|
||||||
|
|
||||||
|
<!-- TODO replace 'this canteen' with %s -->
|
||||||
|
<string name="text_sheet_empty_opening_hours">The Öffnungszeiten für diese Mensa können nicht angezeigt werden.</string>
|
||||||
|
<string name="text_sheet_empty_news">Es sind keine Neuigkeiten verfügbar.</string>
|
||||||
|
|
||||||
<string name="sheet_licences_header">Lizenzen</string>
|
<string name="sheet_licences_header">Lizenzen</string>
|
||||||
|
|
||||||
<string name="title_schedule">Dein Stundenplan</string>
|
<string name="title_schedule">Dein Stundenplan</string>
|
||||||
@@ -79,7 +84,7 @@
|
|||||||
|
|
||||||
<string name="mensa_uni">Uni-Mensa</string>
|
<string name="mensa_uni">Uni-Mensa</string>
|
||||||
<string name="cafe_central">Café Central</string>
|
<string name="cafe_central">Café Central</string>
|
||||||
<string name="mensa_nw1">Mensa NW1</string>
|
<string name="mensa_nw1" tools:ignore="Typos">Mensa NW1</string>
|
||||||
<string name="cafeteria_gw2">Cafeteria GW2</string>
|
<string name="cafeteria_gw2">Cafeteria GW2</string>
|
||||||
<string name="mensa_neustadt">Mensa Neustadtswall</string>
|
<string name="mensa_neustadt">Mensa Neustadtswall</string>
|
||||||
<string name="mensa_werder">Mensa Werderstraße</string>
|
<string name="mensa_werder">Mensa Werderstraße</string>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<resources>
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<string name="app_name" translatable="false">WeserPlaner</string>
|
<string name="app_name" translatable="false">WeserPlaner</string>
|
||||||
|
|
||||||
<string name="toast_first_launch">Hey, thank you for trying out my app! ~Deniz</string>
|
<string name="toast_first_launch">Hey, thank you for trying out my app! ~Deniz</string>
|
||||||
|
<string name="error_generic">An error occurred.</string>
|
||||||
|
|
||||||
<string name="monday">Monday</string>
|
<string name="monday">Monday</string>
|
||||||
<string name="tuesday">Tuesday</string>
|
<string name="tuesday">Tuesday</string>
|
||||||
@@ -69,6 +70,10 @@
|
|||||||
<string name="canteen_fab_switch_canteen_content_desc">Switch canteen</string>
|
<string name="canteen_fab_switch_canteen_content_desc">Switch canteen</string>
|
||||||
<string name="canteen_fab_refresh_content_desc">Refresh offers</string>
|
<string name="canteen_fab_refresh_content_desc">Refresh offers</string>
|
||||||
|
|
||||||
|
<!-- TODO replace 'this canteen' with %s -->
|
||||||
|
<string name="text_sheet_empty_opening_hours">The opening hours for this canteen could not be downloaded.</string>
|
||||||
|
<string name="text_sheet_empty_news">No news are available.</string>
|
||||||
|
|
||||||
<string name="sheet_licences_header">Licences</string>
|
<string name="sheet_licences_header">Licences</string>
|
||||||
<string name="sheet_licences_content" translatable="false">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</string>
|
<string name="sheet_licences_content" translatable="false">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</string>
|
||||||
|
|
||||||
@@ -81,7 +86,7 @@
|
|||||||
|
|
||||||
<string name="mensa_uni">Uni-Mensa</string>
|
<string name="mensa_uni">Uni-Mensa</string>
|
||||||
<string name="cafe_central">Café Central</string>
|
<string name="cafe_central">Café Central</string>
|
||||||
<string name="mensa_nw1">Mensa NW1</string>
|
<string name="mensa_nw1" tools:ignore="Typos">Mensa NW1</string>
|
||||||
<string name="cafeteria_gw2">Cafeteria GW2</string>
|
<string name="cafeteria_gw2">Cafeteria GW2</string>
|
||||||
<string name="mensa_neustadt">Mensa Neustadtswall</string>
|
<string name="mensa_neustadt">Mensa Neustadtswall</string>
|
||||||
<string name="mensa_werder">Mensa Werderstraße</string>
|
<string name="mensa_werder">Mensa Werderstraße</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user