From df1d127a172462de056b912cea83d32e792093eb Mon Sep 17 00:00:00 2001 From: denizk0461 Date: Wed, 3 May 2023 14:16:32 +0200 Subject: [PATCH] Implemented functionality for adding a new event manually; added floating action buttons for adding an event and refreshing the canteen offers --- .../denizk0461/studip/data/StudIPParser.kt | 7 - .../com/denizk0461/studip/db/AppDatabase.kt | 2 +- .../com/denizk0461/studip/db/AppRepository.kt | 9 + .../studip/fragment/CanteenFragment.kt | 9 + .../studip/fragment/EventFragment.kt | 11 + .../studip/fragment/EventPageFragment.kt | 1 + .../denizk0461/studip/model/StudIPEvent.kt | 2 +- .../studip/sheet/ScheduleUpdateSheet.kt | 381 ++++++++++++------ .../viewmodel/ScheduleUpdateViewModel.kt | 7 + app/src/main/res/drawable/edit_calendar.xml | 5 + app/src/main/res/drawable/plus.xml | 5 + app/src/main/res/layout/fragment_canteen.xml | 59 ++- app/src/main/res/layout/fragment_event.xml | 18 +- app/src/main/res/layout/fragment_settings.xml | 4 +- .../main/res/layout/sheet_schedule_update.xml | 10 +- app/src/main/res/menu/menu_days.xml | 31 ++ app/src/main/res/values-de/strings.xml | 5 +- app/src/main/res/values/strings.xml | 5 +- 18 files changed, 416 insertions(+), 155 deletions(-) create mode 100644 app/src/main/res/drawable/edit_calendar.xml create mode 100644 app/src/main/res/drawable/plus.xml create mode 100644 app/src/main/res/menu/menu_days.xml 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 2ee0807..d5730c2 100644 --- a/app/src/main/java/com/denizk0461/studip/data/StudIPParser.kt +++ b/app/src/main/java/com/denizk0461/studip/data/StudIPParser.kt @@ -25,9 +25,6 @@ class StudIPParser(application: Application) { */ @Throws(IOException::class) fun parse(html: String): Int { - // Primary key value to uniquely identify entries in the database - var id = 0 - // Counts how many elements could not be successfully fetched var elementsNotFetched = 0 @@ -92,7 +89,6 @@ class StudIPParser(application: Application) { // Construct the newly scraped Stud.IP event val event = StudIPEvent( - eventId = id, title = parsedTitle, lecturer = parsedLecturers, room = entryInfo.getOrQuestionMark(1), @@ -104,9 +100,6 @@ class StudIPParser(application: Application) { // Add the new element to the temporary list newEvents.add(event) - - // Raise the primary key value by 1 to avoid not fulfilling the unique constraint - id += 1 } } 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 8e682cd..e426038 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 = 18, + version = 19, ) 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 27528ac..29ff86a 100644 --- a/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt +++ b/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt @@ -85,6 +85,15 @@ class AppRepository(app: Application) { */ fun getOffersByDay(day: Int): LiveData> = dao.getOffersByDay(day) + /** + * Inserts a new schedule element. + * + * @param event the event to save + */ + fun insert(event: StudIPEvent) { + dao.insert(event) + } + /** * Updates a schedule element. * diff --git a/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt index 3b481d0..209f22b 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt @@ -127,6 +127,15 @@ class CanteenFragment : AppFragment() { } } + // Set up floating action button for refreshing the canteen offers + binding.fabRefreshOffers.setOnClickListener { + // Display to the user that a refresh is in progress + binding.swipeRefreshLayout.isRefreshing = true + + // Refresh the offers + refresh() + } + // Set up the view pager's adapter viewPagerAdapter = CanteenOfferPageAdapter( childFragmentManager, diff --git a/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt index 0a91e2f..1d1850a 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt @@ -8,6 +8,7 @@ import androidx.fragment.app.viewModels import com.denizk0461.studip.R import com.denizk0461.studip.adapter.StudIPEventPageAdapter import com.denizk0461.studip.databinding.FragmentEventBinding +import com.denizk0461.studip.sheet.ScheduleUpdateSheet import com.denizk0461.studip.viewmodel.EventViewModel import com.google.android.material.tabs.TabLayoutMediator import java.util.* @@ -74,6 +75,16 @@ class EventFragment : AppFragment() { TabLayoutMediator(binding.dayTabLayout, binding.viewPager) { tab, position -> tab.text = weekdays[position] }.attach() + + binding.fabAddEvent.setOnClickListener { + openBottomSheet( + ScheduleUpdateSheet().also { sheet -> + val bundle = Bundle() + bundle.putBoolean("isEditing", false) + sheet.arguments = bundle + } + ) + } } /** 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 d2e9597..5d8da43 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/EventPageFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/EventPageFragment.kt @@ -91,6 +91,7 @@ class EventPageFragment : AppFragment(), StudIPEventItemAdapter.OnClickListener openBottomSheet( ScheduleUpdateSheet().also { sheet -> val bundle = Bundle() + bundle.putBoolean("isEditing", true) bundle.putParcelable("event", event) sheet.arguments = bundle } 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 bd7ade2..8803f3d 100644 --- a/app/src/main/java/com/denizk0461/studip/model/StudIPEvent.kt +++ b/app/src/main/java/com/denizk0461/studip/model/StudIPEvent.kt @@ -20,7 +20,7 @@ import androidx.room.PrimaryKey */ @Entity(tableName = "studip_events") data class StudIPEvent( - @PrimaryKey val eventId: Int, + @PrimaryKey(autoGenerate = true) val eventId: Int = 0, val title: String, val lecturer: String, val room: String, 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 d917e92..1501f3c 100644 --- a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt +++ b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt @@ -3,6 +3,7 @@ package com.denizk0461.studip.sheet import android.os.Bundle import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.PopupMenu import androidx.fragment.app.FragmentActivity import androidx.fragment.app.viewModels import androidx.transition.TransitionManager @@ -27,8 +28,8 @@ import com.denizk0461.studip.viewmodel.ScheduleUpdateViewModel class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePickerFragment.OnTimeSetListener { // Editable fields - private var timeslotStart = "" - private var timeslotEnd = "" + private var timeslotStart = "12:00" + private var timeslotEnd = "13:00" private var colour = -1 // View binding @@ -40,144 +41,245 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker // Whether the user has once clicked the delete button; used to prevent an accidental click private var hasClickedDelete: Boolean = false + // Determines whether the user is editing an existing event or creating a new one + private var isEditing: Boolean = false + + // Day the event is scheduled for, default is Monday + private var selectedDay = 0 + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - try { - // Retrieve event from arguments bundle - val event: StudIPEvent = arguments.getParcelableCompat("event") + if (arguments?.getBoolean("isEditing") == true) { - // Set values of the text field to that of the event - timeslotStart = event.timeslotStart - timeslotEnd = event.timeslotEnd - colour = event.colour + try { + /* + * Retrieve event from arguments bundle; determines whether this sheet is for editing or + * creating an event. + */ + val event: StudIPEvent = arguments.getParcelableCompat("event") - // Set editable text fields - binding.editTextTitle.setText(event.title) - binding.editTextLecturers.setText(event.lecturer) - binding.editTextRoom.setText(event.room) + // - Set-up for editing an existing event - // + // Set the title to reflect that an event is being edited + binding.sheetTitle.text = getString(R.string.sheet_schedule_update_header_edit) - /* - * Show academic quarter suggestion if it is applicable. For this to be the case, both the - * start timestamp and the end timestamp must match up in a pattern that would make it - * likely for the course to use the academic quarter. Example: - * 14:00 - 16:00 -> likely 14:15 - 15:45 - * - * 13:00 - 15:30 -> likely no academic quarter intended - */ - binding.buttonAcademicQuarter.setOnClickListener { - try { - // Retrieve new timestamps with the academic quarter applied, or throw a tantrum - val newStart = getTimestampAcademicQuarterStart(timeslotStart) - val newEnd = getTimestampAcademicQuarterEnd(timeslotEnd) + // User is editing an existing event + isEditing = true - // Set the buttons to the new timesatmps - timeslotStart = newStart - binding.buttonTimeStart.text = newStart - timeslotEnd = newEnd - binding.buttonTimeEnd.text = newEnd + // Set day + selectedDay = event.day + // Set values of the text field to that of the event + timeslotStart = event.timeslotStart + timeslotEnd = event.timeslotEnd + colour = event.colour + + // Set editable text fields + binding.editTextTitle.setText(event.title) + binding.editTextLecturers.setText(event.lecturer) + binding.editTextRoom.setText(event.room) + + // Prepare delete button + binding.buttonDelete.setOnClickListener { /* - * Attempt to fix the issue of the bottom sheet jumping up when hiding the - * button. + * Check if the user has already clicked the button before; this is done to prevent + * accidentally deleting an event. */ - TransitionManager.beginDelayedTransition(binding.sheet.parent as ViewGroup) - binding.buttonAcademicQuarter.visibility = View.GONE - - // Catch if a timeslot couldn't be found in the list, and tell the user - } catch (e: AcademicQuarterNotApplicableException) { - showToast( - context, - getString(R.string.sheet_schedule_update_hint_quarter_error) - ) + if (hasClickedDelete) { + viewModel.delete(event) + // Dismiss the sheet upon deletion + dismiss() + } else { + // Update the text to show the user that they clicked the button once + TransitionManager.beginDelayedTransition(binding.buttonContainer as ViewGroup) + binding.buttonDelete.text = + getString(R.string.sheet_schedule_update_delete_confirm) + hasClickedDelete = true + } } - } - binding.buttonAcademicQuarter.visibility = getVisibilityForAcademicQuarter( - timeslotsForAcademicQuarter.contains(timeslotStart), - timeslotsForAcademicQuarter.contains(timeslotEnd), - ) + // Prepare update/save button + binding.buttonSave.setOnClickListener { + // Check if any of the text fields are empty + checkIfTextFieldsEmpty { + // Update the event if all fields are filled + viewModel.update( + // construct new StudIPEvent from the data the user may have edited + StudIPEvent( + eventId = event.eventId, + title = binding.editTextTitle.text.toString().trim(), + lecturer = binding.editTextLecturers.text.toString().trim(), + room = binding.editTextRoom.text.toString().trim(), + day = selectedDay, + timeslotStart = timeslotStart, + timeslotEnd = timeslotEnd, + timeslotId = timeslotStart.parseToMinutes(), + colour = colour, + ) + ) + // Dismiss the sheet upon update + dismiss() + } + } - // Prepare timestamp buttons - binding.buttonTimeStart.text = timeslotStart - binding.buttonTimeStart.setOnClickListener { - // Launch a time picker dialogue to pick a new start timestamp - TimePickerFragment( - this, - true, - ).also { sheet -> - val bundle = Bundle() - bundle.putString("timestamp", binding.buttonTimeStart.text.toString()) - sheet.arguments = bundle - }.show((context as FragmentActivity).supportFragmentManager, "timePicker") - } - binding.buttonTimeEnd.text = timeslotEnd - binding.buttonTimeEnd.setOnClickListener { - // Launch a time picker dialogue to pick a new end timestamp - TimePickerFragment( - this, - false, - ).also { sheet -> - val bundle = Bundle() - bundle.putString("timestamp", binding.buttonTimeEnd.text.toString()) - sheet.arguments = bundle - }.show((context as FragmentActivity).supportFragmentManager, "timePicker") - } + } catch (e: ParcelNotFoundException) { + // Tell the user that something went wrong when retrieving Parcelable + showToast(context, getString(R.string.event_update_sheet_error)) - /* - * TODO implement option to change the colour for the course - single-selection coloured - * filter buttons with checkmarks when they're selected maybe? - */ - - // Prepare cancel button - binding.buttonCancel.setOnClickListener { - // Do nothing and dismiss the sheet + // Close the sheet dismiss() } - // Prepare delete button - binding.buttonDelete.setOnClickListener { - /* - * Check if the user has already clicked the button before; this is done to prevent - * accidentally deleting an event. - */ - if (hasClickedDelete) { - viewModel.delete(event) - // Dismiss the sheet upon deletion - dismiss() - } else { - // Update the text to show the user that they clicked the button once - TransitionManager.beginDelayedTransition(binding.buttonContainer as ViewGroup) - binding.buttonDelete.text = getString(R.string.sheet_schedule_update_delete_confirm) - hasClickedDelete = true - } - } + } else { + // - Set-up for creating a new event - // + + // Set the title to reflect that an event is being added + binding.sheetTitle.text = getString(R.string.sheet_schedule_update_header_add) + + // Hide delete button, since there is nothing to delete + binding.buttonDelete.visibility = View.GONE // Prepare update/save button binding.buttonSave.setOnClickListener { - viewModel.update( - // construct new StudIPEvent from the data the user may have edited - StudIPEvent( - eventId = event.eventId, - title = binding.editTextTitle.text.toString(), - lecturer = binding.editTextLecturers.text.toString(), - room = binding.editTextRoom.text.toString(), - day = event.day, - timeslotStart = timeslotStart, - timeslotEnd = timeslotEnd, - timeslotId = timeslotStart.parseToMinutes(), - colour = colour, + // Check if any of the text fields are empty + checkIfTextFieldsEmpty { + // Insert new event into the database + viewModel.insert( + // construct new StudIPEvent from the data the user may have edited + StudIPEvent( + title = binding.editTextTitle.text.toString().trim(), + lecturer = binding.editTextLecturers.text.toString().trim(), + room = binding.editTextRoom.text.toString().trim(), + day = selectedDay, + timeslotStart = timeslotStart, + timeslotEnd = timeslotEnd, + timeslotId = timeslotStart.parseToMinutes(), + colour = colour, + ) ) - ) - // Dismiss the sheet upon update - dismiss() + // Dismiss the sheet upon update + dismiss() + } } - } catch (e: ParcelNotFoundException) { - // Tell the user that something went wrong when retrieving Parcelable - showToast(context, getString(R.string.event_update_sheet_error)) + } - // Close the sheet + // - Set-up that is required for both editing and creating a new event - // + + /* + * TODO implement option to change the colour for the course - single-selection coloured + * filter buttons with checkmarks when they're selected maybe? + */ + + // Set visibility for academic quarter button based on whether the change applies + binding.buttonAcademicQuarter.visibility = getVisibilityForAcademicQuarter( + timeslotsForAcademicQuarter.contains(timeslotStart), + timeslotsForAcademicQuarter.contains(timeslotEnd), + ) + + // Retrieve new values for the day of the current event + binding.buttonDay.text = getString(when (selectedDay) { + 1 -> R.string.tuesday + 2 -> R.string.wednesday + 3 -> R.string.thursday + 4 -> R.string.friday + 5 -> R.string.saturday + 6 -> R.string.sunday + else -> R.string.monday // assume Monday + }) + + // Open the menu for the day picker button + binding.buttonDay.setOnClickListener { + PopupMenu(binding.root.context, binding.buttonDay).apply { + setOnMenuItemClickListener { item -> + // Retrieve new values for the day selected by the user + val (newDay, newDayId) = when (item?.itemId) { + R.id.tuesday -> Pair(1, R.string.tuesday) + R.id.wednesday -> Pair(2, R.string.wednesday) + R.id.thursday -> Pair(3, R.string.thursday) + R.id.friday -> Pair(4, R.string.friday) + R.id.saturday -> Pair(5, R.string.saturday) + R.id.sunday -> Pair(6, R.string.sunday) + else -> Pair(0, R.string.monday) // assume Monday + } + + selectedDay = newDay + + // Set newly selected day to the button + binding.buttonDay.text = getString(newDayId) + + true + } + inflate(R.menu.menu_days) + show() + } + } + + /* + * Show academic quarter suggestion if it is applicable. For this to be the case, both the + * start timestamp and the end timestamp must match up in a pattern that would make it + * likely for the course to use the academic quarter. Example: + * 14:00 - 16:00 -> likely 14:15 - 15:45 + * + * 13:00 - 15:30 -> likely no academic quarter intended + */ + binding.buttonAcademicQuarter.setOnClickListener { + try { + // Retrieve new timestamps with the academic quarter applied, or throw a tantrum + val newStart = getTimestampAcademicQuarterStart(timeslotStart) + val newEnd = getTimestampAcademicQuarterEnd(timeslotEnd) + + // Set the buttons to the new time stamps + timeslotStart = newStart + binding.buttonTimeStart.text = newStart + timeslotEnd = newEnd + binding.buttonTimeEnd.text = newEnd + + /* + * Attempt to fix the issue of the bottom sheet jumping up when hiding the + * button. + */ + TransitionManager.beginDelayedTransition(binding.sheet.parent as ViewGroup) + binding.buttonAcademicQuarter.visibility = View.GONE + + // Catch if a timeslot couldn't be found in the list, and tell the user + } catch (e: AcademicQuarterNotApplicableException) { + showToast( + context, + getString(R.string.sheet_schedule_update_hint_quarter_error) + ) + } + } + + // Prepare timestamp buttons + binding.buttonTimeStart.text = timeslotStart + binding.buttonTimeStart.setOnClickListener { + // Launch a time picker dialogue to pick a new start timestamp + TimePickerFragment( + this, + true, + ).also { sheet -> + val bundle = Bundle() + bundle.putString("timestamp", binding.buttonTimeStart.text.toString()) + sheet.arguments = bundle + }.show((context as FragmentActivity).supportFragmentManager, "timePicker") + } + binding.buttonTimeEnd.text = timeslotEnd + binding.buttonTimeEnd.setOnClickListener { + // Launch a time picker dialogue to pick a new end timestamp + TimePickerFragment( + this, + false, + ).also { sheet -> + val bundle = Bundle() + bundle.putString("timestamp", binding.buttonTimeEnd.text.toString()) + sheet.arguments = bundle + }.show((context as FragmentActivity).supportFragmentManager, "timePicker") + } + + // Prepare cancel button + binding.buttonCancel.setOnClickListener { + // Do nothing and dismiss the sheet dismiss() } } @@ -218,6 +320,53 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker } } + /** + * Checks whether the text fields in the sheet are blank (meaning, with whitespace trimmed from + * the start and the end of the string). Executes an action if the fields are all filled. + * + * @param actionIfFilled action to execute if all fields are filled + */ + private fun checkIfTextFieldsEmpty(actionIfFilled: () -> Unit) { + + // Assume at the start that no fields are empty; this may be changed during the checks + var hasEmptyFields = false + + // Check if the title field is blank + if (binding.editTextTitle.text.toString().isBlank()) { + // Set an error on the title field + binding.editTextTitle.error = + getString(R.string.sheet_schedule_update_text_field_empty_error) + + // Set that the action must not be executed + hasEmptyFields = true + } + + // Check if the lecturer field is blank + if (binding.editTextLecturers.text.toString().isBlank()) { + // Set an error on the lecturer field + binding.editTextLecturers.error = + getString(R.string.sheet_schedule_update_text_field_empty_error) + + // Set that the action must not be executed + hasEmptyFields = true + } + + // Check if the room field is blank + if (binding.editTextRoom.text.toString().isBlank()) { + // Set an error on the room field + binding.editTextRoom.error = + getString(R.string.sheet_schedule_update_text_field_empty_error) + + // Set that the action must not be executed + hasEmptyFields = true + } + + // If any fields are empty, don't execute the action + if (!hasEmptyFields) { + actionIfFilled() + } + } + /** * Determines which visibility the academic quarter button should have given the timestamps. * diff --git a/app/src/main/java/com/denizk0461/studip/viewmodel/ScheduleUpdateViewModel.kt b/app/src/main/java/com/denizk0461/studip/viewmodel/ScheduleUpdateViewModel.kt index 0c68a5f..e358ef6 100644 --- a/app/src/main/java/com/denizk0461/studip/viewmodel/ScheduleUpdateViewModel.kt +++ b/app/src/main/java/com/denizk0461/studip/viewmodel/ScheduleUpdateViewModel.kt @@ -5,6 +5,13 @@ import com.denizk0461.studip.model.StudIPEvent class ScheduleUpdateViewModel(application: Application) : AppViewModel(application) { + /** + * Inserts a new schedule element. + * + * @param event the event to save + */ + fun insert(event: StudIPEvent) { doAsync { repo.insert(event) } } + /** * Updates a schedule element. * diff --git a/app/src/main/res/drawable/edit_calendar.xml b/app/src/main/res/drawable/edit_calendar.xml new file mode 100644 index 0000000..16c2b91 --- /dev/null +++ b/app/src/main/res/drawable/edit_calendar.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/plus.xml b/app/src/main/res/drawable/plus.xml new file mode 100644 index 0000000..89633bb --- /dev/null +++ b/app/src/main/res/drawable/plus.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/fragment_canteen.xml b/app/src/main/res/layout/fragment_canteen.xml index c630388..a0cece9 100644 --- a/app/src/main/res/layout/fragment_canteen.xml +++ b/app/src/main/res/layout/fragment_canteen.xml @@ -17,19 +17,32 @@ android:orientation="vertical" app:layout_scrollFlags="scroll|exitUntilCollapsed"> - + + + android:layout_marginHorizontal="16dp"> - + android:text="@string/title_food" + android:textSize="32sp" + android:fontFamily="@font/lato_bolditalic" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/button_info"/> + android:layout_gravity="center_vertical|end" + app:iconTint="?attr/colorOnSurfaceVariant" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent"/> - - - + + + diff --git a/app/src/main/res/layout/fragment_event.xml b/app/src/main/res/layout/fragment_event.xml index 26a837a..199d5f4 100644 --- a/app/src/main/res/layout/fragment_event.xml +++ b/app/src/main/res/layout/fragment_event.xml @@ -14,14 +14,14 @@ + app:layout_scrollFlags="scroll|exitUntilCollapsed"/> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 6d1f5a1..afe1f08 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -15,8 +15,8 @@ @@ -125,6 +125,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 2afe04a..aa540bd 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -43,7 +43,8 @@ Sicher? Abbrechen Bestätigen - Veranstaltung bearbeiten + Veranstaltung bearbeiten + Veranstaltung hinzufügen Veranstaltungstitel Dozierende(r) Raum @@ -51,9 +52,11 @@ Sorry, ein Fehler ist aufgetreten! Der Kurs kann nicht anfangen nachdem er aufhört! Der Kurs kann nicht enden bevor er anfängt! + Dieses Feld darf nicht leer sein Kein Angebot Für diesen Tag sind keine Angebote vorhanden + Aktualisiere Angebote Lizenzen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d0a2325..bdea1e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -43,7 +43,8 @@ Sure? Cancel Confirm - Edit Event + Edit event + Add event Event title Lecturer(s) Room @@ -52,9 +53,11 @@ Sorry, an error occurred! The course can\'t begin after it ends! The course can\'t end before it begins! + This field cannot be empty No offers There are no offers available for this day + Refresh offers Licences Android developer resources provided by Google.\nhttps://developer.android.com/\n\nCrash reporting provided by Google.\nhttps://firebase.google.com/products/crashlytics/\n\nDesign guidelines, icons, and colour palette provided by Google.\nhttps://m3.material.io/\n\nAdditional icons provided by Flaticon.\nhttps://www.flaticon.com/\n\nWeb scraping functionality provided by Jonathan Hedley.\nhttps://jhy.io/ | https://jsoup.org/