├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── PULL_REQUEST_TEMPLATE.md │ ├── deploy_beta.yml │ ├── deploy_web.yml │ └── lint_test_build.yml ├── .gitignore ├── .metadata ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── analysis_options.yaml ├── android ├── .gitignore ├── Gemfile ├── app │ ├── build.gradle │ ├── google-services.json │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── de │ │ │ │ └── tum │ │ │ │ └── in │ │ │ │ └── tumcampus │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── util │ │ │ │ ├── ColorExtension.kt │ │ │ │ ├── Const.kt │ │ │ │ ├── DateTimeSerializer.kt │ │ │ │ └── DateTimeUtils.kt │ │ │ │ └── widgets │ │ │ │ └── calendar │ │ │ │ ├── CalendarWidgetProvider.kt │ │ │ │ ├── CalendarWidgetService.kt │ │ │ │ └── WidgetCalendarItem.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ ├── appwidget_preview.png │ │ │ ├── launch_background.xml │ │ │ └── rounded_background.xml │ │ │ ├── layout │ │ │ ├── calendar_widget.xml │ │ │ └── calendar_widget_item.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ └── ic_launcher.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ ├── ic_launcher_monochrome.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ ├── ic_launcher_monochrome.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ ├── ic_launcher_monochrome.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ ├── ic_launcher_monochrome.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ ├── ic_launcher_monochrome.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values-de │ │ │ └── strings.xml │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ ├── values-v31 │ │ │ └── themes.xml │ │ │ ├── values │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ ├── styles.xml │ │ │ └── themes.xml │ │ │ ├── xml-v31 │ │ │ └── calendar_widget_info.xml │ │ │ └── xml │ │ │ └── calendar_widget_info.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── build │ └── .last_build_id ├── fastlane │ ├── Appfile │ └── Fastfile ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── images │ ├── campus │ │ ├── campus-freising.jpg │ │ ├── campus-garching.jpeg │ │ ├── campus-klinikum.jpg │ │ ├── campus-olympia.jpg │ │ └── campus-stamm.jpeg │ ├── errors │ │ └── error.svg │ ├── location.png │ ├── logos │ │ ├── tum-logo-blue-text.png │ │ ├── tum-logo-blue.png │ │ ├── tum-logo-rainbow.png │ │ └── tum-logo-white.png │ ├── placeholders │ │ ├── movie_placeholder.png │ │ ├── news_placeholder.png │ │ ├── portrait_placeholder.png │ │ └── student_club_placeholder.png │ └── tower.png ├── lottieFiles │ ├── gradient_background_blue_red.json │ ├── gradient_background_blue_white.json │ ├── gradient_background_blue_white_speedup.json │ └── gradient_background_silver_white.json ├── mapStyles │ ├── darkMapTheme.json │ └── lightMapTheme.json ├── translations │ ├── de.json │ └── en.json └── videos │ └── token-tutorial.mp4 ├── devtools_options.yaml ├── ios ├── .gitignore ├── CalendarWidget │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x-1.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x-1.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x-1.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ ├── ItunesArtwork@2x.png │ │ │ ├── slice1@3x copy 2.png │ │ │ ├── slice1@3x copy 3-1.png │ │ │ ├── slice1@3x copy 3.png │ │ │ ├── slice1@3x copy 4.png │ │ │ ├── slice1@3x copy 5.png │ │ │ ├── slice1@3x copy 6-1.png │ │ │ ├── slice1@3x copy 6.png │ │ │ ├── slice1@3x copy 7-1.png │ │ │ ├── slice1@3x copy 7.png │ │ │ └── slice1@3x copy 8.png │ │ ├── Contents.json │ │ └── WidgetBackground.colorset │ │ │ └── Contents.json │ ├── CalendarEntry.swift │ ├── CalendarEventType.swift │ ├── CalendarEventView.swift │ ├── CalendarWidget.swift │ ├── CalendarWidgetBundle.swift │ ├── CalendarWidgetContent.swift │ ├── CalendarWidgetEntry.swift │ ├── ColorExtension.swift │ ├── DateExtension.swift │ └── Info.plist ├── CalendarWidgetExtension.entitlements ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Gemfile ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x-1.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x-1.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x-1.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ ├── ItunesArtwork@2x.png │ │ │ ├── slice1@3x copy 2.png │ │ │ ├── slice1@3x copy 3-1.png │ │ │ ├── slice1@3x copy 3.png │ │ │ ├── slice1@3x copy 4.png │ │ │ ├── slice1@3x copy 5.png │ │ │ ├── slice1@3x copy 6-1.png │ │ │ ├── slice1@3x copy 6.png │ │ │ ├── slice1@3x copy 7-1.png │ │ │ ├── slice1@3x copy 7.png │ │ │ └── slice1@3x copy 8.png │ │ ├── Contents.json │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── README.md │ │ │ └── logo-white.png │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── GoogleService-Info.plist │ ├── Info.plist │ ├── Localizable.xcstrings │ ├── Runner-Bridging-Header.h │ └── Runner.entitlements ├── build │ └── .last_build_id ├── ci_scripts │ └── ci_post_clone.sh ├── fastlane │ ├── Appfile │ ├── Fastfile │ └── Matchfile └── firebase_app_id_file.json ├── lib ├── base │ ├── enums │ │ ├── appearance.dart │ │ ├── campus.dart │ │ ├── credentials.dart │ │ ├── device.dart │ │ ├── error_handling_view_type.dart │ │ ├── gender.dart │ │ ├── home_widget.dart │ │ ├── remote_config_message.dart │ │ ├── role.dart │ │ ├── search_category.dart │ │ ├── search_type.dart │ │ ├── shortcut_item.dart │ │ ├── user_preference.dart │ │ └── widget_type.dart │ ├── errorHandling │ │ ├── default_error_router.dart │ │ ├── dio_exception_router.dart │ │ ├── error_handling_router.dart │ │ ├── error_handling_view.dart │ │ ├── grpc_error_router.dart │ │ ├── search_exception_router.dart │ │ ├── tum_online_api_exception_router.dart │ │ └── type_error_router.dart │ ├── extensions │ │ ├── base_64_decode_image_data.dart │ │ ├── cast.dart │ │ ├── color.dart │ │ ├── context.dart │ │ ├── date_time.dart │ │ ├── latlng_to_json.dart │ │ ├── locale_fullname.dart │ │ ├── string_capitalize.dart │ │ ├── string_levenshtein.dart │ │ ├── string_remove_diacritics.dart │ │ └── string_valid_chars.dart │ ├── networking │ │ ├── apis │ │ │ ├── eatApi │ │ │ │ ├── eat_api.dart │ │ │ │ └── eat_api_endpoint.dart │ │ │ ├── google │ │ │ │ └── protobuf │ │ │ │ │ ├── empty.pb.dart │ │ │ │ │ ├── empty.pbenum.dart │ │ │ │ │ ├── empty.pbjson.dart │ │ │ │ │ ├── timestamp.pb.dart │ │ │ │ │ ├── timestamp.pbenum.dart │ │ │ │ │ └── timestamp.pbjson.dart │ │ │ ├── irisApi │ │ │ │ ├── iris_api.dart │ │ │ │ └── iris_api_endpoint.dart │ │ │ ├── mvvDeparturesApi │ │ │ │ └── mvv_departures_api.dart │ │ │ ├── navigaTumApi │ │ │ │ ├── navigatum_api.dart │ │ │ │ └── navigatum_api_endpoint.dart │ │ │ ├── tumOnlineApi │ │ │ │ ├── tum_online_api.dart │ │ │ │ ├── tum_online_api_endpoint.dart │ │ │ │ └── tum_online_api_exception.dart │ │ │ └── tumdev │ │ │ │ ├── campus_backend.pb.dart │ │ │ │ ├── campus_backend.pbenum.dart │ │ │ │ ├── campus_backend.pbgrpc.dart │ │ │ │ └── campus_backend.pbjson.dart │ │ ├── base │ │ │ ├── api_response.dart │ │ │ ├── grpc_client.dart │ │ │ └── rest_client.dart │ │ ├── cache │ │ │ ├── cache.dart │ │ │ ├── cache_entry.dart │ │ │ ├── cache_entry.g.dart │ │ │ ├── grpc_cache_interceptor.dart │ │ │ └── rest_cache_interceptor.dart │ │ └── protocols │ │ │ ├── api.dart │ │ │ ├── api_exception.dart │ │ │ └── api_exception.g.dart │ ├── routing │ │ ├── router.dart │ │ ├── router_service.dart │ │ └── routes.dart │ ├── services │ │ ├── connection_service.dart │ │ ├── device_type_service.dart │ │ ├── location_service.dart │ │ └── user_preferences_service.dart │ ├── theme │ │ ├── constants.dart │ │ ├── dark_theme.dart │ │ └── light_theme.dart │ └── util │ │ ├── card_with_padding.dart │ │ ├── color_picker_view.dart │ │ ├── custom_back_button.dart │ │ ├── days_parser.dart │ │ ├── delayed_loading_indicator.dart │ │ ├── diagonalStripePattern │ │ ├── diagonal_stripe_pattern_view.dart │ │ └── stripe_pattern_painter.dart │ │ ├── enum_parser.dart │ │ ├── fast_hash.dart │ │ ├── fullscreen_image_view.dart │ │ ├── grid_utility.dart │ │ ├── horizontal_slider.dart │ │ ├── hyperlink_text.dart │ │ ├── icon_text.dart │ │ ├── info_row.dart │ │ ├── last_updated_text.dart │ │ ├── map_launcher.dart │ │ ├── padded_divider.dart │ │ ├── placeholder_text.dart │ │ ├── places_util.dart │ │ ├── read_list_value.dart │ │ ├── semester_calculator.dart │ │ ├── seperated_list.dart │ │ ├── shimmer_view.dart │ │ ├── speaker.dart │ │ ├── string_parser.dart │ │ └── url_launcher.dart ├── calendarComponent │ ├── model │ │ ├── calendar_data_source.dart │ │ ├── calendar_editing.dart │ │ ├── calendar_editing.g.dart │ │ ├── calendar_event.dart │ │ ├── calendar_event.g.dart │ │ ├── calendar_preferences.dart │ │ └── calendar_preferences.g.dart │ ├── services │ │ ├── calendar_preference_service.dart │ │ ├── calendar_service.dart │ │ └── calendar_view_service.dart │ ├── viewModels │ │ ├── calendar_addition_viewmodel.dart │ │ └── calendar_viewmodel.dart │ └── views │ │ ├── calendar_day_view.dart │ │ ├── calendar_event_view.dart │ │ ├── calendar_month_view.dart │ │ ├── calendar_week_view.dart │ │ ├── calendars_view.dart │ │ ├── custom_event_view.dart │ │ ├── event_creation_date_time_picker.dart │ │ ├── event_creation_form_field.dart │ │ ├── event_creation_view.dart │ │ ├── homeWidget │ │ ├── calendar_widget_event_view.dart │ │ └── calendar_widget_view.dart │ │ └── visibility_button_view.dart ├── campusComponent │ ├── model │ │ ├── student_club.dart │ │ └── student_club_collection.dart │ ├── screen │ │ ├── campus_screen.dart │ │ ├── movie_screen.dart │ │ ├── news_screen.dart │ │ └── student_clubs_screen.dart │ ├── service │ │ ├── movie_service.dart │ │ ├── news_service.dart │ │ └── student_club_service.dart │ ├── view │ │ ├── movie │ │ │ ├── movie_card_view.dart │ │ │ ├── movie_grid_view.dart │ │ │ └── movies_widget_view.dart │ │ ├── news │ │ │ ├── news_card_view.dart │ │ │ └── news_widget_view.dart │ │ └── studentClub │ │ │ ├── student_club_card_view.dart │ │ │ ├── student_club_grid_view.dart │ │ │ └── student_club_widget_view.dart │ └── viewmodel │ │ ├── movies_viewmodel.dart │ │ ├── news_viewmodel.dart │ │ └── student_club_viewmodel.dart ├── feedbackComponent │ ├── services │ │ └── feedback_service.dart │ ├── viewModels │ │ └── feedback_viewmodel.dart │ └── views │ │ ├── feedback_checkmark_view.dart │ │ ├── feedback_form_view.dart │ │ ├── feedback_success_view.dart │ │ └── feedback_textfield.dart ├── firebase_options.dart ├── homeComponent │ ├── model │ │ ├── departure.dart │ │ ├── departure.g.dart │ │ ├── departures_preference.dart │ │ ├── departures_preference.g.dart │ │ ├── mvv_response.dart │ │ ├── mvv_response.g.dart │ │ ├── station.dart │ │ └── station.g.dart │ ├── screen │ │ └── home_screen.dart │ ├── service │ │ └── departures_service.dart │ ├── view │ │ ├── contactCard │ │ │ ├── contact_card_error_view.dart │ │ │ ├── contact_card_loading_view.dart │ │ │ ├── contact_card_unauthorized_view.dart │ │ │ ├── contact_card_view.dart │ │ │ ├── contact_view.dart │ │ │ ├── link_view.dart │ │ │ └── tuition_view.dart │ │ ├── departure │ │ │ ├── departures_details_row_view.dart │ │ │ ├── departures_details_view.dart │ │ │ └── departures_widget_view.dart │ │ └── widget │ │ │ ├── home_settings_view.dart │ │ │ ├── preference_selection_view.dart │ │ │ ├── widget_frame_view.dart │ │ │ └── widget_screen.dart │ └── viewmodel │ │ ├── departures_viewmodel.dart │ │ └── home_viewmodel.dart ├── main.dart ├── navigaTumComponent │ ├── model │ │ ├── details │ │ │ ├── navigatum_navigation_additional_properties.dart │ │ │ ├── navigatum_navigation_additional_properties.g.dart │ │ │ ├── navigatum_navigation_coordinates.dart │ │ │ ├── navigatum_navigation_coordinates.g.dart │ │ │ ├── navigatum_navigation_maps.dart │ │ │ ├── navigatum_navigation_maps.g.dart │ │ │ ├── navigatum_overlays_maps.dart │ │ │ ├── navigatum_overlays_maps.g.dart │ │ │ ├── navigatum_roomfinder_maps.dart │ │ │ └── navigatum_roomfinder_maps.g.dart │ │ ├── navigatum_navigation_details.dart │ │ ├── navigatum_navigation_details.g.dart │ │ ├── navigatum_navigation_entity.dart │ │ ├── navigatum_navigation_entity.g.dart │ │ ├── navigatum_navigation_property.dart │ │ ├── navigatum_navigation_property.g.dart │ │ ├── navigatum_overlay_map.dart │ │ ├── navigatum_overlay_map.g.dart │ │ ├── navigatum_roomfinder_map.dart │ │ ├── navigatum_roomfinder_map.g.dart │ │ └── search │ │ │ ├── navigatum_search_response.dart │ │ │ ├── navigatum_search_response.g.dart │ │ │ ├── navigatum_search_response_section.dart │ │ │ └── navigatum_search_response_section.g.dart │ ├── services │ │ ├── navigatum_search_service.dart │ │ └── navigatum_service.dart │ ├── viewModels │ │ ├── navigatum_campus_viewmodel.dart │ │ └── navigatum_details_viewmodel.dart │ └── views │ │ ├── navigatum_room_building_view.dart │ │ ├── navigatum_room_details_view.dart │ │ ├── navigatum_room_maps_view.dart │ │ └── navigatum_room_view.dart ├── navigation.dart ├── navigation_service.dart ├── onboardingComponent │ ├── model │ │ ├── confirm.dart │ │ ├── confirm.g.dart │ │ ├── token.dart │ │ └── token.g.dart │ ├── services │ │ └── onboarding_service.dart │ ├── viewModels │ │ └── onboarding_viewmodel.dart │ └── views │ │ ├── confirm_view.dart │ │ ├── location_permissions_view.dart │ │ ├── login_view.dart │ │ ├── permission_check_view.dart │ │ └── permission_view.dart ├── personComponent │ ├── model │ │ ├── personDetails │ │ │ ├── contact_info.dart │ │ │ ├── contact_info.g.dart │ │ │ ├── organisation.dart │ │ │ ├── organisation.g.dart │ │ │ ├── person_details.dart │ │ │ ├── person_details.g.dart │ │ │ ├── phone_extension.dart │ │ │ ├── phone_extension.g.dart │ │ │ ├── room.dart │ │ │ └── room.g.dart │ │ ├── personSearch │ │ │ ├── person.dart │ │ │ └── person.g.dart │ │ └── profile │ │ │ ├── profile.dart │ │ │ ├── profile.g.dart │ │ │ ├── tuition.dart │ │ │ └── tuition.g.dart │ ├── services │ │ ├── person_details_service.dart │ │ ├── person_search_service.dart │ │ └── profile_service.dart │ ├── viewModel │ │ ├── person_details_viewmodel.dart │ │ └── profile_viewmodel.dart │ └── views │ │ └── person_details_view.dart ├── placesComponent │ ├── model │ │ ├── cafeterias │ │ │ ├── cafeteria.dart │ │ │ ├── cafeteria.g.dart │ │ │ ├── cafeteria_menu.dart │ │ │ ├── dish.dart │ │ │ ├── dish.g.dart │ │ │ ├── meal_plan.dart │ │ │ ├── meal_plan.g.dart │ │ │ ├── mensa_menu.dart │ │ │ ├── mensa_menu.g.dart │ │ │ ├── opening_hours.dart │ │ │ └── opening_hours.g.dart │ │ └── studyRooms │ │ │ ├── study_room.dart │ │ │ ├── study_room.g.dart │ │ │ ├── study_room_attribute.dart │ │ │ ├── study_room_attribute.g.dart │ │ │ ├── study_room_data.dart │ │ │ ├── study_room_data.g.dart │ │ │ ├── study_room_group.dart │ │ │ ├── study_room_group.g.dart │ │ │ ├── study_room_opening_hours.dart │ │ │ └── study_room_opening_hours.g.dart │ ├── services │ │ ├── cafeterias_service.dart │ │ ├── map_theme_service.dart │ │ ├── mealplan_service.dart │ │ └── study_rooms_service.dart │ ├── viewModels │ │ ├── cafeterias_viewmodel.dart │ │ ├── places_viewmodel.dart │ │ └── study_rooms_viewmodel.dart │ └── views │ │ ├── cafeterias │ │ ├── cafeteria_row_view.dart │ │ ├── cafeteria_view.dart │ │ ├── cafeterias_view.dart │ │ ├── dish_card_view.dart │ │ ├── dish_grid_view.dart │ │ └── dish_slider_view.dart │ │ ├── campuses │ │ ├── campus_card_view.dart │ │ ├── campus_map_legend.dart │ │ ├── campus_map_view.dart │ │ ├── campus_most_searched_view.dart │ │ ├── campus_scaffold.dart │ │ └── campus_view.dart │ │ ├── homeWidget │ │ ├── cafeteria_widget_view.dart │ │ └── study_room_widget_view.dart │ │ ├── map_widget.dart │ │ ├── places_screen.dart │ │ ├── places_view.dart │ │ └── studyGroups │ │ ├── study_room_group_scaffold.dart │ │ ├── study_room_group_view.dart │ │ ├── study_room_row_view.dart │ │ └── study_rooms_view.dart ├── searchComponent │ ├── model │ │ ├── comparison_token.dart │ │ └── search_exception.dart │ ├── protocols │ │ ├── global_search.dart │ │ ├── search_category_viewmodel.dart │ │ └── searchable.dart │ ├── viewModels │ │ ├── search_viewmodel.dart │ │ └── searchableViewModels │ │ │ ├── cafeteria_search_viewmodel.dart │ │ │ ├── calendar_search_viewmodel.dart │ │ │ ├── grades_search_viewmodel.dart │ │ │ ├── lecture_search_viewmodel.dart │ │ │ ├── movie_search_viewmodel.dart │ │ │ ├── navigatum_search_viewmodel.dart │ │ │ ├── news_search_viewmodel.dart │ │ │ ├── person_search_viewmodel.dart │ │ │ ├── personal_lecture_seach_viewmodel.dart │ │ │ ├── student_club_search_viewmodel.dart │ │ │ └── study_room_search_viewmodel.dart │ └── views │ │ ├── resultViews │ │ ├── cafeteria_search_result_view.dart │ │ ├── calendar_search_result_view.dart │ │ ├── grade_search_result_view.dart │ │ ├── lecture_search_result_view.dart │ │ ├── movie_search_result_view.dart │ │ ├── navigatum_search_result_view.dart │ │ ├── news_search_result_view.dart │ │ ├── person_search_result_view.dart │ │ ├── personal_lecture_search_result_view.dart │ │ ├── student_club_search_result_view.dart │ │ └── study_room_search_result_view.dart │ │ ├── search_category_picker_view.dart │ │ ├── search_result_card_view.dart │ │ ├── search_result_details_view.dart │ │ ├── search_result_view_builder.dart │ │ ├── search_scaffold.dart │ │ ├── search_textfield_view.dart │ │ └── search_view.dart ├── settingsComponent │ ├── viewModels │ │ └── settings_viewmodel.dart │ └── views │ │ ├── appearance_settings_view.dart │ │ ├── calendar_settings_view.dart │ │ ├── contact_view.dart │ │ ├── general_settings_view.dart │ │ ├── settings_scaffold.dart │ │ └── settings_view.dart ├── studentCardComponent │ ├── model │ │ ├── student_card.dart │ │ └── student_card.g.dart │ ├── services │ │ └── student_card_service.dart │ ├── viewModel │ │ └── student_card_viewmodel.dart │ └── views │ │ ├── bar_code_view.dart │ │ ├── information_view.dart │ │ ├── snapping_slider.dart │ │ ├── student_card_view.dart │ │ └── verfication_code_view.dart └── studiesComponent │ ├── model │ ├── average_grade.dart │ ├── average_grade.g.dart │ ├── grade.dart │ ├── grade.g.dart │ ├── lecture.dart │ ├── lecture.g.dart │ ├── lecture_details.dart │ └── lecture_details.g.dart │ ├── screen │ └── studies_screen.dart │ ├── service │ ├── grade_service.dart │ ├── lecture_details_service.dart │ ├── lecture_search_service.dart │ └── lecture_service.dart │ ├── view │ ├── grade │ │ ├── chart_view.dart │ │ ├── grade_rectangle.dart │ │ ├── grade_view.dart │ │ └── grades_view.dart │ ├── lecture │ │ ├── lecture_view.dart │ │ └── lectures_view.dart │ ├── lectureDetail │ │ ├── basic_lecture_info_row_view.dart │ │ ├── basic_lecture_info_view.dart │ │ ├── detailed_lecture_info_row_view.dart │ │ ├── detailed_lecture_info_view.dart │ │ ├── lecture_details_view.dart │ │ ├── lecture_info_card_view.dart │ │ ├── lecture_links_view.dart │ │ └── lecture_meeting_info_view.dart │ └── semester_view.dart │ └── viewModel │ ├── grade_viewmodel.dart │ ├── lecture_details_viewmodel.dart │ └── lecture_viewmodel.dart ├── protos ├── google │ └── api │ │ ├── annotations.proto │ │ └── http.proto └── tumdev │ └── campus_backend.proto ├── pubspec.lock ├── pubspec.yaml └── test └── api_test.dart /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | We are glad that you are contributing to the TUM Campus App and are helping to enhance the user experience. Please make sure all your contributions adhere to the following guidelines: 4 | 5 | * Are able to be published under LICENCE_IS_TOO_BE_DISCUSSED. Don't use licensed material 6 | * Are your own creations or attributed correctly if not 7 | * The code is in a usable state and there are no Null Pointer Exceptions or similar acts of sabotage 8 | * Your code is *not* magic :sparkles: 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: TUM-Dev 4 | open_collective: tum-dev -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] " 5 | labels: 'Bug :bug:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Smartphone (please complete the following information):** 27 | * Phone: 28 | * OS version: 29 | * Language: 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature]" 5 | labels: 'Feature :tada:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Issue 2 | 3 | This fixes the following issue(s): 4 | - Resolves: #XXXX 5 | 6 | ## Screenshot 7 | 8 | ## Why this is useful for all students 9 | 10 | -------------------------------------------------------------------------------- /.github/workflows/lint_test_build.yml: -------------------------------------------------------------------------------- 1 | name: Linting, Testing and Building 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - "dev" 7 | - "main" 8 | 9 | jobs: 10 | build: 11 | runs-on: macos-13 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Install latest CocoaPods Version 17 | run: sudo gem install cocoapods 18 | 19 | - name: Setup Flutter 20 | uses: subosito/flutter-action@v2 21 | with: 22 | channel: stable 23 | 24 | - name: Install Flutter Packages 25 | run: flutter pub get 26 | 27 | - name: Analyze Project 28 | run: dart analyze --fatal-warnings 29 | 30 | - name: Run Tests 31 | run: flutter test 32 | 33 | - name: Install CocoaPods 34 | run: cd ./ios && pod install 35 | 36 | - name: Install Java SDK 37 | uses: actions/setup-java@v3 38 | with: 39 | distribution: 'corretto' 40 | java-version: '17' 41 | 42 | - name: Build iOS 43 | run: flutter build ipa --no-codesign 44 | 45 | - name: Build Android 46 | run: flutter build apk 47 | 48 | #- name: Build Website 49 | # run: flutter build web --base-href / 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | .vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | 48 | # fastlane related 49 | ios/Runner.app.dSYM.zip 50 | ios/Runner.ipa 51 | ios/fastlane/report.xml 52 | ios/fastlane/README.md 53 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please report any and all security vulnerabilitys you found, or you think you found at app (at-symbol) tum.de . 6 | We will diagnose the issue internally and propose a fix. 7 | The timeline of a fix depends on how severe the problem is and what impacts it has. 8 | As a reward for reporting such vulnerabilitys you can get exclusive stickers or other small things. 9 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | linter: 4 | rules: 5 | require_trailing_commas: true 6 | always_use_package_imports: true 7 | 8 | analyzer: 9 | errors: 10 | invalid_annotation_target: ignore 11 | exclude: 12 | - '**/*.g.dart' 13 | - lib/base/networking/apis/tumdev/campus_backend.pb.dart 14 | - lib/base/networking/apis/tumdev/campus_backend.pbenum.dart 15 | - lib/base/networking/apis/tumdev/campus_backend.pbgrpc.dart 16 | - lib/base/networking/apis/tumdev/campus_backend.pbjson.dart 17 | - lib/base/networking/apis/google/protobuf/empty.pbjson.dart 18 | - lib/base/networking/apis/google/protobuf/timestamp.pb.dart -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | **/.cxx 9 | 10 | # Remember to never publicly share your keystore. 11 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 12 | key.properties 13 | **/*.keystore 14 | **/*.jks 15 | 16 | Gemfile.lock 17 | -------------------------------------------------------------------------------- /android/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/de/tum/in/tumcampus/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package de.tum.`in`.tumcampus 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.content.pm.ActivityInfo 6 | import android.os.Bundle 7 | import io.flutter.embedding.android.FlutterActivity 8 | 9 | 10 | class MainActivity : FlutterActivity() { 11 | @SuppressLint("SourceLockedOrientationActivity") 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | if (isPhone(this)) { 14 | requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT 15 | } 16 | 17 | super.onCreate(savedInstanceState) 18 | } 19 | } 20 | 21 | fun isPhone(context: Context): Boolean { 22 | val resources = context.resources 23 | val configuration = resources.configuration 24 | val screenWidthDp = configuration.screenWidthDp 25 | return screenWidthDp <= resources.getDimension(R.dimen.min_tablet_width_dp) 26 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/de/tum/in/tumcampus/util/ColorExtension.kt: -------------------------------------------------------------------------------- 1 | package de.tum.`in`.tumcampus.util 2 | 3 | import android.graphics.Color 4 | 5 | fun argbToColor(argb: Long): Int { 6 | val alpha = ((argb shr 24) and 0xFF) / 255f 7 | val red = ((argb shr 16) and 0xFF) / 255f 8 | val green = ((argb shr 8) and 0xFF) / 255f 9 | val blue = (argb and 0xFF) / 255f 10 | return Color.argb(alpha, red, green, blue) 11 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/de/tum/in/tumcampus/util/Const.kt: -------------------------------------------------------------------------------- 1 | package de.tum.`in`.tumcampus.util 2 | 3 | /** 4 | * Contains different constants used by several classes. Allows a unified access. 5 | */ 6 | object Const { 7 | const val EVENT_TIME = "event_time" 8 | } 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/appwidget_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/drawable/appwidget_preview.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/rounded_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/themes.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #FFE1F5FE 3 | #FF81D4FA 4 | #FF039BE5 5 | #FF01579B 6 | 7 | @color/tum_500 8 | @color/tum_700 9 | 10 | #0065BD 11 | #004C8E 12 | 13 | #030303 14 | #a5a5a5 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10dp 4 | 8dp 5 | 4dp 6 | 2dp 7 | 600dp 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 12 | 13 | 17 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml-v31/calendar_widget_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/calendar_widget_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/build/.last_build_id: -------------------------------------------------------------------------------- 1 | 5ac2f0046179d5c246a76aed8c877cba -------------------------------------------------------------------------------- /android/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | package_name("de.tum.in.tumcampus") -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.nonTransitiveRClass=false 5 | android.nonFinalResIds=false 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip 6 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version '8.9.0' apply false 22 | id "org.jetbrains.kotlin.android" version "1.9.20" apply false 23 | id "org.jetbrains.kotlin.plugin.serialization" version "2.0.21" apply false 24 | id "com.google.gms.google-services" version "4.4.2" apply false 25 | id "com.google.firebase.crashlytics" version "3.0.3" apply false 26 | } 27 | 28 | include ":app" 29 | -------------------------------------------------------------------------------- /assets/images/campus/campus-freising.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/campus/campus-freising.jpg -------------------------------------------------------------------------------- /assets/images/campus/campus-garching.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/campus/campus-garching.jpeg -------------------------------------------------------------------------------- /assets/images/campus/campus-klinikum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/campus/campus-klinikum.jpg -------------------------------------------------------------------------------- /assets/images/campus/campus-olympia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/campus/campus-olympia.jpg -------------------------------------------------------------------------------- /assets/images/campus/campus-stamm.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/campus/campus-stamm.jpeg -------------------------------------------------------------------------------- /assets/images/location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/location.png -------------------------------------------------------------------------------- /assets/images/logos/tum-logo-blue-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/logos/tum-logo-blue-text.png -------------------------------------------------------------------------------- /assets/images/logos/tum-logo-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/logos/tum-logo-blue.png -------------------------------------------------------------------------------- /assets/images/logos/tum-logo-rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/logos/tum-logo-rainbow.png -------------------------------------------------------------------------------- /assets/images/logos/tum-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/logos/tum-logo-white.png -------------------------------------------------------------------------------- /assets/images/placeholders/movie_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/placeholders/movie_placeholder.png -------------------------------------------------------------------------------- /assets/images/placeholders/news_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/placeholders/news_placeholder.png -------------------------------------------------------------------------------- /assets/images/placeholders/portrait_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/placeholders/portrait_placeholder.png -------------------------------------------------------------------------------- /assets/images/placeholders/student_club_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/placeholders/student_club_placeholder.png -------------------------------------------------------------------------------- /assets/images/tower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/images/tower.png -------------------------------------------------------------------------------- /assets/mapStyles/lightMapTheme.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "featureType": "poi.business", 4 | "stylers": [ 5 | { 6 | "visibility": "off" 7 | } 8 | ] 9 | }, 10 | { 11 | "featureType": "poi.park", 12 | "elementType": "labels.text", 13 | "stylers": [ 14 | { 15 | "visibility": "off" 16 | } 17 | ] 18 | } 19 | ] -------------------------------------------------------------------------------- /assets/videos/token-tutorial.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/assets/videos/token-tutorial.mp4 -------------------------------------------------------------------------------- /devtools_options.yaml: -------------------------------------------------------------------------------- 1 | description: This file stores settings for Dart & Flutter DevTools. 2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states 3 | extensions: 4 | - drift: true -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | 36 | Gemfile.lock 37 | -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xBC", 9 | "green" : "0x64", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xB3", 27 | "green" : "0x70", 28 | "red" : "0x30" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 2.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3-1.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 4.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 5.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6-1.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7-1.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/CalendarWidget/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 8.png -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/CalendarWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "1.000", 10 | "red" : "1.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.000", 27 | "green" : "0.000", 28 | "red" : "0.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ios/CalendarWidget/CalendarEntry.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CalendarEntry.swift 3 | // Runner 4 | // 5 | // Created by Jakob Körber on 31.01.24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | struct CalendarEntry: Codable, Identifiable { 12 | let id: String 13 | let title: String 14 | let status: String 15 | let startDate: Date 16 | let endDate: Date 17 | let location: [String] 18 | let color: Int? 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case id = "nr" 22 | case startDate = "dtstart" 23 | case endDate = "dtend" 24 | case title, location, status, color 25 | } 26 | 27 | var eventColor: Color { 28 | return color == nil ? .accent : Color(argb: UInt32(color!)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ios/CalendarWidget/CalendarEventType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CalendarEventType.swift 3 | // CalendarWidgetExtension 4 | // 5 | // Created by Jakob Körber on 02.02.24. 6 | // 7 | 8 | import Foundation 9 | 10 | enum CalendarEventType { 11 | case canceled 12 | case lecture 13 | case exercise 14 | case other 15 | } 16 | -------------------------------------------------------------------------------- /ios/CalendarWidget/CalendarWidgetBundle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CalendarWidgetBundle.swift 3 | // CalendarWidget 4 | // 5 | // Created by Jakob Körber on 31.01.24. 6 | // 7 | 8 | import WidgetKit 9 | import SwiftUI 10 | 11 | @main 12 | struct CalendarWidgetBundle: WidgetBundle { 13 | var body: some Widget { 14 | CalendarWidget() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ios/CalendarWidget/CalendarWidgetEntry.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CalendarWidgetEntry.swift 3 | // CalendarWidgetExtension 4 | // 5 | // Created by Jakob Körber on 01.02.24. 6 | // 7 | 8 | import WidgetKit 9 | import SwiftUI 10 | 11 | struct CalendarWidgetEntry: TimelineEntry { 12 | let date: Date 13 | let entries: [CalendarEntry] 14 | let size: WidgetFamily 15 | } 16 | -------------------------------------------------------------------------------- /ios/CalendarWidget/ColorExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorExtension.swift 3 | // CalendarWidgetExtension 4 | // 5 | // Created by Jakob Körber on 03.04.24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | extension Color { 12 | init(argb: UInt32) { 13 | let alpha = Double((argb >> 24) & 0xFF) / 255.0 14 | let red = Double((argb >> 16) & 0xFF) / 255.0 15 | let green = Double((argb >> 8) & 0xFF) / 255.0 16 | let blue = Double(argb & 0xFF) / 255.0 17 | self.init(red: red, green: green, blue: blue, opacity: alpha) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ios/CalendarWidget/DateExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateExtension.swift 3 | // CalendarWidgetExtension 4 | // 5 | // Created by Jakob Körber on 04.03.24. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Date { 11 | var isToday: Bool { 12 | let calendar = Calendar.autoupdatingCurrent 13 | return calendar.isDateInToday(self) 14 | } 15 | 16 | var isTomorrow: Bool { 17 | let calendar = Calendar.autoupdatingCurrent 18 | return calendar.isDateInTomorrow(self) 19 | } 20 | 21 | var timeAgo: String? { 22 | let formatter = DateComponentsFormatter() 23 | formatter.unitsStyle = .full 24 | formatter.allowedUnits = [.year, .month, .day, .hour, .minute, .second] 25 | formatter.zeroFormattingBehavior = .dropAll 26 | formatter.maximumUnitCount = 1 27 | if (Date().timeIntervalSince(self) > 60) { 28 | return String(format: formatter.string(from: self, to: Date()) ?? "") 29 | } else { 30 | return nil 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ios/CalendarWidget/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.widgetkit-extension 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ios/CalendarWidgetExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.de.tum.tca-widget 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | import GoogleMaps 4 | 5 | @main 6 | @objc class AppDelegate: FlutterAppDelegate { 7 | override func application( 8 | _ application: UIApplication, 9 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 10 | ) -> Bool { 11 | GMSServices.provideAPIKey("AIzaSyAxUbnUMsXWVzeptXiLuNDMGpGEVFHLT4Y") 12 | GeneratedPluginRegistrant.register(with: self) 13 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 2.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 3.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 4.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 5.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 6.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7-1.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 7.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/AppIcon.appiconset/slice1@3x copy 8.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo-white.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TUM-Dev/campus_flutter/a840a546cd48ff207435650c125b2df07975acd7/ios/Runner/Assets.xcassets/LaunchImage.imageset/logo-white.png -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.security.application-groups 8 | 9 | group.de.tum.tca-widget 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ios/build/.last_build_id: -------------------------------------------------------------------------------- 1 | 39f4bf50ad275767c79aa66def67de4c -------------------------------------------------------------------------------- /ios/ci_scripts/ci_post_clone.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # by default, the execution directory of this script is the ci_scripts directory 4 | # CI_WORKSPACE is the directory of your cloned repo 5 | echo "🟩 Navigate from ($PWD) to ($CI_WORKSPACE)" 6 | cd $CI_WORKSPACE 7 | 8 | echo "🟩 Install Flutter" 9 | time git clone https://github.com/flutter/flutter.git -b stable $HOME/flutter 10 | export PATH="$PATH:$HOME/flutter/bin" 11 | 12 | echo "🟩 Flutter Precache" 13 | time flutter precache --ios 14 | 15 | echo "🟩 Install Flutter Dependencies" 16 | time flutter pub get 17 | 18 | echo "🟩 Install CocoaPods via Homebrew" 19 | time HOMEBREW_NO_AUTO_UPDATE=1 brew install cocoapods 20 | 21 | echo "🟩 Install CocoaPods dependencies..." 22 | time cd ios && pod install 23 | 24 | exit 0 -------------------------------------------------------------------------------- /ios/fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("de.tum.tca") 2 | team_name("Technische Universitaet Muenchen") 3 | team_id("2J3C6P6X3N") 4 | itc_team_name("Technische Universitaet Muenchen") 5 | itc_team_id("850117") -------------------------------------------------------------------------------- /ios/fastlane/Matchfile: -------------------------------------------------------------------------------- 1 | git_url("git@github.com:TUM-Dev/campus_flutter_match.git") 2 | storage_mode("git") 3 | type("appstore") 4 | app_identifier(["de.tum.tca", "de.tum.tca.calendarWidget"]) 5 | -------------------------------------------------------------------------------- /ios/firebase_app_id_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_generated_by": "FlutterFire CLI", 3 | "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", 4 | "GOOGLE_APP_ID": "1:944892355389:ios:70b9e0e71c71af4b52db54", 5 | "FIREBASE_PROJECT_ID": "tca-backend-0001", 6 | "GCM_SENDER_ID": "944892355389" 7 | } -------------------------------------------------------------------------------- /lib/base/enums/appearance.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | enum Appearance { 4 | system(Icons.devices, ThemeMode.system, "System", "System"), 5 | light(Icons.light_mode, ThemeMode.light, "Light", "Hell"), 6 | dark(Icons.dark_mode, ThemeMode.dark, "Dark", "Dunkel"); 7 | 8 | final IconData icon; 9 | final ThemeMode themeMode; 10 | final String english; 11 | final String german; 12 | 13 | const Appearance(this.icon, this.themeMode, this.english, this.german); 14 | } 15 | -------------------------------------------------------------------------------- /lib/base/enums/credentials.dart: -------------------------------------------------------------------------------- 1 | enum Credentials { none, noTumId, tumId } 2 | -------------------------------------------------------------------------------- /lib/base/enums/device.dart: -------------------------------------------------------------------------------- 1 | enum Device { phone, portraitTablet, landscapeTablet } 2 | -------------------------------------------------------------------------------- /lib/base/enums/error_handling_view_type.dart: -------------------------------------------------------------------------------- 1 | enum ErrorHandlingViewType { 2 | fullScreen, 3 | fullScreenNoImage, 4 | textOnly, 5 | descriptionOnly, 6 | redDescriptionOnly, 7 | } 8 | -------------------------------------------------------------------------------- /lib/base/enums/gender.dart: -------------------------------------------------------------------------------- 1 | enum Gender { male, female, nonBinary, unknown } 2 | -------------------------------------------------------------------------------- /lib/base/enums/home_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/widget_type.dart'; 2 | 3 | class HomeScreenWidget { 4 | WidgetType widgetType; 5 | bool enabled; 6 | 7 | HomeScreenWidget({required this.widgetType, this.enabled = true}); 8 | 9 | String convertToString() { 10 | return "${WidgetType.values.indexOf(widgetType)};${enabled.toString()}"; 11 | } 12 | 13 | static HomeScreenWidget? fromString(String data) { 14 | final dataPoints = data.split(";"); 15 | final index = int.parse(dataPoints[0]); 16 | if (index < WidgetType.values.length) { 17 | final widgetType = WidgetType.values[int.parse(dataPoints[0])]; 18 | final enabled = dataPoints[1] == "true" ? true : false; 19 | return HomeScreenWidget(widgetType: widgetType, enabled: enabled); 20 | } else { 21 | return null; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/base/enums/remote_config_message.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | enum RemoteConfigMessage { 5 | tumOnlineDegraded, 6 | tumOnlineMaintenance; 7 | 8 | String get firebaseId { 9 | switch (this) { 10 | case RemoteConfigMessage.tumOnlineDegraded: 11 | return "isTUMOnlineDegraded"; 12 | case RemoteConfigMessage.tumOnlineMaintenance: 13 | return "isTUMOnlineMaintenanceMode"; 14 | } 15 | } 16 | 17 | String message(BuildContext context) { 18 | switch (this) { 19 | case RemoteConfigMessage.tumOnlineDegraded: 20 | return context.tr("tumOnlineDegraded"); 21 | case RemoteConfigMessage.tumOnlineMaintenance: 22 | return context.tr("tumOnlineMaintenance"); 23 | } 24 | } 25 | 26 | static RemoteConfigMessage? fromString(String key) { 27 | if (key == "isTUMOnlineDegraded") { 28 | return RemoteConfigMessage.tumOnlineDegraded; 29 | } else if (key == "isTUMOnlineMaintenanceMode") { 30 | return RemoteConfigMessage.tumOnlineMaintenance; 31 | } else { 32 | return null; 33 | } 34 | } 35 | 36 | static Set get keys { 37 | return RemoteConfigMessage.values.map((e) => e.firebaseId).toSet(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/base/enums/role.dart: -------------------------------------------------------------------------------- 1 | enum Role { 2 | student("Student"), 3 | extern("Extern"), 4 | employee("Employee"); 5 | 6 | final String name; 7 | 8 | const Role(this.name); 9 | } 10 | -------------------------------------------------------------------------------- /lib/base/enums/search_type.dart: -------------------------------------------------------------------------------- 1 | enum SearchType { general, room, person } 2 | -------------------------------------------------------------------------------- /lib/base/enums/user_preference.dart: -------------------------------------------------------------------------------- 1 | enum UserPreference { 2 | cafeteria(String), 3 | departure(int), 4 | studyRoom(int), 5 | homeWidgets(List), 6 | theme(int), 7 | calendarColors(String), 8 | browser(bool), 9 | studentCardPicture(bool), 10 | failedGrades(bool), 11 | weekends(bool), 12 | hiddenCalendarEntries(bool), 13 | calendarTab(int); 14 | 15 | final Type type; 16 | 17 | const UserPreference(this.type); 18 | } 19 | -------------------------------------------------------------------------------- /lib/base/enums/widget_type.dart: -------------------------------------------------------------------------------- 1 | enum WidgetType { cafeterias, calendar, departures, studyRooms } 2 | -------------------------------------------------------------------------------- /lib/base/errorHandling/default_error_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/error_handling_view_type.dart'; 2 | import 'package:campus_flutter/base/errorHandling/error_handling_view.dart'; 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class DefaultErrorRouter extends StatelessWidget with ErrorHandlingView { 7 | DefaultErrorRouter({ 8 | super.key, 9 | required this.exception, 10 | required ErrorHandlingViewType errorHandlingViewType, 11 | Function()? retry, 12 | Color? titleColor, 13 | Color? bodyColor, 14 | }) { 15 | this.errorHandlingViewType = errorHandlingViewType; 16 | this.retry = retry; 17 | this.titleColor = titleColor; 18 | this.bodyColor = bodyColor; 19 | } 20 | 21 | final Object? exception; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return exceptionMessage( 26 | errorMessage: context.tr("unknownError"), 27 | fixMessage: context.tr("pleaseReport"), 28 | context: context, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/base/errorHandling/grpc_error_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/error_handling_view_type.dart'; 2 | import 'package:campus_flutter/base/errorHandling/error_handling_view.dart'; 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:grpc/grpc.dart'; 6 | 7 | class GrpcErrorRouter extends StatelessWidget with ErrorHandlingView { 8 | GrpcErrorRouter({ 9 | super.key, 10 | required this.grpcError, 11 | required ErrorHandlingViewType errorHandlingViewType, 12 | Function()? retry, 13 | Color? titleColor, 14 | Color? bodyColor, 15 | }) { 16 | this.errorHandlingViewType = errorHandlingViewType; 17 | this.retry = retry; 18 | this.titleColor = titleColor; 19 | this.bodyColor = bodyColor; 20 | } 21 | 22 | final GrpcError grpcError; 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return exceptionMessage( 27 | errorMessage: grpcError.message ?? context.tr("unknownError"), 28 | context: context, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/base/errorHandling/search_exception_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/error_handling_view_type.dart'; 2 | import 'package:campus_flutter/base/errorHandling/error_handling_view.dart'; 3 | import 'package:campus_flutter/searchComponent/model/search_exception.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class SearchExceptionRouter extends StatelessWidget with ErrorHandlingView { 7 | SearchExceptionRouter({ 8 | super.key, 9 | required this.searchException, 10 | required ErrorHandlingViewType errorHandlingViewType, 11 | Function()? retry, 12 | Color? titleColor, 13 | Color? bodyColor, 14 | }) { 15 | this.errorHandlingViewType = errorHandlingViewType; 16 | this.retry = retry; 17 | this.titleColor = titleColor; 18 | this.bodyColor = bodyColor; 19 | } 20 | 21 | final SearchException searchException; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return exceptionMessage( 26 | errorMessage: searchException.message, 27 | context: context, 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/base/errorHandling/type_error_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/error_handling_view_type.dart'; 2 | import 'package:campus_flutter/base/errorHandling/error_handling_view.dart'; 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class TypeErrorRouter extends StatelessWidget with ErrorHandlingView { 7 | TypeErrorRouter({ 8 | super.key, 9 | required this.typeError, 10 | required ErrorHandlingViewType errorHandlingViewType, 11 | Function()? retry, 12 | Color? titleColor, 13 | Color? bodyColor, 14 | }) { 15 | this.errorHandlingViewType = errorHandlingViewType; 16 | this.retry = retry; 17 | this.titleColor = titleColor; 18 | this.bodyColor = bodyColor; 19 | } 20 | 21 | final TypeError typeError; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return exceptionMessage( 26 | errorMessage: context.tr("decodingError"), 27 | fixMessage: context.tr("pleaseReport"), 28 | context: context, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/base/extensions/base_64_decode_image_data.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter/foundation.dart'; 3 | 4 | Uint8List base64DecodeImageData(String source) { 5 | var mutatedSource = source; 6 | mutatedSource = mutatedSource.replaceAll(r'\r\\n', ""); 7 | mutatedSource = mutatedSource.replaceAll(r'\\n', ""); 8 | return base64Decode(mutatedSource); 9 | } 10 | -------------------------------------------------------------------------------- /lib/base/extensions/cast.dart: -------------------------------------------------------------------------------- 1 | T? cast(x) => x is T ? x : null; 2 | -------------------------------------------------------------------------------- /lib/base/extensions/color.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | extension IntColorComponents on Color { 4 | int get intValue { 5 | return _floatToInt8(a) << 24 | 6 | _floatToInt8(r) << 16 | 7 | _floatToInt8(g) << 8 | 8 | _floatToInt8(b) << 0; 9 | } 10 | 11 | int get intAlpha => _floatToInt8(a); 12 | int get intRed => _floatToInt8(r); 13 | int get intGreen => _floatToInt8(g); 14 | int get intBlue => _floatToInt8(b); 15 | 16 | int _floatToInt8(double x) { 17 | return (x * 255.0).round() & 0xff; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/base/extensions/context.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | extension ContextTheme on BuildContext { 4 | ThemeData get theme => Theme.of(this); 5 | 6 | double get halfPadding => 5.0; 7 | 8 | double get padding => 15.0; 9 | 10 | Color get primaryColor => Theme.of(this).primaryColor; 11 | } 12 | -------------------------------------------------------------------------------- /lib/base/extensions/date_time.dart: -------------------------------------------------------------------------------- 1 | import 'package:intl/intl.dart'; 2 | 3 | /// found here: https://stackoverflow.com/a/54129275/20473653 4 | extension NumberOfWeeks on DateTime { 5 | int _numOfWeeks(int year) { 6 | DateTime dec28 = DateTime(year, 12, 28); 7 | int dayOfDec28 = int.parse(DateFormat("D").format(dec28)); 8 | return ((dayOfDec28 - dec28.weekday + 10) / 7).floor(); 9 | } 10 | 11 | String weekNumber() { 12 | int dayOfYear = int.parse(DateFormat("D").format(this)); 13 | int woy = ((dayOfYear - weekday + 10) / 7).floor(); 14 | if (woy < 1) { 15 | woy = _numOfWeeks(year - 1); 16 | } else if (woy > _numOfWeeks(year)) { 17 | woy = 1; 18 | } 19 | return woy.toString().padLeft(2, "0"); 20 | } 21 | } 22 | 23 | extension SameDay on DateTime { 24 | bool isAtSameDay(DateTime dateTime) { 25 | return day == dateTime.day && 26 | month == dateTime.month && 27 | year == dateTime.year; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/base/extensions/latlng_to_json.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 4 | 5 | extension JsonString on LatLng { 6 | static String? toJsonString(LatLng? latLng) { 7 | if (latLng == null) { 8 | return null; 9 | } else { 10 | return const JsonEncoder().convert(latLng.toJson()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/base/extensions/locale_fullname.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | extension FullName on Locale { 4 | String fullName() { 5 | switch (languageCode) { 6 | case 'en': 7 | return 'English'; 8 | case 'de': 9 | return 'Deutsch'; 10 | } 11 | return 'Unknown'; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/base/extensions/string_capitalize.dart: -------------------------------------------------------------------------------- 1 | /// found on https://stackoverflow.com/a/60528001 2 | extension StringExtension on String { 3 | String capitalizeFirstLetter() { 4 | return "${this[0].toUpperCase()}${substring(1)}"; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lib/base/extensions/string_levenshtein.dart: -------------------------------------------------------------------------------- 1 | extension Levenshtein on String { 2 | int levenshtein(String comparisonToken) { 3 | if (isEmpty && comparisonToken.isEmpty) { 4 | return 0; 5 | } else if (isEmpty) { 6 | return comparisonToken.length; 7 | } else if (comparisonToken.isEmpty) { 8 | return length; 9 | } 10 | 11 | List a = split(''); 12 | List b = comparisonToken.split(''); 13 | 14 | List> dist = List.generate( 15 | a.length + 1, 16 | (_) => List.filled(b.length + 1, 0), 17 | ); 18 | 19 | for (int i = 1; i <= a.length; i++) { 20 | dist[i][0] = i; 21 | } 22 | 23 | for (int j = 1; j <= b.length; j++) { 24 | dist[0][j] = j; 25 | } 26 | 27 | for (int i = 1; i <= a.length; i++) { 28 | for (int j = 1; j <= b.length; j++) { 29 | if (a[i - 1] == b[j - 1]) { 30 | dist[i][j] = dist[i - 1][j - 1]; // Noop 31 | } else { 32 | dist[i][j] = [ 33 | dist[i - 1][j] + 1, // Deletion 34 | dist[i][j - 1] + 1, // Insertion 35 | dist[i - 1][j - 1] + 1, // Substitution 36 | ].reduce((min, current) => current < min ? current : min); 37 | } 38 | } 39 | } 40 | 41 | return dist[a.length][b.length]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/base/extensions/string_remove_diacritics.dart: -------------------------------------------------------------------------------- 1 | extension RemoveDiacritics on String { 2 | /// found on: https://stackoverflow.com/a/64742829 3 | String removeDiacritics() { 4 | String string = this; 5 | 6 | var withDia = 7 | 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÕÖØòóôõöøÈÉÊËèéêëðÇçÐÌÍÎÏìíîïÙÚÛÜùúûüÑñŠšŸÿýŽž'; 8 | var withoutDia = 9 | 'AAAAAAaaaaaaOOOOOOOooooooEEEEeeeeeCcDIIIIiiiiUUUUuuuuNnSsYyyZz'; 10 | 11 | for (int i = 0; i < withDia.length; i++) { 12 | string = string.replaceAll(withDia[i], withoutDia[i]); 13 | } 14 | 15 | return string; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/base/extensions/string_valid_chars.dart: -------------------------------------------------------------------------------- 1 | extension ValidChars on String { 2 | String keepValidChars() { 3 | return replaceAll(RegExp(r'[^a-zA-Z0-9 ]'), ''); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/base/networking/apis/eatApi/eat_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/eatApi/eat_api_endpoint.dart'; 2 | import 'package:campus_flutter/base/networking/protocols/api.dart'; 3 | 4 | class EatApi extends Api { 5 | final EatApiEndpoint eatApiEndpoint; 6 | 7 | EatApi(this.eatApiEndpoint); 8 | 9 | @override 10 | String get domain => "tum-dev.github.io"; 11 | 12 | @override 13 | String get path => "eat-api/"; 14 | 15 | @override 16 | String get slug { 17 | switch (eatApiEndpoint) { 18 | case EatApiEndpointCanteens _: 19 | return "enums/canteens.json"; 20 | case EatApiEndpointLanguages _: 21 | return "enums/languages.json"; 22 | case EatApiEndpointLabels _: 23 | return "enums/labels.json"; 24 | case EatApiEndpointAll _: 25 | return "all.json"; 26 | case EatApiEndpointAllRef _: 27 | return "all_ref.json"; 28 | case EatApiEndpointMenu menu: 29 | return "${menu.location}/${menu.year}/${menu.week.toString().padLeft(1, "0")}.json"; 30 | } 31 | } 32 | 33 | @override 34 | Map get parameters => {}; 35 | 36 | @override 37 | bool get needsAuth => false; 38 | } 39 | -------------------------------------------------------------------------------- /lib/base/networking/apis/eatApi/eat_api_endpoint.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/date_time.dart'; 2 | 3 | sealed class EatApiEndpoint {} 4 | 5 | class EatApiEndpointCanteens extends EatApiEndpoint {} 6 | 7 | class EatApiEndpointLanguages extends EatApiEndpoint {} 8 | 9 | class EatApiEndpointLabels extends EatApiEndpoint {} 10 | 11 | class EatApiEndpointAll extends EatApiEndpoint {} 12 | 13 | class EatApiEndpointAllRef extends EatApiEndpoint {} 14 | 15 | class EatApiEndpointMenu extends EatApiEndpoint { 16 | final String location; 17 | final int year; 18 | final String week; 19 | 20 | EatApiEndpointMenu({required this.location, int? year, String? week}) 21 | : year = year ?? DateTime.now().year, 22 | week = week ?? DateTime.now().weekNumber(); 23 | } 24 | -------------------------------------------------------------------------------- /lib/base/networking/apis/google/protobuf/empty.pbenum.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated code. Do not modify. 3 | // source: google/protobuf/empty.proto 4 | // 5 | // @dart = 2.12 6 | 7 | // ignore_for_file: annotate_overrides, camel_case_types, comment_references 8 | // ignore_for_file: constant_identifier_names, library_prefixes 9 | // ignore_for_file: non_constant_identifier_names, prefer_final_fields 10 | // ignore_for_file: unnecessary_import, unnecessary_this, unused_import 11 | 12 | -------------------------------------------------------------------------------- /lib/base/networking/apis/google/protobuf/empty.pbjson.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated code. Do not modify. 3 | // source: google/protobuf/empty.proto 4 | // 5 | // @dart = 2.12 6 | 7 | // ignore_for_file: annotate_overrides, camel_case_types, comment_references 8 | // ignore_for_file: constant_identifier_names, library_prefixes 9 | // ignore_for_file: non_constant_identifier_names, prefer_final_fields 10 | // ignore_for_file: unnecessary_import, unnecessary_this, unused_import 11 | 12 | import 'dart:convert' as $convert; 13 | import 'dart:core' as $core; 14 | import 'dart:typed_data' as $typed_data; 15 | 16 | @$core.Deprecated('Use emptyDescriptor instead') 17 | const Empty$json = { 18 | '1': 'Empty', 19 | }; 20 | 21 | /// Descriptor for `Empty`. Decode as a `google.protobuf.DescriptorProto`. 22 | final $typed_data.Uint8List emptyDescriptor = $convert.base64Decode( 23 | 'CgVFbXB0eQ=='); 24 | 25 | -------------------------------------------------------------------------------- /lib/base/networking/apis/google/protobuf/timestamp.pbenum.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated code. Do not modify. 3 | // source: google/protobuf/timestamp.proto 4 | // 5 | // @dart = 2.12 6 | 7 | // ignore_for_file: annotate_overrides, camel_case_types, comment_references 8 | // ignore_for_file: constant_identifier_names, library_prefixes 9 | // ignore_for_file: non_constant_identifier_names, prefer_final_fields 10 | // ignore_for_file: unnecessary_import, unnecessary_this, unused_import 11 | 12 | -------------------------------------------------------------------------------- /lib/base/networking/apis/google/protobuf/timestamp.pbjson.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated code. Do not modify. 3 | // source: google/protobuf/timestamp.proto 4 | // 5 | // @dart = 2.12 6 | 7 | // ignore_for_file: annotate_overrides, camel_case_types, comment_references 8 | // ignore_for_file: constant_identifier_names, library_prefixes 9 | // ignore_for_file: non_constant_identifier_names, prefer_final_fields 10 | // ignore_for_file: unnecessary_import, unnecessary_this, unused_import 11 | 12 | import 'dart:convert' as $convert; 13 | import 'dart:core' as $core; 14 | import 'dart:typed_data' as $typed_data; 15 | 16 | @$core.Deprecated('Use timestampDescriptor instead') 17 | const Timestamp$json = { 18 | '1': 'Timestamp', 19 | '2': [ 20 | {'1': 'seconds', '3': 1, '4': 1, '5': 3, '10': 'seconds'}, 21 | {'1': 'nanos', '3': 2, '4': 1, '5': 5, '10': 'nanos'}, 22 | ], 23 | }; 24 | 25 | /// Descriptor for `Timestamp`. Decode as a `google.protobuf.DescriptorProto`. 26 | final $typed_data.Uint8List timestampDescriptor = $convert.base64Decode( 27 | 'CglUaW1lc3RhbXASGAoHc2Vjb25kcxgBIAEoA1IHc2Vjb25kcxIUCgVuYW5vcxgCIAEoBVIFbm' 28 | 'Fub3M='); 29 | 30 | -------------------------------------------------------------------------------- /lib/base/networking/apis/irisApi/iris_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/irisApi/iris_api_endpoint.dart'; 2 | import 'package:campus_flutter/base/networking/protocols/api.dart'; 3 | 4 | class IrisApi extends Api { 5 | final IrisApiEndpoint irisApiEndpoint; 6 | 7 | IrisApi({required this.irisApiEndpoint}); 8 | 9 | @override 10 | String get domain => "iris.asta.tum.de"; 11 | 12 | @override 13 | bool get needsAuth => false; 14 | 15 | @override 16 | Map get parameters => irisApiEndpoint.getParameters(); 17 | 18 | @override 19 | String get path => ""; 20 | 21 | @override 22 | String get slug => "api"; 23 | } 24 | -------------------------------------------------------------------------------- /lib/base/networking/apis/irisApi/iris_api_endpoint.dart: -------------------------------------------------------------------------------- 1 | sealed class IrisApiEndpoint { 2 | Map getParameters() => {}; 3 | } 4 | 5 | class IrisApiEndpointRooms extends IrisApiEndpoint {} 6 | -------------------------------------------------------------------------------- /lib/base/networking/apis/mvvDeparturesApi/mvv_departures_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/protocols/api.dart'; 2 | 3 | class MvvDeparturesApi extends Api { 4 | final String station; 5 | final int? walkingTime; 6 | 7 | MvvDeparturesApi({required this.station, required this.walkingTime}); 8 | 9 | @override 10 | String get domain => "efa.mvv-muenchen.de"; 11 | 12 | @override 13 | bool get needsAuth => false; 14 | 15 | @override 16 | Map get parameters => { 17 | "outputFormat": "JSON", 18 | "language": "en", 19 | "stateless": "1", 20 | "coordOutputFormat": "WGS84", 21 | "type_dm": "stop", 22 | "name_dm": station, 23 | if (walkingTime != null) "timeOffset": walkingTime.toString(), 24 | "useRealtime": "1", 25 | "itOptionsActive": "1", 26 | "ptOptionsActive": "1", 27 | "limit": "20", 28 | "mergeDep": "1", 29 | "useAllStops": "1", 30 | "mode": "direct", 31 | }; 32 | 33 | @override 34 | String get path => "ng/"; 35 | 36 | @override 37 | String get slug => "XML_DM_REQUEST"; 38 | } 39 | -------------------------------------------------------------------------------- /lib/base/networking/apis/navigaTumApi/navigatum_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/navigaTumApi/navigatum_api_endpoint.dart'; 2 | import 'package:campus_flutter/base/networking/protocols/api.dart'; 3 | 4 | class NavigaTumApi extends Api { 5 | final NavigaTumApiEndpoint navigaTumApiEndpoint; 6 | 7 | NavigaTumApi({required this.navigaTumApiEndpoint}); 8 | 9 | @override 10 | String get domain => "nav.tum.de"; 11 | 12 | @override 13 | bool get needsAuth => false; 14 | 15 | @override 16 | Map get parameters => navigaTumApiEndpoint.getParameters(); 17 | 18 | @override 19 | String get path => ""; 20 | 21 | @override 22 | String get slug { 23 | switch (navigaTumApiEndpoint) { 24 | case NavigaTumApiEndpointSearch _: 25 | return "api/search"; 26 | case NavigaTumApiEndpointDetails details: 27 | return "api/locations/${details.id}"; 28 | case NavigaTumApiEndpointImages images: 29 | return "cdn/maps/roomfinder/${images.id}"; 30 | case NavigaTumApiEndpointOverlayImages overlayImages: 31 | return "cdn/maps/roomfinder/${overlayImages.id}"; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/base/networking/apis/navigaTumApi/navigatum_api_endpoint.dart: -------------------------------------------------------------------------------- 1 | sealed class NavigaTumApiEndpoint { 2 | Map getParameters() => {}; 3 | } 4 | 5 | class NavigaTumApiEndpointSearch extends NavigaTumApiEndpoint { 6 | final String query; 7 | 8 | NavigaTumApiEndpointSearch({required this.query}); 9 | 10 | @override 11 | Map getParameters() => {"q": query}; 12 | } 13 | 14 | class NavigaTumApiEndpointDetails extends NavigaTumApiEndpoint { 15 | final String id; 16 | final String language; 17 | 18 | NavigaTumApiEndpointDetails({required this.id, required this.language}); 19 | 20 | @override 21 | Map getParameters() => {"lang": language}; 22 | } 23 | 24 | class NavigaTumApiEndpointImages extends NavigaTumApiEndpoint { 25 | final String id; 26 | 27 | NavigaTumApiEndpointImages({required this.id}); 28 | } 29 | 30 | class NavigaTumApiEndpointOverlayImages extends NavigaTumApiEndpoint { 31 | final String id; 32 | 33 | NavigaTumApiEndpointOverlayImages({required this.id}); 34 | } 35 | -------------------------------------------------------------------------------- /lib/base/networking/base/api_response.dart: -------------------------------------------------------------------------------- 1 | class ApiResponse { 2 | T data; 3 | DateTime? saved; 4 | 5 | ApiResponse({required this.data, this.saved}); 6 | 7 | factory ApiResponse.fromJson( 8 | dynamic json, 9 | Map extras, 10 | Function(Map) create, 11 | ) { 12 | if (json is List) { 13 | return ApiResponse( 14 | data: create({"data": json}), 15 | saved: extras["saved"] as DateTime?, 16 | ); 17 | } else { 18 | return ApiResponse( 19 | data: create(json), 20 | saved: extras["saved"] as DateTime?, 21 | ); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/base/networking/protocols/api_exception.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'api_exception.g.dart'; 6 | 7 | abstract class ApiException implements Exception { 8 | String message(BuildContext? context, WidgetRef? ref); 9 | 10 | String? recoverySuggestion(BuildContext context, WidgetRef ref); 11 | 12 | Function()? overwriteRetry(BuildContext context); 13 | 14 | String? overwriteRetryMessage(BuildContext context); 15 | } 16 | 17 | @JsonSerializable() 18 | class ExceptionBody { 19 | @JsonKey(name: "error") 20 | final ExceptionMessage exceptionMessage; 21 | 22 | ExceptionBody({required this.exceptionMessage}); 23 | 24 | factory ExceptionBody.fromJson(Map json) => 25 | _$ExceptionBodyFromJson(json); 26 | 27 | Map toJson() => _$ExceptionBodyToJson(this); 28 | } 29 | 30 | @JsonSerializable() 31 | class ExceptionMessage { 32 | final String message; 33 | 34 | ExceptionMessage({required this.message}); 35 | 36 | factory ExceptionMessage.fromJson(Map json) => 37 | _$ExceptionMessageFromJson(json); 38 | 39 | Map toJson() => _$ExceptionMessageToJson(this); 40 | } 41 | -------------------------------------------------------------------------------- /lib/base/networking/protocols/api_exception.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'api_exception.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ExceptionBody _$ExceptionBodyFromJson(Map json) => 10 | ExceptionBody( 11 | exceptionMessage: ExceptionMessage.fromJson( 12 | json['error'] as Map, 13 | ), 14 | ); 15 | 16 | Map _$ExceptionBodyToJson(ExceptionBody instance) => 17 | {'error': instance.exceptionMessage}; 18 | 19 | ExceptionMessage _$ExceptionMessageFromJson(Map json) => 20 | ExceptionMessage(message: json['message'] as String); 21 | 22 | Map _$ExceptionMessageToJson(ExceptionMessage instance) => 23 | {'message': instance.message}; 24 | -------------------------------------------------------------------------------- /lib/base/services/connection_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | class ConnectionService { 4 | bool _hasInternet = true; 5 | DateTime? _dateTime; 6 | 7 | ConnectionService() { 8 | checkConnection(); 9 | } 10 | 11 | Future checkConnection() async { 12 | if (_dateTime != null && 13 | _dateTime!.difference(DateTime.now()).inSeconds < 30) { 14 | return _hasInternet; 15 | } else { 16 | _hasInternet = await _lookupInternetAddress(); 17 | return _hasInternet; 18 | } 19 | } 20 | 21 | Future _lookupInternetAddress() { 22 | _dateTime = DateTime.now(); 23 | return InternetAddress.lookup("google.com").then( 24 | (value) => 25 | _hasInternet = (value.isNotEmpty && value[0].rawAddress.isNotEmpty), 26 | onError: (_) => false, 27 | ); 28 | } 29 | 30 | bool hasInternet() { 31 | checkConnection(); 32 | return _hasInternet; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/base/services/device_type_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/device.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class DeviceService { 5 | static Device getType(BuildContext context) { 6 | return MediaQuery.orientationOf(context) == Orientation.landscape 7 | ? Device.landscapeTablet 8 | : MediaQuery.sizeOf(context).width > 600 9 | ? Device.portraitTablet 10 | : Device.phone; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/base/services/location_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:geolocator/geolocator.dart'; 2 | 3 | /// Determine the current position of the device. 4 | /// 5 | /// When the location services are not enabled or permissions 6 | /// are denied the `Future` will return an error. 7 | class LocationService { 8 | static Future determinePosition() async { 9 | bool serviceEnabled; 10 | LocationPermission permission; 11 | 12 | serviceEnabled = await Geolocator.isLocationServiceEnabled(); 13 | if (!serviceEnabled) { 14 | return Future.error("Location Service disabled"); 15 | } 16 | 17 | permission = await Geolocator.checkPermission(); 18 | if (permission == LocationPermission.denied) { 19 | permission = await Geolocator.requestPermission(); 20 | if (permission == LocationPermission.deniedForever) { 21 | return Future.error("Permission forever denied"); 22 | } 23 | 24 | if (permission == LocationPermission.denied) { 25 | return Future.error("Permission denied"); 26 | } 27 | } 28 | 29 | return await Geolocator.getCurrentPosition(); 30 | } 31 | 32 | static Future getLastKnown() async { 33 | try { 34 | return await Geolocator.getLastKnownPosition(); 35 | } catch (_) { 36 | return null; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/base/theme/constants.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const Color primaryLightColor = Color(0xff0064BC); 4 | const Color primaryDarkColor = Color(0xff3070B3); 5 | const Color lightBackground = Color(0xfff2f2f7); 6 | const Color darkBackground = Color(0xff191919); 7 | const Color lightGray = Color(0xffAAAAAA); 8 | const Color navigationIconGrayLight = Color(0xffA0A0A1); 9 | const Color navigationIconGrayDark = Color(0xff808080); 10 | const Color darkGray = Color(0xff555555); 11 | const Color almostBlack = Color(0xff1a1c1e); 12 | const Color almostWhite = Color(0xffe3e2e6); 13 | -------------------------------------------------------------------------------- /lib/base/util/custom_back_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/routing/routes.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:go_router/go_router.dart'; 4 | 5 | class CustomBackButton extends StatelessWidget { 6 | const CustomBackButton({ 7 | super.key, 8 | this.beforeOnPressed, 9 | this.onPressed, 10 | this.color, 11 | }); 12 | 13 | final Function()? onPressed; 14 | final Function()? beforeOnPressed; 15 | final Color? color; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return BackButton( 20 | color: color, 21 | onPressed: () { 22 | if (beforeOnPressed != null) { 23 | beforeOnPressed!(); 24 | } 25 | 26 | if (onPressed != null) { 27 | onPressed!(); 28 | } else { 29 | defaultOnPressed(context); 30 | } 31 | }, 32 | ); 33 | } 34 | 35 | void defaultOnPressed(BuildContext context) { 36 | context.canPop() ? context.pop() : context.go(home); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/base/util/days_parser.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | List decodeDaysBitmask(String bitmaskString) { 4 | final bitmask = int.tryParse(bitmaskString); 5 | if (bitmask == null) { 6 | return []; 7 | } 8 | 9 | final decodedDays = []; 10 | 11 | for (int i = 0; i < 7; i++) { 12 | if (bitmask & (1 << i) != 0) { 13 | decodedDays.add(i + 1); 14 | } 15 | } 16 | 17 | return decodedDays; 18 | } 19 | 20 | String getDayOfWeek(int dayNumber) { 21 | final daysOfWeek = [ 22 | 'monday', 23 | 'tuesday', 24 | 'wednesday', 25 | 'thursday', 26 | 'friday', 27 | 'saturday', 28 | 'sunday', 29 | ]; 30 | return daysOfWeek[dayNumber - 1]; 31 | } 32 | -------------------------------------------------------------------------------- /lib/base/util/enum_parser.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/shortcut_item.dart'; 2 | import 'package:collection/collection.dart'; 3 | 4 | class EnumParser { 5 | static ShortcutItemType typeFromString(String string) { 6 | return ShortcutItemType.values.firstWhereOrNull((e) => e.type == string) ?? 7 | ShortcutItemType.home; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/base/util/fast_hash.dart: -------------------------------------------------------------------------------- 1 | /// as found on https://isar.dev/recipes/string_ids.html#fast-hash-function 2 | int fastHash(String string) { 3 | var hash = 0xcbf29ce484222325; 4 | 5 | var i = 0; 6 | while (i < string.length) { 7 | final codeUnit = string.codeUnitAt(i++); 8 | hash ^= codeUnit >> 8; 9 | hash *= 0x100000001b3; 10 | hash ^= codeUnit & 0xFF; 11 | hash *= 0x100000001b3; 12 | } 13 | 14 | return hash; 15 | } 16 | -------------------------------------------------------------------------------- /lib/base/util/grid_utility.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/device.dart'; 2 | import 'package:campus_flutter/base/services/device_type_service.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class GridUtility { 6 | static int campusCrossAxisCount(BuildContext context) { 7 | switch (DeviceService.getType(context)) { 8 | case Device.landscapeTablet: 9 | return 6; 10 | case Device.portraitTablet: 11 | return 4; 12 | case Device.phone: 13 | return 2; 14 | } 15 | } 16 | 17 | static int campusPaddedCrossAxisCount(BuildContext context) { 18 | switch (DeviceService.getType(context)) { 19 | case Device.landscapeTablet: 20 | return 3; 21 | case Device.portraitTablet: 22 | return 4; 23 | case Device.phone: 24 | return 2; 25 | } 26 | } 27 | 28 | static int campusNumberOfItems(BuildContext context) { 29 | switch (DeviceService.getType(context)) { 30 | case Device.landscapeTablet: 31 | return 6; 32 | case Device.portraitTablet: 33 | return 8; 34 | case Device.phone: 35 | return 6; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/base/util/info_row.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/context.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class InfoRow extends StatelessWidget { 5 | const InfoRow({super.key, required this.title, required this.info}); 6 | 7 | final String title; 8 | final String info; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Row( 13 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 14 | children: [ 15 | Expanded( 16 | child: Text( 17 | title, 18 | style: const TextStyle(fontWeight: FontWeight.w500), 19 | ), 20 | ), 21 | Padding(padding: EdgeInsets.symmetric(horizontal: context.halfPadding)), 22 | Expanded(child: Text(info)), 23 | ], 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/base/util/last_updated_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | import 'package:timeago/timeago.dart' as timeago; 5 | 6 | class LastUpdatedText extends ConsumerWidget { 7 | const LastUpdatedText(this.dateTime, {super.key}); 8 | 9 | final DateTime dateTime; 10 | 11 | @override 12 | Widget build(BuildContext context, WidgetRef ref) { 13 | timeago.setLocaleMessages("de", timeago.DeMessages()); 14 | return Center( 15 | child: Text( 16 | context.tr( 17 | "lastUpdatedAt", 18 | args: [ 19 | timeago.format( 20 | dateTime, 21 | locale: Localizations.localeOf(context).languageCode, 22 | ), 23 | ], 24 | ), 25 | style: Theme.of( 26 | context, 27 | ).textTheme.bodySmall?.copyWith(color: Colors.grey.shade600), 28 | maxLines: 1, 29 | overflow: TextOverflow.ellipsis, 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/base/util/padded_divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/context.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class PaddedDivider extends StatelessWidget { 5 | const PaddedDivider({super.key, this.height}); 6 | 7 | final double? height; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Padding( 12 | padding: EdgeInsets.symmetric(horizontal: context.padding), 13 | child: Divider(height: height), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/base/util/placeholder_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class PlaceholderText extends StatelessWidget { 4 | const PlaceholderText({super.key, required this.text, this.style}); 5 | 6 | final String text; 7 | final TextStyle? style; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | var textSize = _calcTextSize(context); 12 | return Container( 13 | height: textSize.height, 14 | width: textSize.width, 15 | color: Colors.grey, 16 | ); 17 | } 18 | 19 | /// found on: https://stackoverflow.com/a/63133637 20 | Size _calcTextSize(BuildContext context) { 21 | final TextPainter textPainter = TextPainter( 22 | text: TextSpan(text: text, style: style), 23 | textDirection: TextDirection.ltr, 24 | textScaler: MediaQuery.textScalerOf(context), 25 | )..layout(); 26 | return textPainter.size; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/base/util/read_list_value.dart: -------------------------------------------------------------------------------- 1 | List readListValue(Map data, String key) { 2 | final relevantData = data[key]; 3 | if (relevantData is List) { 4 | return relevantData; 5 | } else if (relevantData is Map || relevantData is String) { 6 | return [relevantData]; 7 | } else { 8 | return []; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/base/util/semester_calculator.dart: -------------------------------------------------------------------------------- 1 | class SemesterCalculator { 2 | static String getCurrentSemester() { 3 | final date = DateTime.now(); 4 | if (date.isBefore(DateTime(date.year, 4, 1))) { 5 | final year = (date.year - 1).toString().substring(2, 4); 6 | return "${year}W"; 7 | } else if (date.isBefore(DateTime(date.year, 9, 1))) { 8 | final year = (date.year).toString().substring(2, 4); 9 | return "${year}S"; 10 | } else { 11 | final year = (date.year).toString().substring(2, 4); 12 | return "${year}W"; 13 | } 14 | } 15 | 16 | static String getPriorSemester() { 17 | final date = DateTime.now(); 18 | if (date.isBefore(DateTime(date.year, 4, 1))) { 19 | final year = (date.year - 1).toString().substring(2, 4); 20 | return "${year}S"; 21 | } else if (date.isBefore(DateTime(date.year, 9, 1))) { 22 | final year = (date.year - 1).toString().substring(2, 4); 23 | return "${year}W"; 24 | } else { 25 | final year = (date.year).toString().substring(2, 4); 26 | return "${year}S"; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/base/util/shimmer_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shimmer/shimmer.dart'; 3 | 4 | class ShimmerView extends StatelessWidget { 5 | final Widget child; 6 | 7 | const ShimmerView({super.key, required this.child}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Shimmer.fromColors( 12 | baseColor: 13 | MediaQuery.of(context).platformBrightness == Brightness.light 14 | ? Colors.grey.shade300 15 | : Colors.grey.shade800, 16 | highlightColor: 17 | MediaQuery.of(context).platformBrightness == Brightness.light 18 | ? Colors.grey.shade100 19 | : Colors.grey.shade600, 20 | child: child, 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/base/util/speaker.dart: -------------------------------------------------------------------------------- 1 | class Speaker { 2 | static String getSpeakerName(String speakerString) { 3 | final speakers = speakerString.split(", "); 4 | final mainSpeaker = speakers.first.split(" [L]"); 5 | return mainSpeaker.first.split(" (").first; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/base/util/url_launcher.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:campus_flutter/settingsComponent/views/settings_view.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | import 'package:url_launcher/url_launcher.dart'; 6 | import 'package:url_launcher/url_launcher_string.dart'; 7 | 8 | class UrlLauncher { 9 | static urlString(String urlString, WidgetRef ref) async { 10 | if (await canLaunchUrlString(urlString)) { 11 | if (ref.read(useWebView)) { 12 | launchUrlString(urlString, mode: LaunchMode.inAppBrowserView).onError( 13 | (error, stackTrace) => 14 | launchUrlString(urlString, mode: LaunchMode.externalApplication), 15 | ); 16 | } else { 17 | launchUrlString(urlString, mode: LaunchMode.externalApplication); 18 | } 19 | } 20 | } 21 | 22 | static url(Uri url, WidgetRef ref) async { 23 | if (await canLaunchUrl(url)) { 24 | if (ref.read(useWebView) && Platform.isIOS) { 25 | launchUrl(url, mode: LaunchMode.inAppWebView).onError( 26 | (error, stackTrace) => 27 | launchUrl(url, mode: LaunchMode.externalApplication), 28 | ); 29 | } else { 30 | launchUrl(url, mode: LaunchMode.externalApplication); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/calendarComponent/model/calendar_preferences.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'calendar_preferences.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CalendarPreferences { 7 | final Map colorPreferences; 8 | final Map visibilityPreferences; 9 | 10 | CalendarPreferences(this.colorPreferences, this.visibilityPreferences); 11 | 12 | factory CalendarPreferences.fromJson(Map json) => 13 | _$CalendarPreferencesFromJson(json); 14 | 15 | Map toJson() => _$CalendarPreferencesToJson(this); 16 | } 17 | -------------------------------------------------------------------------------- /lib/calendarComponent/model/calendar_preferences.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'calendar_preferences.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CalendarPreferences _$CalendarPreferencesFromJson(Map json) => 10 | CalendarPreferences( 11 | Map.from(json['colorPreferences'] as Map), 12 | Map.from(json['visibilityPreferences'] as Map), 13 | ); 14 | 15 | Map _$CalendarPreferencesToJson( 16 | CalendarPreferences instance, 17 | ) => { 18 | 'colorPreferences': instance.colorPreferences, 19 | 'visibilityPreferences': instance.visibilityPreferences, 20 | }; 21 | -------------------------------------------------------------------------------- /lib/calendarComponent/views/visibility_button_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | 5 | class VisibilityButtonView extends ConsumerStatefulWidget { 6 | const VisibilityButtonView({ 7 | super.key, 8 | required this.id, 9 | required this.isVisible, 10 | }); 11 | 12 | final String id; 13 | final bool? isVisible; 14 | 15 | @override 16 | ConsumerState createState() => 17 | _VisibilityButtonViewState(); 18 | } 19 | 20 | class _VisibilityButtonViewState extends ConsumerState { 21 | late bool isVisible = widget.isVisible ?? true; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return InkWell( 26 | onTap: () { 27 | ref.read(calendarViewModel).toggleEventVisibility(widget.id); 28 | setState(() { 29 | isVisible = !isVisible; 30 | }); 31 | }, 32 | child: Icon((isVisible) ? Icons.visibility : Icons.visibility_off), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/campusComponent/model/student_club.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pb.dart'; 2 | import 'package:html/parser.dart'; 3 | 4 | extension ParsedStudentClub on StudentClub { 5 | String get parsedName => parseFragment(name).text ?? name; 6 | } 7 | -------------------------------------------------------------------------------- /lib/campusComponent/model/student_club_collection.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pb.dart'; 2 | import 'package:html/parser.dart'; 3 | 4 | extension ParsedStudentClubCollection on StudentClubCollection { 5 | String get parsedTitle => parseFragment(title).text ?? title; 6 | } 7 | -------------------------------------------------------------------------------- /lib/campusComponent/service/movie_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/google/protobuf/timestamp.pb.dart'; 2 | import 'package:campus_flutter/base/networking/base/grpc_client.dart'; 3 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pbgrpc.dart'; 4 | import 'package:campus_flutter/main.dart'; 5 | 6 | class MovieService { 7 | static Future<(DateTime?, List)> fetchMovies( 8 | bool forcedRefresh, 9 | ) async { 10 | final currentDate = DateTime.now(); 11 | GrpcClient grpcClient = getIt(); 12 | final response = await grpcClient.listMovies( 13 | ListMoviesRequest(oldestDateAt: Timestamp.fromDateTime(currentDate)), 14 | ); 15 | return (currentDate, response.movies); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/campusComponent/service/news_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/google/protobuf/timestamp.pb.dart'; 2 | import 'package:campus_flutter/base/networking/base/grpc_client.dart'; 3 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pbgrpc.dart'; 4 | import 'package:campus_flutter/main.dart'; 5 | 6 | class NewsService { 7 | static Future<(DateTime?, List)> fetchRecentNews( 8 | bool forcedRefresh, 9 | ) async { 10 | final start = DateTime.now(); 11 | GrpcClient grpcClient = getIt(); 12 | final news = await grpcClient.listNews( 13 | ListNewsRequest( 14 | oldestDateAt: Timestamp.fromDateTime( 15 | DateTime( 16 | start.year, 17 | start.month, 18 | start.day, 19 | ).subtract(const Duration(days: 30)), 20 | ), 21 | ), 22 | ); 23 | return (start, news.news); 24 | } 25 | 26 | static Future<(DateTime?, List)> fetchNews(bool forcedRefresh) async { 27 | final start = DateTime.now(); 28 | GrpcClient grpcClient = getIt(); 29 | final news = await grpcClient.listNews(ListNewsRequest()); 30 | return (start, news.news); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/campusComponent/service/student_club_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pb.dart'; 2 | import 'package:campus_flutter/base/networking/base/grpc_client.dart'; 3 | import 'package:campus_flutter/main.dart'; 4 | 5 | class StudentClubService { 6 | static Future<(DateTime?, List)> fetchStudentClubs( 7 | Language? language, 8 | bool forceRefresh, 9 | ) async { 10 | final start = DateTime.now(); 11 | GrpcClient grpcClient = getIt(); 12 | final response = await grpcClient.listStudentClub( 13 | ListStudentClubRequest(language: language), 14 | ); 15 | return (start, response.collections); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/campusComponent/view/movie/movie_grid_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/context.dart'; 2 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pb.dart'; 3 | import 'package:campus_flutter/campusComponent/view/movie/movie_card_view.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class MovieGridView extends StatelessWidget { 7 | const MovieGridView({ 8 | super.key, 9 | required this.movies, 10 | required this.padding, 11 | required this.crossAxisCount, 12 | required this.withinScrollView, 13 | }); 14 | 15 | final List movies; 16 | final EdgeInsets padding; 17 | final int crossAxisCount; 18 | final bool withinScrollView; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return GridView.count( 23 | shrinkWrap: withinScrollView, 24 | physics: withinScrollView ? NeverScrollableScrollPhysics() : null, 25 | padding: padding, 26 | crossAxisCount: crossAxisCount, 27 | mainAxisSpacing: context.padding, 28 | crossAxisSpacing: context.padding, 29 | childAspectRatio: 250 / 470, 30 | children: [for (var movie in movies) MovieCardView(movie: movie)], 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/campusComponent/view/studentClub/student_club_grid_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/context.dart'; 2 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pb.dart'; 3 | import 'package:campus_flutter/campusComponent/view/studentClub/student_club_card_view.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class StudentClubGridView extends StatelessWidget { 7 | const StudentClubGridView({ 8 | super.key, 9 | required this.studentClubs, 10 | required this.padding, 11 | required this.crossAxisCount, 12 | required this.withinScrollView, 13 | }); 14 | 15 | final List studentClubs; 16 | final EdgeInsets padding; 17 | final int crossAxisCount; 18 | final bool withinScrollView; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return GridView.count( 23 | shrinkWrap: withinScrollView, 24 | physics: withinScrollView ? NeverScrollableScrollPhysics() : null, 25 | padding: padding, 26 | mainAxisSpacing: context.padding, 27 | crossAxisSpacing: context.padding, 28 | crossAxisCount: crossAxisCount, 29 | children: [ 30 | for (var studentClub in studentClubs) 31 | StudentClubCardView(studentClub: studentClub), 32 | ], 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/campusComponent/viewmodel/movies_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pbgrpc.dart'; 2 | import 'package:campus_flutter/campusComponent/service/movie_service.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | import 'package:rxdart/rxdart.dart'; 5 | 6 | final movieViewModel = Provider((ref) => MovieViewModel()); 7 | 8 | class MovieViewModel { 9 | final BehaviorSubject?> movies = BehaviorSubject.seeded(null); 10 | final BehaviorSubject lastFetched = BehaviorSubject.seeded(null); 11 | 12 | Future fetch(bool forcedRefresh) async { 13 | return MovieService.fetchMovies(forcedRefresh).then((response) { 14 | lastFetched.add(response.$1); 15 | movies.add(response.$2); 16 | }, onError: (error) => movies.addError(error)); 17 | } 18 | } 19 | 20 | extension MovieTitle on Movie { 21 | String get movieTitle { 22 | final titleParts = title.split(": "); 23 | return titleParts.length == 2 ? titleParts[1] : title; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/feedbackComponent/services/feedback_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:campus_flutter/base/networking/base/grpc_client.dart'; 4 | import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pbgrpc.dart'; 5 | import 'package:campus_flutter/main.dart'; 6 | 7 | class FeedbackService { 8 | static Future sendFeedback( 9 | CreateFeedbackRequest createFeedbackRequest, 10 | ) async { 11 | GrpcClient restClient = getIt(); 12 | return await restClient.createFeedback(Stream.value(createFeedbackRequest)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/feedbackComponent/views/feedback_checkmark_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | import 'package:rxdart/rxdart.dart'; 4 | 5 | class FeedbackCheckMarkView extends ConsumerWidget { 6 | const FeedbackCheckMarkView({ 7 | super.key, 8 | required this.text, 9 | required this.isChecked, 10 | }); 11 | 12 | final String text; 13 | final BehaviorSubject isChecked; 14 | 15 | @override 16 | Widget build(BuildContext context, WidgetRef ref) { 17 | return StreamBuilder( 18 | stream: isChecked, 19 | builder: (context, snapshot) { 20 | return ListTile( 21 | dense: true, 22 | title: Text(text), 23 | trailing: Checkbox( 24 | value: snapshot.data ?? false, 25 | onChanged: (newValue) => isChecked.add(newValue ?? false), 26 | ), 27 | ); 28 | }, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/homeComponent/model/departures_preference.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/enums/campus.dart'; 2 | import 'package:campus_flutter/homeComponent/model/station.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'departures_preference.g.dart'; 6 | 7 | @JsonSerializable() 8 | class DeparturesPreference { 9 | final Map preferences; 10 | 11 | DeparturesPreference({required this.preferences}); 12 | 13 | factory DeparturesPreference.fromJson(Map json) => 14 | _$DeparturesPreferenceFromJson(json); 15 | 16 | Map toJson() => _$DeparturesPreferenceToJson(this); 17 | } 18 | -------------------------------------------------------------------------------- /lib/homeComponent/model/departures_preference.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'departures_preference.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | DeparturesPreference _$DeparturesPreferenceFromJson( 10 | Map json, 11 | ) => DeparturesPreference( 12 | preferences: (json['preferences'] as Map).map( 13 | (k, e) => MapEntry( 14 | $enumDecode(_$CampusEnumMap, k), 15 | Station.fromJson(e as Map), 16 | ), 17 | ), 18 | ); 19 | 20 | Map _$DeparturesPreferenceToJson( 21 | DeparturesPreference instance, 22 | ) => { 23 | 'preferences': instance.preferences.map( 24 | (k, e) => MapEntry(_$CampusEnumMap[k]!, e), 25 | ), 26 | }; 27 | 28 | const _$CampusEnumMap = { 29 | Campus.stammgelaende: 'stammgelaende', 30 | Campus.olympiapark: 'olympiapark', 31 | Campus.klinikumRechts: 'klinikumRechts', 32 | Campus.grosshadern: 'grosshadern', 33 | Campus.garching: 'garching', 34 | Campus.freising: 'freising', 35 | }; 36 | -------------------------------------------------------------------------------- /lib/homeComponent/model/mvv_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/homeComponent/model/departure.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'mvv_response.g.dart'; 5 | 6 | @JsonSerializable() 7 | class MvvResponse { 8 | @JsonKey(name: "departureList", readValue: readDepartures) 9 | final List departures; 10 | 11 | MvvResponse({required this.departures}); 12 | 13 | factory MvvResponse.fromJson(Map json) => 14 | _$MvvResponseFromJson(json); 15 | 16 | Map toJson() => _$MvvResponseToJson(this); 17 | 18 | static List readDepartures(Map data, String key) { 19 | final relevantData = data[key]; 20 | if (relevantData is List) { 21 | return relevantData; 22 | } else if (relevantData is Map) { 23 | return [relevantData["departure"]]; 24 | } else { 25 | return []; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/homeComponent/model/mvv_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'mvv_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | MvvResponse _$MvvResponseFromJson(Map json) => MvvResponse( 10 | departures: 11 | (MvvResponse.readDepartures(json, 'departureList') as List) 12 | .map((e) => Departure.fromJson(e as Map)) 13 | .toList(), 14 | ); 15 | 16 | Map _$MvvResponseToJson(MvvResponse instance) => 17 | {'departureList': instance.departures}; 18 | -------------------------------------------------------------------------------- /lib/homeComponent/model/station.dart: -------------------------------------------------------------------------------- 1 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 2 | import 'package:campus_flutter/base/extensions/latlng_to_json.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'station.g.dart'; 6 | 7 | @JsonSerializable() 8 | /// local data type 9 | class Station { 10 | final String name; 11 | final String apiName; 12 | @JsonKey(fromJson: LatLng.fromJson, toJson: JsonString.toJsonString) 13 | final LatLng? location; 14 | 15 | Station({required this.name, required this.apiName, this.location}); 16 | 17 | factory Station.fromJson(Map json) => 18 | _$StationFromJson(json); 19 | 20 | Map toJson() => _$StationToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /lib/homeComponent/model/station.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'station.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Station _$StationFromJson(Map json) => Station( 10 | name: json['name'] as String, 11 | apiName: json['apiName'] as String, 12 | location: LatLng.fromJson(json['location']), 13 | ); 14 | 15 | Map _$StationToJson(Station instance) => { 16 | 'name': instance.name, 17 | 'apiName': instance.apiName, 18 | 'location': JsonString.toJsonString(instance.location), 19 | }; 20 | -------------------------------------------------------------------------------- /lib/homeComponent/service/departures_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/mvvDeparturesApi/mvv_departures_api.dart'; 2 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 3 | import 'package:campus_flutter/homeComponent/model/mvv_response.dart'; 4 | import 'package:campus_flutter/main.dart'; 5 | 6 | class DeparturesService { 7 | static Future<({DateTime? saved, MvvResponse data})> fetchDepartures( 8 | bool forcedRefresh, 9 | String station, 10 | int? walkingTime, 11 | ) async { 12 | RestClient restClient = getIt(); 13 | final response = await restClient.get( 14 | MvvDeparturesApi(station: station, walkingTime: walkingTime), 15 | MvvResponse.fromJson, 16 | forcedRefresh, 17 | ); 18 | 19 | return (saved: response.saved, data: response.data); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/homeComponent/view/contactCard/contact_card_error_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class ContactCardErrorView extends StatelessWidget { 5 | const ContactCardErrorView({super.key}); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Padding( 10 | padding: const EdgeInsets.all(10.0), 11 | child: Row( 12 | children: [ 13 | const CircleAvatar( 14 | backgroundImage: AssetImage( 15 | 'assets/images/placeholders/portrait_placeholder.png', 16 | ), 17 | radius: 50, 18 | ), 19 | const Padding(padding: EdgeInsets.only(left: 15)), 20 | Expanded( 21 | child: Text( 22 | context.tr("profileError"), 23 | style: Theme.of(context).textTheme.titleLarge, 24 | textAlign: TextAlign.center, 25 | ), 26 | ), 27 | ], 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/homeComponent/view/contactCard/contact_card_unauthorized_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/routing/routes.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:go_router/go_router.dart'; 5 | 6 | class ContactCardUnauthorizedView extends StatelessWidget { 7 | const ContactCardUnauthorizedView({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return InkWell( 12 | onTap: () => context.push(onboarding), 13 | child: Padding( 14 | padding: const EdgeInsets.all(10.0), 15 | child: Row( 16 | children: [ 17 | const CircleAvatar( 18 | backgroundImage: AssetImage( 19 | 'assets/images/placeholders/portrait_placeholder.png', 20 | ), 21 | radius: 50, 22 | ), 23 | const Padding(padding: EdgeInsets.only(left: 15)), 24 | Expanded( 25 | child: Text( 26 | context.tr("notLoggedIn"), 27 | style: Theme.of(context).textTheme.titleLarge, 28 | textAlign: TextAlign.center, 29 | ), 30 | ), 31 | ], 32 | ), 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/homeComponent/view/widget/preference_selection_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/context.dart'; 2 | import 'package:campus_flutter/base/util/padded_divider.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class PreferenceSelectionView extends StatelessWidget { 6 | const PreferenceSelectionView({ 7 | super.key, 8 | required this.data, 9 | required this.entry, 10 | }); 11 | 12 | final List data; 13 | final String entry; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return SingleChildScrollView( 18 | child: Padding( 19 | padding: EdgeInsets.only(bottom: context.padding * 2), 20 | child: Card( 21 | child: ListView.separated( 22 | physics: const NeverScrollableScrollPhysics(), 23 | shrinkWrap: true, 24 | padding: EdgeInsets.zero, 25 | itemBuilder: (context, index) => data[index], 26 | separatorBuilder: 27 | (context, index) => const PaddedDivider(height: 0), 28 | itemCount: data.length, 29 | ), 30 | ), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_navigation_additional_properties.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/navigaTumComponent/model/navigatum_navigation_property.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'navigatum_navigation_additional_properties.g.dart'; 5 | 6 | @JsonSerializable() 7 | class NavigaTumNavigationAdditionalProperties { 8 | @JsonKey(name: "computed") 9 | final List properties; 10 | 11 | NavigaTumNavigationAdditionalProperties(this.properties); 12 | 13 | factory NavigaTumNavigationAdditionalProperties.fromJson( 14 | Map json, 15 | ) => _$NavigaTumNavigationAdditionalPropertiesFromJson(json); 16 | 17 | Map toJson() => 18 | _$NavigaTumNavigationAdditionalPropertiesToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_navigation_additional_properties.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_navigation_additional_properties.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumNavigationAdditionalProperties 10 | _$NavigaTumNavigationAdditionalPropertiesFromJson(Map json) => 11 | NavigaTumNavigationAdditionalProperties( 12 | (json['computed'] as List) 13 | .map( 14 | (e) => 15 | NavigaTumNavigationProperty.fromJson(e as Map), 16 | ) 17 | .toList(), 18 | ); 19 | 20 | Map _$NavigaTumNavigationAdditionalPropertiesToJson( 21 | NavigaTumNavigationAdditionalProperties instance, 22 | ) => {'computed': instance.properties}; 23 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_navigation_coordinates.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'navigatum_navigation_coordinates.g.dart'; 4 | 5 | @JsonSerializable() 6 | class NavigaTumNavigationCoordinates { 7 | @JsonKey(name: "lat") 8 | final double? latitude; 9 | @JsonKey(name: "lon") 10 | final double? longitude; 11 | 12 | NavigaTumNavigationCoordinates(this.latitude, this.longitude); 13 | 14 | factory NavigaTumNavigationCoordinates.fromJson(Map json) => 15 | _$NavigaTumNavigationCoordinatesFromJson(json); 16 | 17 | Map toJson() => _$NavigaTumNavigationCoordinatesToJson(this); 18 | } 19 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_navigation_coordinates.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_navigation_coordinates.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumNavigationCoordinates _$NavigaTumNavigationCoordinatesFromJson( 10 | Map json, 11 | ) => NavigaTumNavigationCoordinates( 12 | (json['lat'] as num?)?.toDouble(), 13 | (json['lon'] as num?)?.toDouble(), 14 | ); 15 | 16 | Map _$NavigaTumNavigationCoordinatesToJson( 17 | NavigaTumNavigationCoordinates instance, 18 | ) => {'lat': instance.latitude, 'lon': instance.longitude}; 19 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_navigation_maps.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/navigaTumComponent/model/details/navigatum_overlays_maps.dart'; 2 | import 'package:campus_flutter/navigaTumComponent/model/details/navigatum_roomfinder_maps.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'navigatum_navigation_maps.g.dart'; 6 | 7 | @JsonSerializable() 8 | class NavigaTumNavigationMaps { 9 | @JsonKey(name: "default") 10 | final String defaultMapId; 11 | final NavigaTumRoomFinderMaps? roomfinder; 12 | final NavigaTumOverlayMaps? overlays; 13 | 14 | NavigaTumNavigationMaps(this.defaultMapId, this.roomfinder, this.overlays); 15 | 16 | factory NavigaTumNavigationMaps.fromJson(Map json) => 17 | _$NavigaTumNavigationMapsFromJson(json); 18 | 19 | Map toJson() => _$NavigaTumNavigationMapsToJson(this); 20 | } 21 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_navigation_maps.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_navigation_maps.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumNavigationMaps _$NavigaTumNavigationMapsFromJson( 10 | Map json, 11 | ) => NavigaTumNavigationMaps( 12 | json['default'] as String, 13 | json['roomfinder'] == null 14 | ? null 15 | : NavigaTumRoomFinderMaps.fromJson( 16 | json['roomfinder'] as Map, 17 | ), 18 | json['overlays'] == null 19 | ? null 20 | : NavigaTumOverlayMaps.fromJson(json['overlays'] as Map), 21 | ); 22 | 23 | Map _$NavigaTumNavigationMapsToJson( 24 | NavigaTumNavigationMaps instance, 25 | ) => { 26 | 'default': instance.defaultMapId, 27 | 'roomfinder': instance.roomfinder, 28 | 'overlays': instance.overlays, 29 | }; 30 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_overlays_maps.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/navigaTumComponent/model/navigatum_overlay_map.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'navigatum_overlays_maps.g.dart'; 5 | 6 | @JsonSerializable() 7 | class NavigaTumOverlayMaps { 8 | final List available; 9 | 10 | NavigaTumOverlayMaps(this.available); 11 | 12 | factory NavigaTumOverlayMaps.fromJson(Map json) => 13 | _$NavigaTumOverlayMapsFromJson(json); 14 | 15 | Map toJson() => _$NavigaTumOverlayMapsToJson(this); 16 | } 17 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_overlays_maps.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_overlays_maps.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumOverlayMaps _$NavigaTumOverlayMapsFromJson( 10 | Map json, 11 | ) => NavigaTumOverlayMaps( 12 | (json['available'] as List) 13 | .map((e) => NavigaTumOverlayMap.fromJson(e as Map)) 14 | .toList(), 15 | ); 16 | 17 | Map _$NavigaTumOverlayMapsToJson( 18 | NavigaTumOverlayMaps instance, 19 | ) => {'available': instance.available}; 20 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_roomfinder_maps.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/navigaTumComponent/model/navigatum_roomfinder_map.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'navigatum_roomfinder_maps.g.dart'; 5 | 6 | @JsonSerializable() 7 | class NavigaTumRoomFinderMaps { 8 | final List available; 9 | @JsonKey(name: "default") 10 | final String defaultMapId; 11 | 12 | NavigaTumRoomFinderMaps(this.available, this.defaultMapId); 13 | 14 | factory NavigaTumRoomFinderMaps.fromJson(Map json) => 15 | _$NavigaTumRoomFinderMapsFromJson(json); 16 | 17 | Map toJson() => _$NavigaTumRoomFinderMapsToJson(this); 18 | } 19 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/details/navigatum_roomfinder_maps.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_roomfinder_maps.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumRoomFinderMaps _$NavigaTumRoomFinderMapsFromJson( 10 | Map json, 11 | ) => NavigaTumRoomFinderMaps( 12 | (json['available'] as List) 13 | .map((e) => NavigaTumRoomFinderMap.fromJson(e as Map)) 14 | .toList(), 15 | json['default'] as String, 16 | ); 17 | 18 | Map _$NavigaTumRoomFinderMapsToJson( 19 | NavigaTumRoomFinderMaps instance, 20 | ) => { 21 | 'available': instance.available, 22 | 'default': instance.defaultMapId, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/navigatum_navigation_entity.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_navigation_entity.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumNavigationEntity _$NavigaTumNavigationEntityFromJson( 10 | Map json, 11 | ) => NavigaTumNavigationEntity( 12 | id: json['id'] as String, 13 | type: json['type'] as String, 14 | name: json['name'] as String, 15 | subtext: json['subtext'] as String, 16 | parsedId: json['parsed_id'] as String?, 17 | ); 18 | 19 | Map _$NavigaTumNavigationEntityToJson( 20 | NavigaTumNavigationEntity instance, 21 | ) => { 22 | 'id': instance.id, 23 | 'type': instance.type, 24 | 'name': instance.name, 25 | 'subtext': instance.subtext, 26 | 'parsed_id': instance.parsedId, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/navigatum_navigation_property.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'navigatum_navigation_property.g.dart'; 4 | 5 | @JsonSerializable() 6 | class NavigaTumNavigationProperty { 7 | final String name; 8 | final String text; 9 | 10 | NavigaTumNavigationProperty({required this.name, required this.text}); 11 | 12 | factory NavigaTumNavigationProperty.fromJson(Map json) => 13 | _$NavigaTumNavigationPropertyFromJson(json); 14 | 15 | Map toJson() => _$NavigaTumNavigationPropertyToJson(this); 16 | } 17 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/navigatum_navigation_property.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_navigation_property.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumNavigationProperty _$NavigaTumNavigationPropertyFromJson( 10 | Map json, 11 | ) => NavigaTumNavigationProperty( 12 | name: json['name'] as String, 13 | text: json['text'] as String, 14 | ); 15 | 16 | Map _$NavigaTumNavigationPropertyToJson( 17 | NavigaTumNavigationProperty instance, 18 | ) => {'name': instance.name, 'text': instance.text}; 19 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/navigatum_overlay_map.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'navigatum_overlay_map.g.dart'; 4 | 5 | @JsonSerializable() 6 | class NavigaTumOverlayMap { 7 | final int id; 8 | final String floor; 9 | @JsonKey(name: "file") 10 | final String imageUrl; 11 | final String name; 12 | 13 | NavigaTumOverlayMap(this.id, this.floor, this.imageUrl, this.name); 14 | 15 | factory NavigaTumOverlayMap.fromJson(Map json) => 16 | _$NavigaTumOverlayMapFromJson(json); 17 | 18 | Map toJson() => _$NavigaTumOverlayMapToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/navigatum_overlay_map.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_overlay_map.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumOverlayMap _$NavigaTumOverlayMapFromJson(Map json) => 10 | NavigaTumOverlayMap( 11 | (json['id'] as num).toInt(), 12 | json['floor'] as String, 13 | json['file'] as String, 14 | json['name'] as String, 15 | ); 16 | 17 | Map _$NavigaTumOverlayMapToJson( 18 | NavigaTumOverlayMap instance, 19 | ) => { 20 | 'id': instance.id, 21 | 'floor': instance.floor, 22 | 'file': instance.imageUrl, 23 | 'name': instance.name, 24 | }; 25 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/navigatum_roomfinder_map.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'navigatum_roomfinder_map.g.dart'; 4 | 5 | @JsonSerializable() 6 | class NavigaTumRoomFinderMap { 7 | final String id; 8 | final String name; 9 | @JsonKey(name: "file") 10 | final String imageUrl; 11 | final int height; 12 | final int width; 13 | final int x; 14 | final int y; 15 | final String scale; 16 | 17 | NavigaTumRoomFinderMap({ 18 | required this.id, 19 | required this.name, 20 | required this.imageUrl, 21 | required this.height, 22 | required this.width, 23 | required this.x, 24 | required this.y, 25 | required this.scale, 26 | }); 27 | 28 | factory NavigaTumRoomFinderMap.fromJson(Map json) => 29 | _$NavigaTumRoomFinderMapFromJson(json); 30 | 31 | Map toJson() => _$NavigaTumRoomFinderMapToJson(this); 32 | } 33 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/navigatum_roomfinder_map.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_roomfinder_map.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumRoomFinderMap _$NavigaTumRoomFinderMapFromJson( 10 | Map json, 11 | ) => NavigaTumRoomFinderMap( 12 | id: json['id'] as String, 13 | name: json['name'] as String, 14 | imageUrl: json['file'] as String, 15 | height: (json['height'] as num).toInt(), 16 | width: (json['width'] as num).toInt(), 17 | x: (json['x'] as num).toInt(), 18 | y: (json['y'] as num).toInt(), 19 | scale: json['scale'] as String, 20 | ); 21 | 22 | Map _$NavigaTumRoomFinderMapToJson( 23 | NavigaTumRoomFinderMap instance, 24 | ) => { 25 | 'id': instance.id, 26 | 'name': instance.name, 27 | 'file': instance.imageUrl, 28 | 'height': instance.height, 29 | 'width': instance.width, 30 | 'x': instance.x, 31 | 'y': instance.y, 32 | 'scale': instance.scale, 33 | }; 34 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/search/navigatum_search_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/navigaTumComponent/model/search/navigatum_search_response_section.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'navigatum_search_response.g.dart'; 5 | 6 | @JsonSerializable() 7 | class NavigaTumSearchResponse { 8 | final List sections; 9 | 10 | NavigaTumSearchResponse(this.sections); 11 | 12 | factory NavigaTumSearchResponse.fromJson(Map json) => 13 | _$NavigaTumSearchResponseFromJson(json); 14 | 15 | Map toJson() => _$NavigaTumSearchResponseToJson(this); 16 | } 17 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/search/navigatum_search_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_search_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumSearchResponse _$NavigaTumSearchResponseFromJson( 10 | Map json, 11 | ) => NavigaTumSearchResponse( 12 | (json['sections'] as List) 13 | .map( 14 | (e) => 15 | NavigaTumSearchResponseSection.fromJson(e as Map), 16 | ) 17 | .toList(), 18 | ); 19 | 20 | Map _$NavigaTumSearchResponseToJson( 21 | NavigaTumSearchResponse instance, 22 | ) => {'sections': instance.sections}; 23 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/search/navigatum_search_response_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/navigaTumComponent/model/navigatum_navigation_entity.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'navigatum_search_response_section.g.dart'; 5 | 6 | @JsonSerializable() 7 | class NavigaTumSearchResponseSection { 8 | @JsonKey(name: "facet") 9 | final String type; 10 | final List entries; 11 | 12 | NavigaTumSearchResponseSection(this.type, this.entries); 13 | 14 | factory NavigaTumSearchResponseSection.fromJson(Map json) => 15 | _$NavigaTumSearchResponseSectionFromJson(json); 16 | 17 | Map toJson() => _$NavigaTumSearchResponseSectionToJson(this); 18 | } 19 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/model/search/navigatum_search_response_section.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'navigatum_search_response_section.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | NavigaTumSearchResponseSection _$NavigaTumSearchResponseSectionFromJson( 10 | Map json, 11 | ) => NavigaTumSearchResponseSection( 12 | json['facet'] as String, 13 | (json['entries'] as List) 14 | .map((e) => NavigaTumNavigationEntity.fromJson(e as Map)) 15 | .toList(), 16 | ); 17 | 18 | Map _$NavigaTumSearchResponseSectionToJson( 19 | NavigaTumSearchResponseSection instance, 20 | ) => {'facet': instance.type, 'entries': instance.entries}; 21 | -------------------------------------------------------------------------------- /lib/navigaTumComponent/services/navigatum_search_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/navigaTumApi/navigatum_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/navigaTumApi/navigatum_api_endpoint.dart'; 3 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 4 | import 'package:campus_flutter/navigaTumComponent/model/search/navigatum_search_response.dart'; 5 | import 'package:campus_flutter/main.dart'; 6 | 7 | class NavigaTumSearchService { 8 | static Future<(DateTime?, NavigaTumSearchResponse)> fetchNavigaTumEntities( 9 | String query, 10 | bool forcedRefresh, 11 | ) async { 12 | RestClient restClient = getIt(); 13 | final response = await restClient 14 | .get( 15 | NavigaTumApi( 16 | navigaTumApiEndpoint: NavigaTumApiEndpointSearch(query: query), 17 | ), 18 | NavigaTumSearchResponse.fromJson, 19 | forcedRefresh, 20 | ); 21 | 22 | return (response.saved, response.data); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/onboardingComponent/model/confirm.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'confirm.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Confirm { 7 | @JsonKey(fromJson: bool.parse) 8 | final bool confirmed; 9 | 10 | Confirm({required this.confirmed}); 11 | 12 | factory Confirm.fromJson(Map json) => 13 | _$ConfirmFromJson(json); 14 | 15 | Map toJson() => _$ConfirmToJson(this); 16 | } 17 | -------------------------------------------------------------------------------- /lib/onboardingComponent/model/confirm.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'confirm.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Confirm _$ConfirmFromJson(Map json) => 10 | Confirm(confirmed: bool.parse(json['confirmed'] as String)); 11 | 12 | Map _$ConfirmToJson(Confirm instance) => { 13 | 'confirmed': instance.confirmed, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/onboardingComponent/model/token.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'token.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Token { 7 | @JsonKey(name: "token") 8 | final String content; 9 | 10 | Token({required this.content}); 11 | 12 | factory Token.fromJson(Map json) => _$TokenFromJson(json); 13 | 14 | Map toJson() => _$TokenToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/onboardingComponent/model/token.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'token.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Token _$TokenFromJson(Map json) => 10 | Token(content: json['token'] as String); 11 | 12 | Map _$TokenToJson(Token instance) => { 13 | 'token': instance.content, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/onboardingComponent/views/location_permissions_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/onboardingComponent/viewModels/onboarding_viewmodel.dart'; 2 | import 'package:campus_flutter/onboardingComponent/views/permission_view.dart'; 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 6 | 7 | class LocationPermissionView extends ConsumerWidget { 8 | const LocationPermissionView({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context, WidgetRef ref) { 12 | return PermissionView( 13 | imagePath: "assets/images/location.png", 14 | title: context.tr("location"), 15 | description: context.tr("locationOnboarding"), 16 | onButtonPress: 17 | () => ref.read(onboardingViewModel).requestLocation(ref, context), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/personComponent/model/personDetails/contact_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'contact_info.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ContactInfo { 7 | @JsonKey(name: "telefon") 8 | final String? phone; 9 | @JsonKey(name: "fax") 10 | final String? fax; 11 | @JsonKey(name: "mobiltelefon") 12 | final String? mobilePhone; 13 | @JsonKey(name: "zusatz_info") 14 | final String? additionalInfo; 15 | @JsonKey(name: "www_homepage") 16 | final String? homepage; 17 | 18 | ContactInfo({ 19 | this.phone, 20 | this.fax, 21 | this.mobilePhone, 22 | this.additionalInfo, 23 | this.homepage, 24 | }); 25 | 26 | factory ContactInfo.fromJson(Map json) => 27 | _$ContactInfoFromJson(json); 28 | 29 | Map toJson() => _$ContactInfoToJson(this); 30 | } 31 | -------------------------------------------------------------------------------- /lib/personComponent/model/personDetails/contact_info.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'contact_info.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ContactInfo _$ContactInfoFromJson(Map json) => ContactInfo( 10 | phone: json['telefon'] as String?, 11 | fax: json['fax'] as String?, 12 | mobilePhone: json['mobiltelefon'] as String?, 13 | additionalInfo: json['zusatz_info'] as String?, 14 | homepage: json['www_homepage'] as String?, 15 | ); 16 | 17 | Map _$ContactInfoToJson(ContactInfo instance) => 18 | { 19 | 'telefon': instance.phone, 20 | 'fax': instance.fax, 21 | 'mobiltelefon': instance.mobilePhone, 22 | 'zusatz_info': instance.additionalInfo, 23 | 'www_homepage': instance.homepage, 24 | }; 25 | -------------------------------------------------------------------------------- /lib/personComponent/model/personDetails/organisation.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'organisation.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Organisation { 7 | @JsonKey(name: "org") 8 | final String? name; 9 | @JsonKey(name: "kennung") 10 | final String? id; 11 | @JsonKey(name: "org_nr") 12 | final String? number; 13 | @JsonKey(name: "titel") 14 | final String? title; 15 | @JsonKey(name: "beschreibung") 16 | final String? description; 17 | 18 | Organisation({this.name, this.id, this.number, this.title, this.description}); 19 | 20 | factory Organisation.fromJson(Map json) => 21 | _$OrganisationFromJson(json); 22 | 23 | Map toJson() => _$OrganisationToJson(this); 24 | } 25 | -------------------------------------------------------------------------------- /lib/personComponent/model/personDetails/organisation.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'organisation.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Organisation _$OrganisationFromJson(Map json) => Organisation( 10 | name: json['org'] as String?, 11 | id: json['kennung'] as String?, 12 | number: json['org_nr'] as String?, 13 | title: json['titel'] as String?, 14 | description: json['beschreibung'] as String?, 15 | ); 16 | 17 | Map _$OrganisationToJson(Organisation instance) => 18 | { 19 | 'org': instance.name, 20 | 'kennung': instance.id, 21 | 'org_nr': instance.number, 22 | 'titel': instance.title, 23 | 'beschreibung': instance.description, 24 | }; 25 | -------------------------------------------------------------------------------- /lib/personComponent/model/personDetails/phone_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'phone_extension.g.dart'; 4 | 5 | @JsonSerializable() 6 | class PhoneExtension { 7 | @JsonKey(name: "telefonnummer") 8 | final String? phoneNumber; 9 | @JsonKey(name: "tum_anlage_land") 10 | final String? countryCode; 11 | @JsonKey(name: "tum_anlage_ortsvorwahl") 12 | final String? areaCode; 13 | @JsonKey(name: "tum_anlage_nummer") 14 | final String? equipmentNumber; 15 | @JsonKey(name: "tum_nebenstelle") 16 | final String? branchNumber; 17 | 18 | PhoneExtension({ 19 | this.phoneNumber, 20 | this.countryCode, 21 | this.areaCode, 22 | this.equipmentNumber, 23 | this.branchNumber, 24 | }); 25 | 26 | factory PhoneExtension.fromJson(Map json) => 27 | _$PhoneExtensionFromJson(json); 28 | 29 | Map toJson() => _$PhoneExtensionToJson(this); 30 | } 31 | -------------------------------------------------------------------------------- /lib/personComponent/model/personDetails/phone_extension.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'phone_extension.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | PhoneExtension _$PhoneExtensionFromJson(Map json) => 10 | PhoneExtension( 11 | phoneNumber: json['telefonnummer'] as String?, 12 | countryCode: json['tum_anlage_land'] as String?, 13 | areaCode: json['tum_anlage_ortsvorwahl'] as String?, 14 | equipmentNumber: json['tum_anlage_nummer'] as String?, 15 | branchNumber: json['tum_nebenstelle'] as String?, 16 | ); 17 | 18 | Map _$PhoneExtensionToJson(PhoneExtension instance) => 19 | { 20 | 'telefonnummer': instance.phoneNumber, 21 | 'tum_anlage_land': instance.countryCode, 22 | 'tum_anlage_ortsvorwahl': instance.areaCode, 23 | 'tum_anlage_nummer': instance.equipmentNumber, 24 | 'tum_nebenstelle': instance.branchNumber, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/personComponent/model/personDetails/room.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'room.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Room { 7 | @JsonKey(name: "nummer") 8 | final String? number; 9 | @JsonKey(name: "gebaeudename") 10 | final String? buildingName; 11 | @JsonKey(name: "gebaeudenummer") 12 | final String? buildingNumber; 13 | @JsonKey(name: "stockwerkname") 14 | final String? floorName; 15 | @JsonKey(name: "stockwerknummer") 16 | final String? floorNumber; 17 | @JsonKey(name: "architekt") 18 | final String? id; 19 | @JsonKey(name: "ortsbeschreibung") 20 | final String? locationDescription; 21 | @JsonKey(name: "kurz") 22 | final String? shortLocationDescription; 23 | @JsonKey(name: "lang") 24 | final String? longLocationDescription; 25 | 26 | Room({ 27 | this.number, 28 | this.buildingName, 29 | this.buildingNumber, 30 | this.floorName, 31 | this.floorNumber, 32 | this.id, 33 | this.locationDescription, 34 | this.shortLocationDescription, 35 | this.longLocationDescription, 36 | }); 37 | 38 | factory Room.fromJson(Map json) => _$RoomFromJson(json); 39 | 40 | Map toJson() => _$RoomToJson(this); 41 | } 42 | -------------------------------------------------------------------------------- /lib/personComponent/model/personSearch/person.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'person.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Person _$PersonFromJson(Map json) => Person( 10 | firstname: json['vorname'] as String, 11 | surname: json['familienname'] as String, 12 | title: json['titel'] as String?, 13 | nr: json['nr'] as String, 14 | obfuscatedID: json['obfuscated_id'] as String, 15 | ); 16 | 17 | Map _$PersonToJson(Person instance) => { 18 | 'vorname': instance.firstname, 19 | 'familienname': instance.surname, 20 | 'titel': instance.title, 21 | 'nr': instance.nr, 22 | 'obfuscated_id': instance.obfuscatedID, 23 | }; 24 | 25 | Persons _$PersonsFromJson(Map json) => Persons( 26 | persons: 27 | (json['row'] as List?) 28 | ?.map((e) => Person.fromJson(e as Map)) 29 | .toList() ?? 30 | [], 31 | ); 32 | 33 | Map _$PersonsToJson(Persons instance) => { 34 | 'row': instance.persons, 35 | }; 36 | -------------------------------------------------------------------------------- /lib/personComponent/model/profile/tuition.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'tuition.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Tuition _$TuitionFromJson(Map json) => Tuition( 10 | amount: StringParser.stringToDouble(json['soll'] as String?), 11 | deadline: DateTime.parse(json['frist'] as String), 12 | semester: json['semester_bezeichnung'] as String, 13 | semesterID: json['semester_id'] as String, 14 | ); 15 | 16 | Map _$TuitionToJson(Tuition instance) => { 17 | 'soll': instance.amount, 18 | 'frist': instance.deadline.toIso8601String(), 19 | 'semester_bezeichnung': instance.semester, 20 | 'semester_id': instance.semesterID, 21 | }; 22 | 23 | Tuitions _$TuitionsFromJson(Map json) => 24 | Tuitions(tuition: Tuitions._tuitionFromJson(json['row'])); 25 | 26 | Map _$TuitionsToJson(Tuitions instance) => { 27 | 'row': instance.tuition, 28 | }; 29 | -------------------------------------------------------------------------------- /lib/personComponent/services/person_details_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_exception.dart'; 3 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_endpoint.dart'; 4 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 5 | import 'package:campus_flutter/main.dart'; 6 | import 'package:campus_flutter/personComponent/model/personDetails/person_details.dart'; 7 | 8 | class PersonDetailsService { 9 | static Future<(DateTime?, PersonDetails)> fetchPersonDetails( 10 | bool forcedRefresh, 11 | String identNumber, 12 | ) async { 13 | RestClient restClient = getIt(); 14 | final response = await restClient.getWithException< 15 | PersonDetailsData, 16 | TumOnlineApi, 17 | TumOnlineApiException 18 | >( 19 | TumOnlineApi(TumOnlineEndpointPersonDetails(identNumber: identNumber)), 20 | PersonDetailsData.fromJson, 21 | TumOnlineApiException.fromJson, 22 | forcedRefresh, 23 | ); 24 | return (response.saved, response.data.person); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/personComponent/services/person_search_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_exception.dart'; 3 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_endpoint.dart'; 4 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 5 | import 'package:campus_flutter/personComponent/model/personSearch/person.dart'; 6 | import 'package:campus_flutter/main.dart'; 7 | 8 | class PersonSearchService { 9 | static Future<(DateTime?, List)> fetchPersons( 10 | String query, 11 | bool forcedRefresh, 12 | ) async { 13 | RestClient restClient = getIt(); 14 | final response = await restClient 15 | .getWithException( 16 | TumOnlineApi(TumOnlineEndpointPersonSearch(search: query)), 17 | Persons.fromJson, 18 | TumOnlineApiException.fromJson, 19 | forcedRefresh, 20 | ); 21 | 22 | return (response.saved, response.data.persons); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/personComponent/viewModel/profile_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/personComponent/model/profile/profile.dart'; 2 | import 'package:campus_flutter/personComponent/model/profile/tuition.dart'; 3 | import 'package:campus_flutter/personComponent/services/profile_service.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | import 'package:rxdart/rxdart.dart'; 6 | 7 | final profileViewModel = Provider((ref) => ProfileViewModel()); 8 | 9 | class ProfileViewModel { 10 | BehaviorSubject profile = BehaviorSubject.seeded(null); 11 | BehaviorSubject tuition = BehaviorSubject.seeded(null); 12 | final BehaviorSubject lastFetched = BehaviorSubject.seeded(null); 13 | 14 | Future fetch(bool forcedRefresh) async { 15 | ProfileService.fetchProfile(forcedRefresh).then((response) { 16 | lastFetched.add(response.$1); 17 | profile.add(response.$2); 18 | ProfileService.fetchTuition( 19 | forcedRefresh, 20 | response.$2.personGroup ?? "", 21 | response.$2.id ?? "", 22 | ).then( 23 | (response) => tuition.add(response.$2), 24 | onError: (error) => tuition.addError(error), 25 | ); 26 | }, onError: (error) => profile.addError(error)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/placesComponent/model/cafeterias/cafeteria_menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/placesComponent/model/cafeterias/mensa_menu.dart'; 2 | 3 | /// local class 4 | class CafeteriaMenu { 5 | final DateTime date; 6 | final List categories; 7 | 8 | CafeteriaMenu({required this.date, required this.categories}); 9 | } 10 | -------------------------------------------------------------------------------- /lib/placesComponent/model/cafeterias/dish.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'dish.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Dish { 7 | final String name; 8 | final Map prices; 9 | final List labels; 10 | @JsonKey(name: "dish_type") 11 | final String dishType; 12 | 13 | Dish({ 14 | required this.name, 15 | required this.prices, 16 | required this.labels, 17 | required this.dishType, 18 | }); 19 | 20 | factory Dish.fromJson(Map json) => _$DishFromJson(json); 21 | 22 | Map toJson() => _$DishToJson(this); 23 | } 24 | 25 | @JsonSerializable() 26 | class Price { 27 | @JsonKey(name: "base_price") 28 | final double? basePrice; 29 | @JsonKey(name: "price_per_unit") 30 | final double? unitPrice; 31 | final String? unit; 32 | 33 | Price({this.basePrice, this.unitPrice, this.unit}); 34 | 35 | factory Price.fromJson(Map json) => _$PriceFromJson(json); 36 | 37 | Map toJson() => _$PriceToJson(this); 38 | } 39 | -------------------------------------------------------------------------------- /lib/placesComponent/model/cafeterias/meal_plan.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/placesComponent/model/cafeterias/mensa_menu.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'meal_plan.g.dart'; 5 | 6 | @JsonSerializable() 7 | class MealPlan { 8 | @JsonKey(name: "number") 9 | final int week; 10 | final int year; 11 | final List days; 12 | 13 | MealPlan({required this.week, required this.year, required this.days}); 14 | 15 | factory MealPlan.fromJson(Map json) => 16 | _$MealPlanFromJson(json); 17 | 18 | Map toJson() => _$MealPlanToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/placesComponent/model/cafeterias/meal_plan.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'meal_plan.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | MealPlan _$MealPlanFromJson(Map json) => MealPlan( 10 | week: (json['number'] as num).toInt(), 11 | year: (json['year'] as num).toInt(), 12 | days: 13 | (json['days'] as List) 14 | .map((e) => MensaMenu.fromJson(e as Map)) 15 | .toList(), 16 | ); 17 | 18 | Map _$MealPlanToJson(MealPlan instance) => { 19 | 'number': instance.week, 20 | 'year': instance.year, 21 | 'days': instance.days, 22 | }; 23 | -------------------------------------------------------------------------------- /lib/placesComponent/model/cafeterias/mensa_menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/placesComponent/model/cafeterias/dish.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'mensa_menu.g.dart'; 5 | 6 | @JsonSerializable() 7 | class MensaMenu { 8 | final DateTime date; 9 | final List dishes; 10 | 11 | MensaMenu({required this.date, required this.dishes}); 12 | 13 | factory MensaMenu.fromJson(Map json) => 14 | _$MensaMenuFromJson(json); 15 | 16 | Map toJson() => _$MensaMenuToJson(this); 17 | } 18 | 19 | @JsonSerializable() 20 | class MenuCategory { 21 | final String name; 22 | final List dishes; 23 | 24 | MenuCategory({required this.name, required this.dishes}); 25 | 26 | factory MenuCategory.fromJson(Map json) => 27 | _$MenuCategoryFromJson(json); 28 | 29 | Map toJson() => _$MenuCategoryToJson(this); 30 | } 31 | -------------------------------------------------------------------------------- /lib/placesComponent/model/cafeterias/mensa_menu.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'mensa_menu.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | MensaMenu _$MensaMenuFromJson(Map json) => MensaMenu( 10 | date: DateTime.parse(json['date'] as String), 11 | dishes: 12 | (json['dishes'] as List) 13 | .map((e) => Dish.fromJson(e as Map)) 14 | .toList(), 15 | ); 16 | 17 | Map _$MensaMenuToJson(MensaMenu instance) => { 18 | 'date': instance.date.toIso8601String(), 19 | 'dishes': instance.dishes, 20 | }; 21 | 22 | MenuCategory _$MenuCategoryFromJson(Map json) => MenuCategory( 23 | name: json['name'] as String, 24 | dishes: 25 | (json['dishes'] as List) 26 | .map((e) => Dish.fromJson(e as Map)) 27 | .toList(), 28 | ); 29 | 30 | Map _$MenuCategoryToJson(MenuCategory instance) => 31 | {'name': instance.name, 'dishes': instance.dishes}; 32 | -------------------------------------------------------------------------------- /lib/placesComponent/model/cafeterias/opening_hours.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'opening_hours.g.dart'; 4 | 5 | @JsonSerializable() 6 | class OpeningHours { 7 | final OpeningHour? mon; 8 | final OpeningHour? tue; 9 | final OpeningHour? wed; 10 | final OpeningHour? thu; 11 | final OpeningHour? fri; 12 | 13 | OpeningHours({this.mon, this.tue, this.wed, this.thu, this.fri}); 14 | 15 | factory OpeningHours.fromJson(Map json) => 16 | _$OpeningHoursFromJson(json); 17 | 18 | Map toJson() => _$OpeningHoursToJson(this); 19 | } 20 | 21 | @JsonSerializable() 22 | class OpeningHour { 23 | final String start; 24 | final String end; 25 | 26 | OpeningHour({required this.start, required this.end}); 27 | 28 | factory OpeningHour.fromJson(Map json) => 29 | _$OpeningHourFromJson(json); 30 | 31 | Map toJson() => _$OpeningHourToJson(this); 32 | } 33 | -------------------------------------------------------------------------------- /lib/placesComponent/model/studyRooms/study_room_attribute.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/searchComponent/model/comparison_token.dart'; 2 | import 'package:campus_flutter/searchComponent/protocols/searchable.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'study_room_attribute.g.dart'; 6 | 7 | @JsonSerializable() 8 | class StudyRoomAttribute extends Searchable { 9 | final String? detail; 10 | final String? name; 11 | 12 | @override 13 | @JsonKey(includeFromJson: false, includeToJson: false) 14 | List get comparisonTokens => [ 15 | ComparisonToken(value: detail ?? ""), 16 | ComparisonToken(value: name ?? ""), 17 | ]; 18 | 19 | StudyRoomAttribute({this.detail, this.name}); 20 | 21 | factory StudyRoomAttribute.fromJson(Map json) => 22 | _$StudyRoomAttributeFromJson(json); 23 | 24 | Map toJson() => _$StudyRoomAttributeToJson(this); 25 | } 26 | -------------------------------------------------------------------------------- /lib/placesComponent/model/studyRooms/study_room_attribute.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'study_room_attribute.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | StudyRoomAttribute _$StudyRoomAttributeFromJson(Map json) => 10 | StudyRoomAttribute( 11 | detail: json['detail'] as String?, 12 | name: json['name'] as String?, 13 | ); 14 | 15 | Map _$StudyRoomAttributeToJson(StudyRoomAttribute instance) => 16 | {'detail': instance.detail, 'name': instance.name}; 17 | -------------------------------------------------------------------------------- /lib/placesComponent/model/studyRooms/study_room_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/placesComponent/model/studyRooms/study_room.dart'; 2 | import 'package:campus_flutter/placesComponent/model/studyRooms/study_room_group.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'study_room_data.g.dart'; 6 | 7 | @JsonSerializable() 8 | class StudyRoomData { 9 | @JsonKey(name: "raeume") 10 | final List? rooms; 11 | @JsonKey(name: "gruppen") 12 | final List? groups; 13 | 14 | StudyRoomData({this.rooms, this.groups}); 15 | 16 | factory StudyRoomData.fromJson(Map json) => 17 | _$StudyRoomDataFromJson(json); 18 | 19 | Map toJson() => _$StudyRoomDataToJson(this); 20 | } 21 | -------------------------------------------------------------------------------- /lib/placesComponent/model/studyRooms/study_room_data.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'study_room_data.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | StudyRoomData _$StudyRoomDataFromJson(Map json) => 10 | StudyRoomData( 11 | rooms: 12 | (json['raeume'] as List?) 13 | ?.map((e) => StudyRoom.fromJson(e as Map)) 14 | .toList(), 15 | groups: 16 | (json['gruppen'] as List?) 17 | ?.map((e) => StudyRoomGroup.fromJson(e as Map)) 18 | .toList(), 19 | ); 20 | 21 | Map _$StudyRoomDataToJson(StudyRoomData instance) => 22 | {'raeume': instance.rooms, 'gruppen': instance.groups}; 23 | -------------------------------------------------------------------------------- /lib/placesComponent/model/studyRooms/study_room_group.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'study_room_group.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | StudyRoomGroup _$StudyRoomGroupFromJson( 10 | Map json, 11 | ) => StudyRoomGroup( 12 | detail: json['detail'] as String?, 13 | id: (json['nr'] as num).toInt(), 14 | name: json['name'] as String, 15 | sorting: (json['sortierung'] as num).toInt(), 16 | rooms: 17 | (json['raeume'] as List?) 18 | ?.map((e) => (e as num).toInt()) 19 | .toList(), 20 | openingHours: 21 | (readListValue(json, 'opening_hours') as List) 22 | .map((e) => StudyRoomOpeningHours.fromJson(e as Map)) 23 | .toList(), 24 | ); 25 | 26 | Map _$StudyRoomGroupToJson(StudyRoomGroup instance) => 27 | { 28 | 'detail': instance.detail, 29 | 'nr': instance.id, 30 | 'name': instance.name, 31 | 'sortierung': instance.sorting, 32 | 'raeume': instance.rooms, 33 | 'opening_hours': instance.openingHours, 34 | }; 35 | -------------------------------------------------------------------------------- /lib/placesComponent/model/studyRooms/study_room_opening_hours.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'study_room_opening_hours.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | StudyRoomOpeningHours _$StudyRoomOpeningHoursFromJson( 10 | Map json, 11 | ) => StudyRoomOpeningHours( 12 | daysString: json['days'] as String, 13 | daysBitMask: json['daysbitmask'] as String, 14 | start: json['start'] as String, 15 | end: json['end'] as String, 16 | ); 17 | 18 | Map _$StudyRoomOpeningHoursToJson( 19 | StudyRoomOpeningHours instance, 20 | ) => { 21 | 'days': instance.daysString, 22 | 'daysbitmask': instance.daysBitMask, 23 | 'start': instance.start, 24 | 'end': instance.end, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/placesComponent/services/cafeterias_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/eatApi/eat_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/eatApi/eat_api_endpoint.dart'; 3 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 4 | import 'package:campus_flutter/placesComponent/model/cafeterias/cafeteria.dart'; 5 | import 'package:campus_flutter/main.dart'; 6 | 7 | class CafeteriasService { 8 | static Future<(DateTime?, List)> fetchCafeterias( 9 | bool forcedRefresh, 10 | ) async { 11 | RestClient restClient = getIt(); 12 | final response = await restClient.get( 13 | EatApi(EatApiEndpointCanteens()), 14 | Cafeterias.fromJson, 15 | forcedRefresh, 16 | ); 17 | 18 | // TODO(Jakob): add fetching of queue status? 19 | 20 | return (response.saved, response.data.cafeterias); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/placesComponent/services/map_theme_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | 3 | class MapThemeService { 4 | late String darkTheme; 5 | late String lightTheme; 6 | 7 | MapThemeService() { 8 | _loadMapThemes(); 9 | } 10 | 11 | _loadMapThemes() async { 12 | darkTheme = await rootBundle.loadString( 13 | 'assets/mapStyles/darkMapTheme.json', 14 | ); 15 | lightTheme = await rootBundle.loadString( 16 | 'assets/mapStyles/lightMapTheme.json', 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/placesComponent/services/study_rooms_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/irisApi/iris_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/irisApi/iris_api_endpoint.dart'; 3 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 4 | import 'package:campus_flutter/placesComponent/model/studyRooms/study_room_data.dart'; 5 | import 'package:campus_flutter/main.dart'; 6 | 7 | class StudyRoomsService { 8 | static Future<(DateTime?, StudyRoomData)> fetchStudyRooms( 9 | bool forcedRefresh, 10 | ) async { 11 | RestClient restClient = getIt(); 12 | final response = await restClient.get( 13 | IrisApi(irisApiEndpoint: IrisApiEndpointRooms()), 14 | StudyRoomData.fromJson, 15 | forcedRefresh, 16 | ); 17 | 18 | return (response.saved, response.data); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/placesComponent/views/cafeterias/cafeteria_row_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/util/card_with_padding.dart'; 2 | import 'package:campus_flutter/base/routing/routes.dart' as routes; 3 | import 'package:campus_flutter/placesComponent/model/cafeterias/cafeteria.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 6 | import 'package:go_router/go_router.dart'; 7 | 8 | class CafeteriaCardView extends StatelessWidget { 9 | const CafeteriaCardView({super.key, required this.cafeteria}); 10 | 11 | final Cafeteria cafeteria; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return CardWithPadding( 16 | padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), 17 | child: CafeteriaRowView(cafeteria: cafeteria), 18 | ); 19 | } 20 | } 21 | 22 | class CafeteriaRowView extends ConsumerWidget { 23 | const CafeteriaRowView({super.key, required this.cafeteria}); 24 | 25 | final Cafeteria cafeteria; 26 | 27 | @override 28 | Widget build(BuildContext context, WidgetRef ref) { 29 | return ListTile( 30 | title: Text(cafeteria.name), 31 | trailing: const Icon(Icons.arrow_forward_ios, size: 15), 32 | onTap: () => context.push(routes.cafeteria, extra: cafeteria), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/placesComponent/views/cafeterias/dish_grid_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/context.dart'; 2 | import 'package:campus_flutter/placesComponent/model/cafeterias/dish.dart'; 3 | import 'package:campus_flutter/placesComponent/views/cafeterias/dish_card_view.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class DishGridView extends StatelessWidget { 7 | const DishGridView({ 8 | super.key, 9 | required this.dishes, 10 | this.isLandscape = false, 11 | this.inverted = false, 12 | }); 13 | 14 | final List<(Dish, String)> dishes; 15 | final bool isLandscape; 16 | final bool inverted; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return GridView.count( 21 | crossAxisCount: isLandscape ? 3 : 2, 22 | crossAxisSpacing: 10.0, 23 | padding: EdgeInsets.symmetric(horizontal: context.padding), 24 | children: 25 | dishes 26 | .map((dish) => DishCardView(dish: dish, inverted: inverted)) 27 | .toList(), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/placesComponent/views/cafeterias/dish_slider_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/util/horizontal_slider.dart'; 2 | import 'package:campus_flutter/placesComponent/model/cafeterias/dish.dart'; 3 | import 'package:campus_flutter/placesComponent/views/cafeterias/dish_card_view.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class DishSliderView extends StatelessWidget { 7 | const DishSliderView({ 8 | super.key, 9 | required this.dishes, 10 | this.inverted = false, 11 | }); 12 | 13 | final List<(Dish, String)> dishes; 14 | final bool inverted; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return HorizontalSlider<(Dish, String)>.height( 19 | data: dishes, 20 | height: 160, 21 | leadingTrailingPadding: !inverted, 22 | child: (dish) { 23 | return DishCardView(dish: dish, inverted: inverted); 24 | }, 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/searchComponent/model/comparison_token.dart: -------------------------------------------------------------------------------- 1 | class ComparisonToken { 2 | final String value; 3 | final ComparisonTokenType type; 4 | 5 | ComparisonToken({ 6 | required this.value, 7 | this.type = ComparisonTokenType.tokenized, 8 | }); 9 | 10 | static bool isEqual(ComparisonToken lhs, ComparisonToken rhs) { 11 | if (lhs.value.length != rhs.value.length) { 12 | return false; 13 | } 14 | 15 | for (int i in Iterable.generate(lhs.value.length)) { 16 | if (lhs.value.codeUnits[i] != rhs.value.codeUnits[i]) { 17 | return false; 18 | } 19 | } 20 | 21 | return true; 22 | } 23 | } 24 | 25 | enum ComparisonTokenType { tokenized, raw } 26 | -------------------------------------------------------------------------------- /lib/searchComponent/model/search_exception.dart: -------------------------------------------------------------------------------- 1 | class SearchException implements Exception { 2 | final String? searchQuery; 3 | 4 | SearchException.empty({required this.searchQuery}); 5 | 6 | SearchException.unexpected() : searchQuery = null; 7 | 8 | String get message { 9 | if (searchQuery != null) { 10 | return "No search results were found for: ${searchQuery!.isEmpty ? "Empty Search" : searchQuery}"; 11 | } else { 12 | return "An unexpected error occurred."; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/searchComponent/protocols/search_category_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/searchComponent/protocols/searchable.dart'; 2 | import 'package:rxdart/rxdart.dart'; 3 | 4 | abstract class SearchCategoryViewModel { 5 | BehaviorSubject?> searchResults = BehaviorSubject.seeded(null); 6 | 7 | Future search({bool forcedRefresh = false, required String query}); 8 | 9 | void clearSearch(); 10 | } 11 | -------------------------------------------------------------------------------- /lib/searchComponent/protocols/searchable.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/string_remove_diacritics.dart'; 2 | import 'package:campus_flutter/base/extensions/string_valid_chars.dart'; 3 | import 'package:campus_flutter/searchComponent/model/comparison_token.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | 6 | abstract class Searchable { 7 | @JsonKey(includeFromJson: false, includeToJson: false) 8 | late List comparisonTokens; 9 | 10 | List tokenize() { 11 | return comparisonTokens 12 | .map((comparisonToken) { 13 | if (comparisonToken.type == ComparisonTokenType.tokenized) { 14 | return comparisonToken.value 15 | .trim() 16 | .toLowerCase() 17 | .removeDiacritics() 18 | .keepValidChars() 19 | .split(" "); 20 | } else { 21 | return [comparisonToken.value]; 22 | } 23 | }) 24 | .expand((element) => element) 25 | .toList(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/searchComponent/viewModels/searchableViewModels/person_search_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/personComponent/model/personSearch/person.dart'; 2 | import 'package:campus_flutter/personComponent/services/person_search_service.dart'; 3 | import 'package:campus_flutter/searchComponent/protocols/search_category_viewmodel.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | import 'package:rxdart/rxdart.dart'; 6 | 7 | final personSearchViewModel = Provider((ref) => PersonSearchViewModel()); 8 | 9 | class PersonSearchViewModel implements SearchCategoryViewModel { 10 | @override 11 | BehaviorSubject?> searchResults = BehaviorSubject.seeded(null); 12 | 13 | @override 14 | Future search({bool forcedRefresh = false, required String query}) async { 15 | return PersonSearchService.fetchPersons(query, forcedRefresh).then((value) { 16 | searchResults.add(value.$2); 17 | }, onError: (error) => searchResults.addError(error)); 18 | } 19 | 20 | @override 21 | void clearSearch() { 22 | searchResults.add(null); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/searchComponent/views/resultViews/grade_search_result_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/searchComponent/viewModels/search_viewmodel.dart'; 2 | import 'package:campus_flutter/studiesComponent/model/grade.dart'; 3 | import 'package:campus_flutter/studiesComponent/view/grade/grade_view.dart'; 4 | import 'package:campus_flutter/base/enums/search_category.dart'; 5 | import 'package:campus_flutter/searchComponent/viewModels/searchableViewModels/grades_search_viewmodel.dart'; 6 | import 'package:campus_flutter/searchComponent/views/search_result_card_view.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 9 | 10 | class GradeSearchResultView extends ConsumerWidget { 11 | const GradeSearchResultView({super.key, required this.searchVM}); 12 | 13 | final Provider searchVM; 14 | 15 | @override 16 | Widget build(BuildContext context, WidgetRef ref) { 17 | return SearchResultCardView( 18 | searchCategory: SearchCategory.grade, 19 | searchVM: searchVM, 20 | searchCategoryVM: gradesSearchViewModel, 21 | body: (grade) => GradeRow(grade: grade), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/searchComponent/views/resultViews/lecture_search_result_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/searchComponent/viewModels/search_viewmodel.dart'; 2 | import 'package:campus_flutter/studiesComponent/model/lecture.dart'; 3 | import 'package:campus_flutter/studiesComponent/view/lecture/lecture_view.dart'; 4 | import 'package:campus_flutter/base/enums/search_category.dart'; 5 | import 'package:campus_flutter/searchComponent/viewModels/searchableViewModels/lecture_search_viewmodel.dart'; 6 | import 'package:campus_flutter/searchComponent/views/search_result_card_view.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 9 | 10 | class LectureSearchResultView extends ConsumerWidget { 11 | const LectureSearchResultView({super.key, required this.searchVM}); 12 | 13 | final Provider searchVM; 14 | 15 | @override 16 | Widget build(BuildContext context, WidgetRef ref) { 17 | return SearchResultCardView( 18 | searchCategory: SearchCategory.lectures, 19 | searchVM: searchVM, 20 | searchCategoryVM: lectureSearchViewModel, 21 | body: (lecture) => LectureView(lecture: lecture, isSearch: true), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/searchComponent/views/resultViews/personal_lecture_search_result_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/searchComponent/viewModels/search_viewmodel.dart'; 2 | import 'package:campus_flutter/studiesComponent/model/lecture.dart'; 3 | import 'package:campus_flutter/studiesComponent/view/lecture/lecture_view.dart'; 4 | import 'package:campus_flutter/base/enums/search_category.dart'; 5 | import 'package:campus_flutter/searchComponent/viewModels/searchableViewModels/personal_lecture_seach_viewmodel.dart'; 6 | import 'package:campus_flutter/searchComponent/views/search_result_card_view.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 9 | 10 | class PersonalLectureSearchResultView extends ConsumerWidget { 11 | const PersonalLectureSearchResultView({super.key, required this.searchVM}); 12 | 13 | final Provider searchVM; 14 | 15 | @override 16 | Widget build(BuildContext context, WidgetRef ref) { 17 | return SearchResultCardView( 18 | searchCategory: SearchCategory.personalLectures, 19 | searchVM: searchVM, 20 | searchCategoryVM: personalLectureSearchViewModel, 21 | body: (lecture) => LectureView(lecture: lecture, isSearch: true), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/searchComponent/views/resultViews/study_room_search_result_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/placesComponent/views/homeWidget/study_room_widget_view.dart'; 2 | import 'package:campus_flutter/base/enums/search_category.dart'; 3 | import 'package:campus_flutter/searchComponent/viewModels/search_viewmodel.dart'; 4 | import 'package:campus_flutter/searchComponent/viewModels/searchableViewModels/study_room_search_viewmodel.dart'; 5 | import 'package:campus_flutter/searchComponent/views/search_result_card_view.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 8 | 9 | class StudyRoomSearchResultView extends ConsumerWidget { 10 | const StudyRoomSearchResultView({super.key, required this.searchVM}); 11 | 12 | final Provider searchVM; 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | return SearchResultCardView< 17 | StudyRoomSearchViewModel, 18 | StudyRoomSearchResult 19 | >( 20 | searchCategory: SearchCategory.studyRoom, 21 | searchVM: searchVM, 22 | searchCategoryVM: studyRoomSearchViewModel, 23 | body: 24 | (studyRoomSearchResult) => 25 | StudyRoomWidgetView(studyRoomSearchResult.studyRoomGroup), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/settingsComponent/views/settings_scaffold.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/extensions/context.dart'; 2 | import 'package:campus_flutter/base/util/custom_back_button.dart'; 3 | import 'package:campus_flutter/base/routing/routes.dart'; 4 | import 'package:campus_flutter/settingsComponent/views/settings_view.dart'; 5 | import 'package:easy_localization/easy_localization.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:go_router/go_router.dart'; 8 | 9 | class SettingsScaffold extends StatelessWidget { 10 | const SettingsScaffold({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar( 16 | leading: const CustomBackButton(), 17 | titleSpacing: 0, 18 | title: Text(context.tr("settingsAndFeedback")), 19 | actions: [ 20 | IconButton( 21 | onPressed: () => context.push(feedback), 22 | icon: Icon(Icons.help, color: context.theme.primaryColor), 23 | ), 24 | ], 25 | ), 26 | body: const SettingsView(), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/studentCardComponent/services/student_card_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer'; 2 | 3 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api.dart'; 4 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_exception.dart'; 5 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_endpoint.dart'; 6 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 7 | import 'package:campus_flutter/main.dart'; 8 | import 'package:campus_flutter/studentCardComponent/model/student_card.dart'; 9 | 10 | class StudentCardService { 11 | static Future<(DateTime?, List)> fetchStudentCard( 12 | bool forcedRefresh, 13 | ) async { 14 | try { 15 | RestClient restClient = getIt(); 16 | final response = await restClient 17 | .getWithException( 18 | TumOnlineApi(TumOnlineEndpointTumCard()), 19 | StudentCards.fromJson, 20 | TumOnlineApiException.fromJson, 21 | forcedRefresh, 22 | ); 23 | 24 | return (response.saved, response.data.studentCards); 25 | } catch (e) { 26 | log(e.toString()); 27 | rethrow; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/studentCardComponent/viewModel/student_card_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/studentCardComponent/model/student_card.dart'; 2 | import 'package:campus_flutter/studentCardComponent/services/student_card_service.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | import 'package:rxdart/rxdart.dart'; 5 | 6 | final studentCardViewModel = Provider((ref) => StudentCardViewModel()); 7 | 8 | class StudentCardViewModel { 9 | BehaviorSubject?> studentCard = BehaviorSubject.seeded( 10 | null, 11 | ); 12 | BehaviorSubject lastFetched = BehaviorSubject.seeded(null); 13 | 14 | Future fetch(bool forcedRefresh) async { 15 | return StudentCardService.fetchStudentCard(forcedRefresh).then((response) { 16 | studentCard.add(response.$2); 17 | lastFetched.add(response.$1); 18 | }, onError: (error) => studentCard.addError(error)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/studentCardComponent/views/verfication_code_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:barcode_widget/barcode_widget.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class VerificationCodeView extends StatelessWidget { 5 | const VerificationCodeView({super.key}); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Card( 10 | child: ExpansionTile( 11 | title: const Text("Verification QR-Code"), 12 | childrenPadding: const EdgeInsets.all(10), 13 | children: [ 14 | BarcodeWidget( 15 | data: "https://www.tum.app", 16 | barcode: Barcode.qrCode(), 17 | drawText: false, 18 | height: 150, 19 | ), 20 | const Text("currently for demo reasons only"), 21 | ], 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/studiesComponent/model/average_grade.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/util/string_parser.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'average_grade.g.dart'; 5 | 6 | @JsonSerializable() 7 | class AverageGrade { 8 | @JsonKey(name: "studidf") 9 | final String id; 10 | @JsonKey(name: "studbez") 11 | final String studyDesignation; 12 | @JsonKey( 13 | name: "avg_grade_weighted_by_credits", 14 | fromJson: StringParser.stringToDouble, 15 | ) 16 | final double? averageGrade; 17 | 18 | AverageGrade({ 19 | required this.id, 20 | required this.studyDesignation, 21 | required this.averageGrade, 22 | }); 23 | 24 | factory AverageGrade.fromJson(Map json) => 25 | _$AverageGradeFromJson(json); 26 | 27 | Map toJson() => _$AverageGradeToJson(this); 28 | } 29 | 30 | @JsonSerializable() 31 | class AverageGrades { 32 | @JsonKey(name: "studium", defaultValue: []) 33 | final List averageGrades; 34 | 35 | AverageGrades({required this.averageGrades}); 36 | 37 | factory AverageGrades.fromJson(Map json) => 38 | _$AverageGradesFromJson(json); 39 | 40 | Map toJson() => _$AverageGradesToJson(this); 41 | } 42 | -------------------------------------------------------------------------------- /lib/studiesComponent/service/lecture_details_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_exception.dart'; 3 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_endpoint.dart'; 4 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 5 | import 'package:campus_flutter/main.dart'; 6 | import 'package:campus_flutter/studiesComponent/model/lecture_details.dart'; 7 | 8 | class LectureDetailsService { 9 | static Future<(DateTime?, LectureDetails)> fetchLectureDetails( 10 | String lvNumber, 11 | bool forcedRefresh, 12 | ) async { 13 | RestClient restClient = getIt(); 14 | final response = await restClient.getWithException< 15 | LectureDetailsElement, 16 | TumOnlineApi, 17 | TumOnlineApiException 18 | >( 19 | TumOnlineApi(TumOnlineEndpointLectureDetails(lvNr: lvNumber)), 20 | LectureDetailsElement.fromJson, 21 | TumOnlineApiException.fromJson, 22 | forcedRefresh, 23 | ); 24 | 25 | return (response.saved, response.data.lectureDetails); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/studiesComponent/service/lecture_search_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_exception.dart'; 3 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_endpoint.dart'; 4 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 5 | import 'package:campus_flutter/studiesComponent/model/lecture.dart'; 6 | import 'package:campus_flutter/main.dart'; 7 | 8 | class LectureSearchService { 9 | static Future<(DateTime?, List)> fetchLectureSearch( 10 | bool forcedRefresh, 11 | String query, 12 | ) async { 13 | final response = await getIt() 14 | .getWithException( 15 | TumOnlineApi(TumOnlineEndpointLectureSearch(search: query)), 16 | Lectures.fromJson, 17 | TumOnlineApiException.fromJson, 18 | forcedRefresh, 19 | ); 20 | 21 | return (response.saved, response.data.lectures); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/studiesComponent/service/lecture_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api.dart'; 2 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_exception.dart'; 3 | import 'package:campus_flutter/base/networking/apis/tumOnlineApi/tum_online_api_endpoint.dart'; 4 | import 'package:campus_flutter/base/networking/base/rest_client.dart'; 5 | import 'package:campus_flutter/studiesComponent/model/lecture.dart'; 6 | import 'package:campus_flutter/main.dart'; 7 | 8 | class LectureService { 9 | static Future<(DateTime?, List)> fetchLecture( 10 | bool forcedRefresh, 11 | ) async { 12 | RestClient restClient = getIt(); 13 | final response = await restClient 14 | .getWithException( 15 | TumOnlineApi(TumOnlineEndpointPersonalLectures()), 16 | Lectures.fromJson, 17 | TumOnlineApiException.fromJson, 18 | forcedRefresh, 19 | ); 20 | return (response.saved, response.data.lectures); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/studiesComponent/view/lectureDetail/basic_lecture_info_row_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BasicLectureInfoRowView extends StatelessWidget { 4 | const BasicLectureInfoRowView({ 5 | super.key, 6 | required this.information, 7 | required this.iconData, 8 | this.trailingWidget, 9 | }); 10 | 11 | final String information; 12 | final IconData iconData; 13 | final Widget? trailingWidget; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return ListTile( 18 | dense: true, 19 | leading: Icon(iconData, size: 20), 20 | title: Text(information), 21 | trailing: trailingWidget, 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/studiesComponent/view/lectureDetail/lecture_info_card_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:campus_flutter/base/util/icon_text.dart'; 2 | import 'package:campus_flutter/base/util/seperated_list.dart'; 3 | import 'package:campus_flutter/homeComponent/view/widget/widget_frame_view.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class LectureInfoCardView extends StatelessWidget { 7 | const LectureInfoCardView({ 8 | super.key, 9 | required this.icon, 10 | required this.title, 11 | required this.widgets, 12 | }); 13 | 14 | final IconData icon; 15 | final String title; 16 | final List widgets; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return WidgetFrameView( 21 | titleWidget: IconText( 22 | iconData: icon, 23 | label: title, 24 | style: Theme.of(context).textTheme.titleMedium, 25 | ), 26 | child: Card( 27 | child: SeparatedList.widgets( 28 | widgets: widgets, 29 | crossAxisAlignment: CrossAxisAlignment.start, 30 | ), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /protos/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /test/api_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | 3 | void main() { 4 | test('Counter value should be incremented', () { 5 | expect(1, 1); 6 | }); 7 | } --------------------------------------------------------------------------------