WeserPlaner 1.0.3: adjusted layout of AllergenSheet.kt to display allergens and additives separately; FetcherActivity.kt now features a button to go directly to the user's schedule, if logged in; replaced toast messages with snack bars; ScheduleUpdateSheet.kt now notifies the user about database transactions via snack bar; schedule view now tells the user if there are no events scheduled for a day

This commit is contained in:
denizk0461
2023-05-14 23:09:06 +02:00
parent 8f69b5f381
commit 1c31d422fa
22 changed files with 261 additions and 85 deletions
+2 -2
View File
@@ -12,8 +12,8 @@ android {
applicationId "com.denizk0461.weserplaner"
minSdk 24
targetSdk 33
versionCode 6
versionName "1.0.2"
versionCode 7
versionName "1.0.3"
resourceConfigurations += ["en", "de"]
+2 -2
View File
@@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 6,
"versionName": "1.0.2",
"versionCode": 7,
"versionName": "1.0.3",
"outputFile": "app-release.apk"
}
],
@@ -10,6 +10,7 @@ import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModelProvider
import com.denizk0461.weserplaner.R
import com.denizk0461.weserplaner.data.showErrorSnackBar
import com.denizk0461.weserplaner.data.showSnackBar
import com.denizk0461.weserplaner.data.showToast
import com.denizk0461.weserplaner.databinding.ActivityFetcherBinding
import com.denizk0461.weserplaner.model.TextSheetContentId
@@ -50,7 +51,11 @@ class FetcherActivity : FragmentActivity() {
setContentView(binding.root)
// Remind the user of the help button
showToast(this, getString(R.string.toast_info_reminder))
theme.showSnackBar(
binding.coordinatorLayout,
getString(R.string.fetch_snack_info_reminder),
binding.bottomAppBar,
)
// Enabling JavaScript. See comment above lint suppression for reason why this is done.
binding.webview.settings.apply {
@@ -104,15 +109,19 @@ class FetcherActivity : FragmentActivity() {
}.show(supportFragmentManager, TextSheet::class.java.simpleName)
true
}
R.id.schedule -> {
binding.webview.loadUrl(scheduleUrl)
true
}
else -> false
}
}
/*
* Attempt to load the user-set Stud.IP front page. Redirects to login page if user is
* Attempt to load the user's Stud.IP schedule page. Redirects to login page if user is
* not logged in.
*/
binding.webview.loadUrl("https://elearning.uni-bremen.de/index.php?again=yes")
binding.webview.loadUrl(scheduleUrl)
binding.fab.setOnClickListener {
@@ -146,18 +155,18 @@ class FetcherActivity : FragmentActivity() {
} catch (e: IOException) {
// Let the user know that an error occurred
theme.showErrorSnackBar(
binding.rootView,
binding.coordinatorLayout,
getString(R.string.fetch_error_snack),
binding.bottomAppBar
binding.bottomAppBar,
)
}
}
} else {
// Tell the user that they must navigate to their timetable
theme.showErrorSnackBar(
binding.rootView,
binding.coordinatorLayout,
getString(R.string.fetch_error_webpage_snack),
binding.bottomAppBar
binding.bottomAppBar,
)
}
}
@@ -76,19 +76,15 @@ class CanteenOfferItemAdapter(
// Display
if (position == (offers.size - 1) && difference > 0) {
holder.binding.textDifference.apply {
visibility = View.VISIBLE
text = if (difference == 1) {
context.getString(R.string.canteen_item_difference_text_one)
} else {
context.getString(R.string.canteen_item_difference_text_other, difference)
}
holder.binding.differenceContainer.visibility = View.VISIBLE
holder.binding.textDifference.text = if (difference == 1) {
context.getString(R.string.canteen_item_difference_text_one)
} else {
context.getString(R.string.canteen_item_difference_text_other, difference)
}
} else {
holder.binding.textDifference.apply {
visibility = View.GONE
text = ""
}
holder.binding.differenceContainer.visibility = View.GONE
holder.binding.textDifference.text = ""
}
/*
@@ -2,12 +2,13 @@ package com.denizk0461.weserplaner.adapter
import android.content.res.ColorStateList
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.denizk0461.weserplaner.data.AppDiffUtilCallback
import com.google.android.material.R
import com.denizk0461.weserplaner.R
import com.denizk0461.weserplaner.data.getThemedColor
import com.denizk0461.weserplaner.data.parseToMinutes
import com.denizk0461.weserplaner.model.StudIPEvent
@@ -19,7 +20,7 @@ import java.util.*
*
* @param currentDay current day that is used to show only a given day's events (0 = Monday,
* 4 = Friday)
* 4 = Friday, 6 = Sunday)
* @param onClickListener used for listening to clicks and long presses
*/
class StudIPEventItemAdapter(
@@ -65,9 +66,28 @@ class StudIPEventItemAdapter(
override fun getItemCount(): Int = events.size
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
// Retrieve item for current position
val currentItem = events[position]
// Context for easier reference
val context = holder.binding.root.context
// Display a notice to the user saying they have no events scheduled for the day
if (currentItem.eventId == -1) {
holder.binding.cardBackground.visibility = View.GONE
holder.binding.noEventsContainer.visibility = View.VISIBLE
holder.binding.textNoEvents.text = context.getString(
R.string.schedule_no_events,
context.resources.getStringArray(R.array.weekdays)[currentDay]
)
return
}
// Set visibility of the elements accordingly if there are events scheduled
holder.binding.cardBackground.visibility = View.VISIBLE
holder.binding.noEventsContainer.visibility = View.GONE
// Set up text fields with corresponding values
holder.binding.textTitle.text = currentItem.title
holder.binding.textLecturers.text = currentItem.lecturer
@@ -77,14 +97,17 @@ class StudIPEventItemAdapter(
holder.binding.textTimeslot.text = currentItem.timeslot()
// Get current theme
val theme = holder.binding.root.context.theme
val theme = context.theme
/*
* Highlight the next upcoming course of the day if the user selected the option, if the day
* of the adapter matches the current day, and if no other course has been highlighted, to
* avoid double highlighting.
*/
if (highlightNextCourse && !isAnyCourseHighlighted && currentItem.isCurrentCourse(currentCalendar)) {
if (highlightNextCourse &&
!isAnyCourseHighlighted &&
currentItem.isCurrentCourse(currentCalendar)
) {
// Ensure that no other course will be highlighted
isAnyCourseHighlighted = true
@@ -98,12 +121,12 @@ class StudIPEventItemAdapter(
}
// Set the divider colour to the text colour
holder.binding.divider.dividerColor =
theme.getThemedColor(com.denizk0461.weserplaner.R.attr.colorText)
theme.getThemedColor(R.attr.colorText)
// Set ripple colour
holder.binding.linearLayout.background = getDrawable(
holder.binding.root.context,
com.denizk0461.weserplaner.R.drawable.selectable_item_background_highlighted,
R.drawable.selectable_item_background_highlighted,
)
// Otherwise, apply colours to ensure that the item will not be highlighted
@@ -111,7 +134,9 @@ class StudIPEventItemAdapter(
holder.binding.cardBackground.apply {
// Set the card's background colour to its default value
backgroundTintList =
ColorStateList.valueOf(theme.getThemedColor(R.attr.colorSurface))
ColorStateList.valueOf(theme.getThemedColor(
com.google.android.material.R.attr.colorSurface
))
// Set the card's stroke to its default colour
strokeColor = theme.getThemedColor(R.attr.colorOutlineVariant)
@@ -122,7 +147,7 @@ class StudIPEventItemAdapter(
// Set ripple colour
holder.binding.linearLayout.background = getDrawable(
holder.binding.root.context,
com.denizk0461.weserplaner.R.drawable.selectable_item_background,
R.drawable.selectable_item_background,
)
}
@@ -10,6 +10,7 @@ import androidx.viewpager2.widget.ViewPager2
import com.denizk0461.weserplaner.R
import com.denizk0461.weserplaner.activity.FetcherActivity
import com.denizk0461.weserplaner.adapter.StudIPEventPageAdapter
import com.denizk0461.weserplaner.data.showSnackBar
import com.denizk0461.weserplaner.databinding.FragmentEventBinding
import com.denizk0461.weserplaner.sheet.ScheduleUpdateSheet
import com.denizk0461.weserplaner.viewmodel.EventViewModel
@@ -144,6 +145,15 @@ class EventFragment : AppFragment() {
binding.fabAddEvent.extend()
}
/**
* Creates and shows a snack bar.
*
* @param text content to display in the snack bar
*/
fun showSnackBar(text: String) {
context.theme.showSnackBar(binding.coordinatorLayout, text)
}
// Invalidate the view binding
override fun onDestroyView() {
super.onDestroyView()
@@ -96,7 +96,20 @@ class EventPageFragment : AppFragment(), StudIPEventItemAdapter.OnClickListener
// Set up LiveData observer to refresh the view on update
viewModel.getEventsForDay(currentDay).observe(viewLifecycleOwner) { events ->
eventAdapter.setNewData(events)
eventAdapter.setNewData(events.ifEmpty { listOf(
// Use an event with eventId = -1 to denote that there are no events for this day
StudIPEvent(
-1,
"",
"",
"",
0,
"",
"",
0,
0,
)
) })
}
}
@@ -238,8 +238,7 @@ class SettingsFragment : AppFragment() {
licencesLongClick = 0
viewModel.preferenceExperimentalSettingsEnabled = true
binding.cardExperimentalSettings.visibility = View.VISIBLE
context.theme.showSnackBar(
binding.coordinatorLayout,
showSnackBar(
getString(R.string.settings_unlocked_experiments),
)
} else {
@@ -320,8 +319,7 @@ class SettingsFragment : AppFragment() {
binding.buttonHideExperiments.setOnClickListener {
viewModel.preferenceExperimentalSettingsEnabled = false
binding.cardExperimentalSettings.visibility = View.GONE
context.theme.showSnackBar(
binding.coordinatorLayout,
showSnackBar(
getString(R.string.settings_hide_experiments),
)
}
@@ -397,8 +395,7 @@ class SettingsFragment : AppFragment() {
viewModel.nukeEverything()
showToast(context, "Nuked everything")
}
else -> context.theme.showSnackBar(
binding.coordinatorLayout,
else -> showSnackBar(
getString(R.string.settings_dev_codes_invalid)
)
}
@@ -418,6 +415,15 @@ class SettingsFragment : AppFragment() {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link)))
}
/**
* Creates and shows a snack bar.
*
* @param text content to display in the snack bar
*/
fun showSnackBar(text: String) {
context.theme.showSnackBar(binding.coordinatorLayout, text)
}
/**
* Decodes Base64 to a regular string.
*
@@ -4,10 +4,11 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.NavHostFragment
import com.denizk0461.weserplaner.R
import com.denizk0461.weserplaner.data.showToast
import com.denizk0461.weserplaner.data.viewBinding
import com.denizk0461.weserplaner.databinding.SheetAllergenConfigBinding
import com.denizk0461.weserplaner.fragment.SettingsFragment
import com.denizk0461.weserplaner.model.AllergenPreferences
import com.denizk0461.weserplaner.viewmodel.AllergenConfigViewModel
@@ -26,6 +27,17 @@ class AllergenConfigSheet : AppSheet(R.layout.sheet_allergen_config) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Set up FAB behaviour for parent fragment's FAB if activity is not null
val parentFragment = activity?.let { activity ->
// Retrieve parent fragment to access its functions
val navHostFragment = activity
.supportFragmentManager
.fragments[0] as NavHostFragment
navHostFragment
.childFragmentManager
.primaryNavigationFragment as SettingsFragment
}
// Retrieve allergens as currently set by the user from view model
val currentAllergenConfig = AllergenPreferences.construct(
viewModel.preferenceAllergenConfig
@@ -73,7 +85,7 @@ class AllergenConfigSheet : AppSheet(R.layout.sheet_allergen_config) {
parentFragment?.setFragmentResult("allergenConfig", Bundle())
// Tell the user that saving was successful
showToast(context, getString(R.string.allergens_config_confirmation))
parentFragment?.showSnackBar(getString(R.string.allergens_config_confirmation))
// Close the sheet
dismiss()
@@ -84,20 +84,28 @@ class AllergenSheet : AppSheet(R.layout.sheet_allergen) {
}
}
// Allergen and additive notice
// textContent.text = offer.allergens.compileAllergenString()
val (a, b) = offer.allergens.compileStrings()
// Retrieve allergen and additive strings
val (allergens, additives) = offer.allergens.compileStrings()
if (a.isBlank() && b.isBlank()) {
// Display notices for allergens and additives, if necessary
if (allergens.isBlank() && additives.isBlank()) {
// Tell the user that no allergens and no additives are present in the offer
textAllergensTitle.text = getString(R.string.allergens_none)
textAllergensContent.visibility = View.GONE
textAdditivesTitle.visibility = View.GONE
textAdditivesContent.visibility = View.GONE
} else {
// Set allergen and additives accordingly if any are present
textAllergensTitle.text = getString(R.string.allergens_allergens_title)
textAllergensContent.text = getString(R.string.allergens_content_template, a)
textAllergensContent.text = getString(
R.string.allergens_content_template,
allergens,
)
textAdditivesTitle.text = getString(R.string.allergens_additives_title)
textAdditivesContent.text = getString(R.string.allergens_content_template, b)
textAdditivesContent.text = getString(
R.string.allergens_content_template,
additives,
)
}
// Show a price, if one is available
@@ -124,22 +132,23 @@ class AllergenSheet : AppSheet(R.layout.sheet_allergen) {
}
/**
* Retrieves localised strings for all allergens present in a given offer and compiles them into
* a human-readable string, if any allergens are present.
* Retrieves localised strings for all allergens and additives present in a given offer and
* compiles them into human-readable strings, if any are present.
*
* @return a string of all allergens
* @receiver string to parse allergens and additives from
* @return allergens and additives formatted as strings
*/
private fun String.compileStrings(): Pair<String, String> {
// Let the user know if no allergens are present
// Return empty values if the received string is blank
if (this.isBlank()) return Pair("", "")
// Stores all localised additives
val additiveList = mutableListOf<String>()
// Stores all localised allergens
val allergenList = mutableListOf<String>()
// Stores all localised additives
val additiveList = mutableListOf<String>()
// Split all allergens to iterate through them
val allergens = this.replace(" ", "").split(",")
@@ -156,16 +165,10 @@ class AllergenSheet : AppSheet(R.layout.sheet_allergen) {
}
}
// Insert the items into a template string
// return getString(
// R.string.allergens_contains,
// allergenList.joinToString(", ").ifBlank {
// getString(R.string.allergens_single_none)
// },
// additiveList.joinToString(", ").ifBlank {
// getString(R.string.allergens_single_none)
// },
// )
/*
* Join the lists to formatted strings, separated by commas. Put a localised "none" if
* either no allergens or additives could be found respectively.
*/
return Pair(
allergenList.joinToString(", ").ifBlank {
getString(R.string.allergens_single_none)
@@ -6,6 +6,7 @@ import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.NavHostFragment
import androidx.transition.TransitionManager
import com.denizk0461.weserplaner.R
import com.denizk0461.weserplaner.data.getParcelableCompat
@@ -18,6 +19,7 @@ import com.denizk0461.weserplaner.data.viewBinding
import com.denizk0461.weserplaner.databinding.SheetScheduleUpdateBinding
import com.denizk0461.weserplaner.exception.AcademicQuarterNotApplicableException
import com.denizk0461.weserplaner.exception.ParcelNotFoundException
import com.denizk0461.weserplaner.fragment.EventFragment
import com.denizk0461.weserplaner.model.StudIPEvent
import com.denizk0461.weserplaner.viewmodel.ScheduleUpdateViewModel
import com.google.android.material.timepicker.MaterialTimePicker
@@ -51,6 +53,17 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Set up FAB behaviour for parent fragment's FAB if activity is not null
val parentFragment = activity?.let { activity ->
// Retrieve parent fragment to access its functions
val navHostFragment = activity
.supportFragmentManager
.fragments[0] as NavHostFragment
navHostFragment
.childFragmentManager
.primaryNavigationFragment as EventFragment
}
if (arguments?.getBoolean("isEditing") == true) {
try {
@@ -88,7 +101,15 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update) {
* accidentally deleting an event.
*/
if (hasClickedDelete) {
// Delete the event
viewModel.delete(event)
// Tell the user that the event has been deleted
parentFragment?.showSnackBar(
getString(R.string.sheet_schedule_snack_delete)
)
// Dismiss the sheet upon deletion
dismiss()
} else {
@@ -133,6 +154,12 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update) {
colour = colour,
)
)
// Tell the user that the event has been updated
parentFragment?.showSnackBar(
getString(R.string.sheet_schedule_snack_update)
)
// Dismiss the sheet upon update
dismiss()
}
@@ -188,6 +215,11 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update) {
)
)
// Tell the user that the event has been updated
parentFragment?.showSnackBar(
getString(R.string.sheet_schedule_snack_add)
)
// Dismiss the sheet upon update
dismiss()
}
+1 -1
View File
@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="#000000"
<vector android:height="24dp" android:tint="?attr/colorOnSurfaceVariant"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M16.24,11.51l1.57,-1.57l-3.75,-3.75l-1.57,1.57L8.35,3.63c-0.78,-0.78 -2.05,-0.78 -2.83,0l-1.9,1.9c-0.78,0.78 -0.78,2.05 0,2.83l4.13,4.13L3,17.25V21h3.75l4.76,-4.76l4.13,4.13c0.95,0.95 2.23,0.6 2.83,0l1.9,-1.9c0.78,-0.78 0.78,-2.05 0,-2.83L16.24,11.51zM9.18,11.07L5.04,6.94l1.89,-1.9c0,0 0,0 0,0l1.27,1.27L7.02,7.5l1.41,1.41l1.19,-1.19l1.45,1.45L9.18,11.07zM17.06,18.96l-4.13,-4.13l1.9,-1.9l1.45,1.45l-1.19,1.19l1.41,1.41l1.19,-1.19l1.27,1.27L17.06,18.96z"/>
+5
View File
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12.126,8.125l1.937,-1.937 3.747,3.747 -1.937,1.938zM20.71,5.63l-2.34,-2.34a1,1 0,0 0,-1.41 0l-1.83,1.83 3.75,3.75L20.71,7a1,1 0,0 0,0 -1.37zM2,5l6.63,6.63L3,17.25V21h3.75l5.63,-5.62L18,21l2,-2L4,3 2,5z"/>
</vector>
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/>
</vector>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root_view"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
@@ -2,6 +2,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.EventFragment">
+20 -3
View File
@@ -47,10 +47,27 @@
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/text_difference"
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/difference_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginHorizontal="4dp"
android:scaleType="centerInside"
app:tint="?attr/colorText"
android:src="@drawable/visibility_off"/>
<TextView
android:id="@+id/text_difference"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
+26 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingHorizontal="8dp"
android:paddingVertical="4dp"
android:orientation="vertical">
@@ -55,4 +55,28 @@
</com.google.android.material.card.MaterialCardView>
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/no_events_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginHorizontal="4dp"
android:scaleType="centerInside"
app:tint="?attr/colorText"
android:src="@drawable/edit_off"/>
<TextView
android:id="@+id/text_no_events"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/schedule_no_events"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
+12 -6
View File
@@ -4,19 +4,25 @@
<item
android:id="@+id/close"
android:icon="@drawable/cross"
android:title="@string/fetch_bar_close_title"
android:title="@string/fetch_bar_close_desc"
android:contentDescription="@string/fetch_bar_close_desc"
app:showAsAction="ifRoom"/>
app:showAsAction="always"/>
<item
android:id="@+id/refresh"
android:icon="@drawable/refresh"
android:title="@string/fetch_bar_refresh_title"
android:title="@string/fetch_bar_refresh_desc"
android:contentDescription="@string/fetch_bar_refresh_desc"
app:showAsAction="ifRoom"/>
app:showAsAction="always"/>
<item
android:id="@+id/help"
android:icon="@drawable/info"
android:title="@string/fetch_bar_help_title"
android:title="@string/fetch_bar_help_desc"
android:contentDescription="@string/fetch_bar_help_desc"
app:showAsAction="ifRoom"/>
app:showAsAction="always"/>
<item
android:id="@+id/schedule"
android:icon="@drawable/design"
android:title="@string/fetch_bar_schedule_desc"
android:contentDescription="@string/fetch_bar_schedule_desc"
app:showAsAction="always"/>
</menu>
+8 -2
View File
@@ -34,24 +34,30 @@
<string name="toast_fetch_finished_one">Dein Stundenplan wurde aktualisiert, doch eine Veranstaltung konnte nicht heruntergeladen werden.</string>
<string name="toast_fetch_finished_other">Dein Stundenplan wurde aktualisiert, doch %d Veranstaltungen konnten nicht heruntergeladen werden.</string>
<string name="toast_info_reminder">Klick\' das Info-Icon unten, falls du Hilfe benötigst.</string>
<string name="fetch_snack_info_reminder">Klick\' das Info-Icon unten, falls du Hilfe benötigst.</string>
<string name="fetch_bar_close_title">Schließen</string>
<string name="fetch_bar_close_desc">Schließe die Webseite, ohne etwas zu speichern</string>
<string name="fetch_bar_refresh_title">Aktualisieren</string>
<string name="fetch_bar_refresh_desc">Aktualisiere die Webseite</string>
<string name="fetch_bar_help_title">Hilfe</string>
<string name="fetch_bar_help_desc">Zeige Hilfe</string>
<string name="fetch_bar_schedule_title">Stundenplan</string>
<string name="fetch_bar_schedule_desc">Gehe zu deinem Stundenplan</string>
<string name="fetch_bar_help_sheet_title">Wie du deinen Stundenplan in der App speichern kannst</string>
<string name="fetch_bar_help_sheet_content"> • Logge dich mit deinem Stud.IP-Login ein\n • Öffne deinen Stundenplan (falls er sich nicht automatisch öffnet)\n • Klicke auf den \'Speichern\'-Knopf, der unten in der rechten Ecke auftauchen sollte\n • Fertig!</string>
<string name="fetch_bar_help_sheet_content"> • Logge dich mit deinem Stud.IP-Login ein\n • Öffne deinen Stundenplan, falls er sich nicht automatisch öffnet, indem du in der unteren Leiste auf das rechte Logo klickst, das wie ein Stift und ein Lineal aussieht\n • Klicke auf den \'Speichern\'-Knopf, der unten in der rechten Ecke auftaucht\n • Fertig!</string>
<string name="fetch_bar_save_desc">Speichere den Stundenplan in der App ab</string>
<string name="schedule_fab_add_text">Neue Veranstaltung</string>
<string name="schedule_no_events">%ss hast du keine Veranstaltungen.</string>
<string name="save">Speichern</string>
<string name="delete">Löschen</string>
<string name="sheet_schedule_update_delete_confirm">Sicher?</string>
<string name="cancel">Abbrechen</string>
<string name="confirm">Bestätigen</string>
<string name="sheet_schedule_snack_delete">Veranstaltung wurde gelöscht.</string>
<string name="sheet_schedule_snack_add">Veranstaltung wurde hinzugefügt.</string>
<string name="sheet_schedule_snack_update">Veranstaltung wurde aktualisiert.</string>
<string name="sheet_schedule_update_header_edit">Bestehende Veranstaltung bearbeiten</string>
<string name="sheet_schedule_update_header_add">Neue Veranstaltung hinzufügen</string>
<string name="sheet_schedule_update_title_hint">Veranstaltungstitel</string>
+8 -2
View File
@@ -35,24 +35,30 @@
<string name="toast_fetch_finished_one">Your schedule has been refreshed, but one item could not be saved.</string>
<string name="toast_fetch_finished_other">Your schedule has been refreshed, but %d items could not be saved.</string>
<string name="toast_info_reminder">Click the info icon at the bottom if you need any help here.</string>
<string name="fetch_snack_info_reminder">Click the info icon at the bottom if you need any help here.</string>
<string name="fetch_bar_close_title">Close</string>
<string name="fetch_bar_close_desc">Close the website without saving anything</string>
<string name="fetch_bar_refresh_title">Refresh</string>
<string name="fetch_bar_refresh_desc">Refresh the page</string>
<string name="fetch_bar_help_title">Help</string>
<string name="fetch_bar_help_desc">Show help</string>
<string name="fetch_bar_schedule_title">Schedule</string>
<string name="fetch_bar_schedule_desc">Go to your schedule</string>
<string name="fetch_bar_help_sheet_title">How to save your timetable in the app</string>
<string name="fetch_bar_help_sheet_content"> • Log in with your Stud.IP login\n • Open your timetable view (in case it doesn\'t open automatically)\n • Click the \'save\' button that should appear in the bottom right corner\n • Done!</string>
<string name="fetch_bar_help_sheet_content"> • Log in with your Stud.IP login\n • Open your timetable view, in case it doesn\'t open automatically, by clicking the rightmost icon in the bottom bar that looks like a pencil and a ruler\n • Click the \'save\' button that appears in the bottom right corner\n • Done!</string>
<string name="fetch_bar_save_desc">Save the timetable in the app</string>
<string name="schedule_fab_add_text">New event</string>
<string name="schedule_no_events">You don\'t have any events for %s.</string>
<string name="save">Save</string>
<string name="delete">Delete</string>
<string name="sheet_schedule_update_delete_confirm">Sure?</string>
<string name="cancel">Cancel</string>
<string name="confirm">Confirm</string>
<string name="sheet_schedule_snack_delete">Event has been deleted.</string>
<string name="sheet_schedule_snack_add">Event has been added.</string>
<string name="sheet_schedule_snack_update">Event has been updated.</string>
<string name="sheet_schedule_update_header_edit">Edit existing event</string>
<string name="sheet_schedule_update_header_add">Add new event</string>
<string name="sheet_schedule_update_title_hint">Event title</string>