diff --git a/.github/workflows/deploy_beta.yml b/.github/workflows/deploy_beta.yml index 9564b507..9558cfea 100644 --- a/.github/workflows/deploy_beta.yml +++ b/.github/workflows/deploy_beta.yml @@ -24,9 +24,6 @@ jobs: uses: subosito/flutter-action@v2 with: channel: stable - cache: true - cache-key: 'flutter-:os:-:channel:-:version:-:arch:' - cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:arch:' - if: matrix.platform == 'android' uses: actions/setup-java@v3 diff --git a/.github/workflows/deploy_web.yml b/.github/workflows/deploy_web.yml index 41036568..7901fa4e 100644 --- a/.github/workflows/deploy_web.yml +++ b/.github/workflows/deploy_web.yml @@ -32,9 +32,6 @@ jobs: uses: subosito/flutter-action@v2 with: channel: stable - cache: true - cache-key: 'flutter-:os:-:channel:-:version:-:arch:' - cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:arch:' - name: Install Flutter Packages run: flutter pub get diff --git a/.github/workflows/lint_test_build.yml b/.github/workflows/lint_test_build.yml index c8a8d178..811251d4 100644 --- a/.github/workflows/lint_test_build.yml +++ b/.github/workflows/lint_test_build.yml @@ -20,9 +20,6 @@ jobs: uses: subosito/flutter-action@v2 with: channel: stable - cache: true - cache-key: 'flutter-:os:-:channel:-:version:-:arch:' - cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:arch:' - name: Install Flutter Packages run: flutter pub get diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 260cea6b..20f07b9b 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -1,2 +1,4 @@ -keep class org.joda.** {*;} -dontwarn org.joda.** +-keep class org.ocpsoft.prettytime.i18n.** +-keepnames class ** implements org.ocpsoft.prettytime.TimeUnit diff --git a/android/app/src/main/kotlin/de/tum/in/tumcampus/util/ColorExtension.kt b/android/app/src/main/kotlin/de/tum/in/tumcampus/util/ColorExtension.kt new file mode 100644 index 00000000..362de195 --- /dev/null +++ b/android/app/src/main/kotlin/de/tum/in/tumcampus/util/ColorExtension.kt @@ -0,0 +1,11 @@ +package de.tum.`in`.tumcampus.util + +import android.graphics.Color + +fun argbToColor(argb: Long): Int { + val alpha = ((argb shr 24) and 0xFF) / 255f + val red = ((argb shr 16) and 0xFF) / 255f + val green = ((argb shr 8) and 0xFF) / 255f + val blue = (argb and 0xFF) / 255f + return Color.argb(alpha, red, green, blue) +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/WidgetCalendarItem.kt b/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/WidgetCalendarItem.kt index 82149267..3aea69c2 100644 --- a/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/WidgetCalendarItem.kt +++ b/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/WidgetCalendarItem.kt @@ -5,26 +5,32 @@ import android.graphics.Color import androidx.core.content.ContextCompat import com.google.gson.annotations.SerializedName import de.tum.`in`.tumcampus.R +import de.tum.`in`.tumcampus.util.argbToColor import org.joda.time.DateTime data class WidgetCalendarItem( - @SerializedName("nr") - val id: String, - val title: String, - @SerializedName("dtstart") - val startDate: DateTime, - @SerializedName("dtend") - val endDate: DateTime, - val location: String, - val status: String, - var isFirstOnDay: Boolean = false + @SerializedName("nr") + val id: String, + val title: String, + @SerializedName("dtstart") + val startDate: DateTime, + @SerializedName("dtend") + val endDate: DateTime, + val location: String, + val status: String, + val color: Long?, + var isFirstOnDay: Boolean = false ) { fun getEventColor(context: Context): Int { - return when (type) { - CalendarEventType.CANCELED -> Color.parseColor("#F44336") - CalendarEventType.LECTURE -> Color.parseColor("#4CAF50") - CalendarEventType.EXERCISE -> Color.parseColor("#9800FF") - else -> ContextCompat.getColor(context, R.color.color_primary); + return if (color == null) { + when (type) { + CalendarEventType.CANCELED -> Color.parseColor("#F44336") + CalendarEventType.LECTURE -> Color.parseColor("#4CAF50") + CalendarEventType.EXERCISE -> Color.parseColor("#9800FF") + else -> ContextCompat.getColor(context, R.color.color_primary) + } + } else { + argbToColor(color) } } diff --git a/android/settings.gradle b/android/settings.gradle index 253bd048..de7a1747 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version '8.3.1' apply false + id "com.android.application" version '8.3.2' apply false id "org.jetbrains.kotlin.android" version "1.9.20" apply false id "com.google.gms.google-services" version "4.4.0" apply false id "com.google.firebase.crashlytics" version "2.9.9" apply false diff --git a/assets/images/tower.png b/assets/images/tower.png index 257443f1..5cdcf82a 100644 Binary files a/assets/images/tower.png and b/assets/images/tower.png differ diff --git a/ios/CalendarWidget/CalendarEntry.swift b/ios/CalendarWidget/CalendarEntry.swift index d4e29ef6..bb928f84 100644 --- a/ios/CalendarWidget/CalendarEntry.swift +++ b/ios/CalendarWidget/CalendarEntry.swift @@ -14,13 +14,14 @@ struct CalendarEntry: Codable, Identifiable { let status: String let startDate: Date let endDate: Date - let location: String + let location: String? + let color: Int? enum CodingKeys: String, CodingKey { case id = "nr" case startDate = "dtstart" case endDate = "dtend" - case title, location, status + case title, location, status, color } var isCanceled: Bool { @@ -40,15 +41,20 @@ struct CalendarEntry: Codable, Identifiable { } var eventColor: Color { - switch type { - case .canceled: - return Color(red: 244 / 255, green: 67 / 255, blue: 54 / 255) - case .lecture: - return Color(red: 76 / 255, green: 175 / 255, blue: 80 / 255) - case .exercise: - return Color(red: 255 / 255, green: 152 / 255, blue: 0 / 255) - default: - return .accent + if (color == nil) { + switch type { + case .canceled: + return Color(red: 244 / 255, green: 67 / 255, blue: 54 / 255) + case .lecture: + return Color(red: 76 / 255, green: 175 / 255, blue: 80 / 255) + case .exercise: + return Color(red: 255 / 255, green: 152 / 255, blue: 0 / 255) + default: + return .accent + } + } + else { + return Color(argb: UInt32(color!)) } } } diff --git a/ios/CalendarWidget/CalendarEventView.swift b/ios/CalendarWidget/CalendarEventView.swift index 40ea568d..ba46c68a 100644 --- a/ios/CalendarWidget/CalendarEventView.swift +++ b/ios/CalendarWidget/CalendarEventView.swift @@ -51,9 +51,15 @@ struct CalendarEventView: View { let timeText = "\(timeFormatter.string(from: event.startDate)) - \(timeFormatter.string(from: event.endDate))" - Text("\(timeText) | \(event.location)") - .font(.caption2) - .lineLimit(1) + if (event.location != nil) { + Text("\(timeText) | \(event.location!)") + .font(.caption2) + .lineLimit(1) + } else { + Text(timeText) + .font(.caption2) + .lineLimit(1) + } } .padding(6) .foregroundStyle(.white) diff --git a/ios/CalendarWidget/CalendarWidget.swift b/ios/CalendarWidget/CalendarWidget.swift index 5a7ebeec..940bd004 100644 --- a/ios/CalendarWidget/CalendarWidget.swift +++ b/ios/CalendarWidget/CalendarWidget.swift @@ -13,13 +13,13 @@ struct Provider: TimelineProvider { CalendarWidgetEntry( date: Date(), entries: [ - CalendarEntry(id: "0", title: "Lineare Algebra für Informatik", status: "Test", startDate: Date.now, endDate: Date.now, location: "Galileo Audimax"), - CalendarEntry(id: "0", title: "Einführung in die Buchführung", status: "Test", startDate: Date.now, endDate: Date.now, location: "Audimax") + CalendarEntry(id: "0", title: "Lineare Algebra für Informatik", status: "Test", startDate: Date.now, endDate: Date.now, location: "Galileo Audimax", color: nil), + CalendarEntry(id: "0", title: "Einführung in die Buchführung", status: "Test", startDate: Date.now, endDate: Date.now, location: "Audimax", color: nil) ], size: context.family ) } - + func getSnapshot(in context: Context, completion: @escaping (CalendarWidgetEntry) -> ()) { if context.isPreview{ let entry = placeholder(in: context) @@ -42,7 +42,7 @@ struct Provider: TimelineProvider { } } } - + func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { getSnapshot(in: context) { (entry) in let timeline = Timeline(entries: [entry], policy: .atEnd) @@ -53,7 +53,7 @@ struct Provider: TimelineProvider { struct CalendarWidget: Widget { let kind: String = "CalendarWidget" - + var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider()) { entry in if #available(iOS 17.0, *) { diff --git a/ios/CalendarWidget/ColorExtension.swift b/ios/CalendarWidget/ColorExtension.swift new file mode 100644 index 00000000..6af5fbe5 --- /dev/null +++ b/ios/CalendarWidget/ColorExtension.swift @@ -0,0 +1,19 @@ +// +// ColorExtension.swift +// CalendarWidgetExtension +// +// Created by Jakob Körber on 03.04.24. +// + +import Foundation +import SwiftUI + +extension Color { + init(argb: UInt32) { + let alpha = Double((argb >> 24) & 0xFF) / 255.0 + let red = Double((argb >> 16) & 0xFF) / 255.0 + let green = Double((argb >> 8) & 0xFF) / 255.0 + let blue = Double(argb & 0xFF) / 255.0 + self.init(red: red, green: green, blue: blue, opacity: alpha) + } +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 947775e6..2552816b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -6,10 +6,10 @@ PODS: - Firebase/Crashlytics (10.22.0): - Firebase/CoreOnly - FirebaseCrashlytics (~> 10.22.0) - - firebase_core (2.27.2): + - firebase_core (2.29.0): - Firebase/CoreOnly (= 10.22.0) - Flutter - - firebase_crashlytics (3.4.20): + - firebase_crashlytics (3.5.1): - Firebase/Crashlytics (= 10.22.0) - firebase_core - Flutter @@ -17,9 +17,9 @@ PODS: - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.12) - GoogleUtilities/Logger (~> 7.12) - - FirebaseCoreExtension (10.23.0): + - FirebaseCoreExtension (10.24.0): - FirebaseCore (~> 10.0) - - FirebaseCoreInternal (10.23.0): + - FirebaseCoreInternal (10.24.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - FirebaseCrashlytics (10.22.0): - FirebaseCore (~> 10.5) @@ -29,12 +29,12 @@ PODS: - GoogleUtilities/Environment (~> 7.8) - nanopb (< 2.30911.0, >= 2.30908.0) - PromisesObjC (~> 2.1) - - FirebaseInstallations (10.23.0): + - FirebaseInstallations (10.24.0): - FirebaseCore (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/UserDefaults (~> 7.8) - PromisesObjC (~> 2.1) - - FirebaseSessions (10.23.0): + - FirebaseSessions (10.24.0): - FirebaseCore (~> 10.5) - FirebaseCoreExtension (~> 10.0) - FirebaseInstallations (~> 10.0) @@ -188,14 +188,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d Firebase: 797fd7297b7e1be954432743a0b3f90038e45a71 - firebase_core: cc49b6648d6dd7570d9273a616cb1205260db91e - firebase_crashlytics: a5050259f9e6989a44c131dbf14887a434b4395a + firebase_core: aaadbddb3cb2ee3792b9804f9dbb63e5f6f7b55c + firebase_crashlytics: 4271b5bb77f6169ac7c2a9d62ad0e6aa5f84c2fe FirebaseCore: 0326ec9b05fbed8f8716cddbf0e36894a13837f7 - FirebaseCoreExtension: cb88851781a24e031d1b58e0bd01eb1f46b044b5 - FirebaseCoreInternal: 6a292e6f0bece1243a737e81556e56e5e19282e3 + FirebaseCoreExtension: af5fd85e817ea9d19f9a2659a376cf9cf99f03c0 + FirebaseCoreInternal: bcb5acffd4ea05e12a783ecf835f2210ce3dc6af FirebaseCrashlytics: e568d68ce89117c80cddb04073ab9018725fbb8c - FirebaseInstallations: 42d6ead4605d6eafb3b6683674e80e18eb6f2c35 - FirebaseSessions: f06853e30f99fe42aa511014d7ee6c8c319f08a3 + FirebaseInstallations: 8f581fca6478a50705d2bd2abd66d306e0f5736e + FirebaseSessions: 2651b464e241c93fd44112f995d5ab663c970487 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be @@ -206,7 +206,7 @@ SPEC CHECKSUMS: GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152 home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57 isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 - map_launcher: e325db1261d029ff33e08e03baccffe09593ffea + map_launcher: 5fde49ac9a52672bf99da746599f507b4490d7b5 nanopb: 438bc412db1928dac798aa6fd75726007be04262 package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index fbdfaf50..e84a14b9 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 28C6B8A32B6AEB8700DD5E9A /* CalendarWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 28C6B8962B6AEB8500DD5E9A /* CalendarWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 28C6B8AB2B6AF13100DD5E9A /* CalendarEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C6B8A92B6AEDEC00DD5E9A /* CalendarEntry.swift */; }; 28CAF3FA2B6CF54100C1F412 /* CalendarEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28CAF3F92B6CF54100C1F412 /* CalendarEventType.swift */; }; + 28ECAB0A2BBD8C7D008A3F17 /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28ECAB092BBD8C7D008A3F17 /* ColorExtension.swift */; }; 28F2C3202B29C62C00DC87B4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 28F2C31F2B29C62C00DC87B4 /* GoogleService-Info.plist */; }; 3208B3C6E6BD767EB8753CBA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B38658BC54648274DCF4104 /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; @@ -89,6 +90,7 @@ 28C6B8A92B6AEDEC00DD5E9A /* CalendarEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarEntry.swift; sourceTree = ""; }; 28CAF3F92B6CF54100C1F412 /* CalendarEventType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarEventType.swift; sourceTree = ""; }; 28CBEFE12ACB1A25002DCDEC /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 28ECAB092BBD8C7D008A3F17 /* ColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtension.swift; sourceTree = ""; }; 28F2C31F2B29C62C00DC87B4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 420655E10FFEF68E399A0BDC /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; @@ -137,6 +139,7 @@ 28CAF3F92B6CF54100C1F412 /* CalendarEventType.swift */, 2844DDE22B964B6C00E20EDA /* CalendarEventView.swift */, 28169AD22B9BBE7200FCCFDC /* CalendarWidgetContent.swift */, + 28ECAB092BBD8C7D008A3F17 /* ColorExtension.swift */, 2844DDE42B964BAE00E20EDA /* DateExtension.swift */, 28C6B89E2B6AEB8700DD5E9A /* Assets.xcassets */, 28C6B8A02B6AEB8700DD5E9A /* Info.plist */, @@ -464,6 +467,7 @@ 2862C8472B6C205600EF5825 /* CalendarWidgetEntry.swift in Sources */, 2844DDE52B964BAE00E20EDA /* DateExtension.swift in Sources */, 2844DDE32B964B6C00E20EDA /* CalendarEventView.swift in Sources */, + 28ECAB0A2BBD8C7D008A3F17 /* ColorExtension.swift in Sources */, 28CAF3FA2B6CF54100C1F412 /* CalendarEventType.swift in Sources */, 28C6B89B2B6AEB8500DD5E9A /* CalendarWidgetBundle.swift in Sources */, 28C6B89D2B6AEB8500DD5E9A /* CalendarWidget.swift in Sources */, diff --git a/lib/base/enums/user_preference.dart b/lib/base/enums/user_preference.dart index 8b332c8c..414e3a8a 100644 --- a/lib/base/enums/user_preference.dart +++ b/lib/base/enums/user_preference.dart @@ -4,8 +4,10 @@ enum UserPreference { studyRoom(int), homeWidgets(List), theme(int), + calendarColors(String), browser(bool), failedGrades(bool), + weekends(bool), locale(String); final Type type; diff --git a/lib/base/errorHandling/error_handling_view.dart b/lib/base/errorHandling/error_handling_view.dart index fe3b5a9f..165d62e0 100644 --- a/lib/base/errorHandling/error_handling_view.dart +++ b/lib/base/errorHandling/error_handling_view.dart @@ -40,7 +40,7 @@ mixin ErrorHandlingView { errorMessage, context, style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: titleColor ?? Theme.of(context).primaryColor, + color: titleColor ?? context.primaryColor, ), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -86,7 +86,7 @@ mixin ErrorHandlingView { errorMessage, context, style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: titleColor ?? Theme.of(context).primaryColor, + color: titleColor ?? context.primaryColor, ), textAlign: TextAlign.center, ), @@ -100,20 +100,18 @@ mixin ErrorHandlingView { ), ); case ErrorHandlingViewType.descriptionOnly: - return Center( - child: _errorMessageText( - errorMessage, - context, - style: TextStyle(color: bodyColor), - ), + return _errorMessageText( + errorMessage, + context, + style: TextStyle(color: bodyColor), + textAlign: TextAlign.center, ); case ErrorHandlingViewType.redDescriptionOnly: - return Center( - child: _errorMessageText( - errorMessage, - context, - style: const TextStyle(color: Colors.red), - ), + return _errorMessageText( + errorMessage, + context, + style: const TextStyle(color: Colors.red), + textAlign: TextAlign.center, ); } } diff --git a/lib/base/extensions/context.dart b/lib/base/extensions/context.dart index 03c93608..6e8f1ffa 100644 --- a/lib/base/extensions/context.dart +++ b/lib/base/extensions/context.dart @@ -7,6 +7,8 @@ extension ContextTheme on BuildContext { double get halfPadding => 5.0; double get padding => 15.0; + + Color get primaryColor => Theme.of(this).primaryColor; } extension Localization on BuildContext { diff --git a/lib/base/localization/app_de.arb b/lib/base/localization/app_de.arb index e196188c..144c25d0 100644 --- a/lib/base/localization/app_de.arb +++ b/lib/base/localization/app_de.arb @@ -263,14 +263,14 @@ }, "closedToday":"Heute geschlossen", "submitFeedback":"Feedback einreichen", - "yourEmailAddress":"Deine E-Mail-Adresse", + "name":"Name", "message":"Nachricht", "shareLocation":"Aktuellen Standort teilen", "shareDeviceInformation":"Informationen über das Gerät teilen", "submit":"Senden", "yourMessage":"Deine Nachricht...", - "yourEmail":"deineemail@tum.de", - "invalidEmail":"Ungültige E-Mail-Adresse", + "yourName":"Dein Name...", + "invalidName":"Ungültiger Name", "invalidMessage":"Ungültige Nachricht", "unableToSend":"Nachricht kann nicht gesendet werden!", "successfullySent":"Nachricht erfolgreich gesendet!\n Danke für Dein Feedback!", @@ -334,5 +334,10 @@ } } }, - "unknownDirection":"Unbekannte Richtung" + "unknownDirection":"Unbekannte Richtung", + "showWeekends":"Wochenenden anzeigen", + "color":"Farbe", + "resetAll":"Alles zurücksetzen", + "resetPreferences":"Einstellungen zurücksetzen", + "mostSearchedRooms":"meistgesuche Räume" } diff --git a/lib/base/localization/app_en.arb b/lib/base/localization/app_en.arb index 065f1313..aa7e7a44 100644 --- a/lib/base/localization/app_en.arb +++ b/lib/base/localization/app_en.arb @@ -263,14 +263,14 @@ }, "closedToday":"Closed Today", "submitFeedback":"Submit Feedback", - "yourEmailAddress":"Your Email Address", + "name":"Name", "message":"Message", "shareLocation":"Share Current Location", "shareDeviceInformation":"Share Device's Information", "submit":"Submit", - "yourMessage":"Your Message", - "yourEmail":"youremail@tum.de", - "invalidEmail":"Invalid Email Address", + "yourMessage":"Your Message...", + "yourName":"Your Name...", + "invalidName":"Invalid Name", "invalidMessage":"Invalid Message", "unableToSend":"Unable to Send Message!", "successfullySent":"Message Successfully Sent!\n Thanks for Your Feedback!", @@ -334,5 +334,10 @@ } } }, - "unknownDirection":"Unknown Direction" + "unknownDirection":"Unknown Direction", + "showWeekends":"Show Weekends", + "color":"Color", + "resetAll":"Reset All", + "resetPreferences":"Reset Preferences", + "mostSearchedRooms":"Most Searched Rooms" } diff --git a/lib/base/networking/apis/tumdev/campus_backend.pb.dart b/lib/base/networking/apis/tumdev/campus_backend.pb.dart index 9d42dfad..3c486186 100644 --- a/lib/base/networking/apis/tumdev/campus_backend.pb.dart +++ b/lib/base/networking/apis/tumdev/campus_backend.pb.dart @@ -3299,6 +3299,7 @@ class CreateFeedbackRequest extends $pb.GeneratedMessage { $core.String? osVersion, $core.String? appVersion, $core.List<$core.int>? attachment, + $core.String? fromName, }) { final $result = create(); if (recipient != null) { @@ -3322,6 +3323,9 @@ class CreateFeedbackRequest extends $pb.GeneratedMessage { if (attachment != null) { $result.attachment = attachment; } + if (fromName != null) { + $result.fromName = fromName; + } return $result; } CreateFeedbackRequest._() : super(); @@ -3336,6 +3340,7 @@ class CreateFeedbackRequest extends $pb.GeneratedMessage { ..aOS(5, _omitFieldNames ? '' : 'osVersion') ..aOS(6, _omitFieldNames ? '' : 'appVersion') ..a<$core.List<$core.int>>(7, _omitFieldNames ? '' : 'attachment', $pb.PbFieldType.OY) + ..aOS(8, _omitFieldNames ? '' : 'fromName') ..hasRequiredFields = false ; @@ -3433,6 +3438,16 @@ class CreateFeedbackRequest extends $pb.GeneratedMessage { $core.bool hasAttachment() => $_has(6); @$pb.TagNumber(7) void clearAttachment() => clearField(7); + + /// how the person wants to be called + @$pb.TagNumber(8) + $core.String get fromName => $_getSZ(7); + @$pb.TagNumber(8) + set fromName($core.String v) { $_setString(7, v); } + @$pb.TagNumber(8) + $core.bool hasFromName() => $_has(7); + @$pb.TagNumber(8) + void clearFromName() => clearField(8); } class Coordinate extends $pb.GeneratedMessage { diff --git a/lib/base/networking/apis/tumdev/campus_backend.pbjson.dart b/lib/base/networking/apis/tumdev/campus_backend.pbjson.dart index 5fa94f26..12c04947 100644 --- a/lib/base/networking/apis/tumdev/campus_backend.pbjson.dart +++ b/lib/base/networking/apis/tumdev/campus_backend.pbjson.dart @@ -687,6 +687,7 @@ const CreateFeedbackRequest$json = { '2': [ {'1': 'recipient', '3': 1, '4': 1, '5': 14, '6': '.api.CreateFeedbackRequest.Recipient', '10': 'recipient'}, {'1': 'from_email', '3': 2, '4': 1, '5': 9, '10': 'fromEmail'}, + {'1': 'from_name', '3': 8, '4': 1, '5': 9, '10': 'fromName'}, {'1': 'message', '3': 3, '4': 1, '5': 9, '10': 'message'}, {'1': 'location', '3': 4, '4': 1, '5': 11, '6': '.api.Coordinate', '10': 'location'}, {'1': 'os_version', '3': 5, '4': 1, '5': 9, '10': 'osVersion'}, @@ -709,10 +710,11 @@ const CreateFeedbackRequest_Recipient$json = { final $typed_data.Uint8List createFeedbackRequestDescriptor = $convert.base64Decode( 'ChVDcmVhdGVGZWVkYmFja1JlcXVlc3QSQgoJcmVjaXBpZW50GAEgASgOMiQuYXBpLkNyZWF0ZU' 'ZlZWRiYWNrUmVxdWVzdC5SZWNpcGllbnRSCXJlY2lwaWVudBIdCgpmcm9tX2VtYWlsGAIgASgJ' - 'Uglmcm9tRW1haWwSGAoHbWVzc2FnZRgDIAEoCVIHbWVzc2FnZRIrCghsb2NhdGlvbhgEIAEoCz' - 'IPLmFwaS5Db29yZGluYXRlUghsb2NhdGlvbhIdCgpvc192ZXJzaW9uGAUgASgJUglvc1ZlcnNp' - 'b24SHwoLYXBwX3ZlcnNpb24YBiABKAlSCmFwcFZlcnNpb24SHgoKYXR0YWNobWVudBgHIAEoDF' - 'IKYXR0YWNobWVudCIpCglSZWNpcGllbnQSCwoHVFVNX0RFVhAAEg8KC1RVTV9DT05UQUNUEAE='); + 'Uglmcm9tRW1haWwSGwoJZnJvbV9uYW1lGAggASgJUghmcm9tTmFtZRIYCgdtZXNzYWdlGAMgAS' + 'gJUgdtZXNzYWdlEisKCGxvY2F0aW9uGAQgASgLMg8uYXBpLkNvb3JkaW5hdGVSCGxvY2F0aW9u' + 'Eh0KCm9zX3ZlcnNpb24YBSABKAlSCW9zVmVyc2lvbhIfCgthcHBfdmVyc2lvbhgGIAEoCVIKYX' + 'BwVmVyc2lvbhIeCgphdHRhY2htZW50GAcgASgMUgphdHRhY2htZW50IikKCVJlY2lwaWVudBIL' + 'CgdUVU1fREVWEAASDwoLVFVNX0NPTlRBQ1QQAQ=='); @$core.Deprecated('Use coordinateDescriptor instead') const Coordinate$json = { diff --git a/lib/base/routing/router.dart b/lib/base/routing/router.dart index 620c595a..4c2e17c8 100644 --- a/lib/base/routing/router.dart +++ b/lib/base/routing/router.dart @@ -7,6 +7,7 @@ import 'package:campus_flutter/calendarComponent/views/calendars_view.dart'; import 'package:campus_flutter/calendarComponent/views/event_creation_view.dart'; import 'package:campus_flutter/departuresComponent/views/departures_details_view.dart'; import 'package:campus_flutter/feedbackComponent/views/feedback_form_view.dart'; +import 'package:campus_flutter/feedbackComponent/views/feedback_success_view.dart'; import 'package:campus_flutter/gradeComponent/views/grades_view.dart'; import 'package:campus_flutter/homeComponent/home_screen.dart'; import 'package:campus_flutter/lectureComponent/model/lecture.dart'; @@ -99,7 +100,7 @@ final _router = GoRouter( routes: [ GoRoute( path: calendar, - pageBuilder: (context, state) => const NoTransitionPage( + pageBuilder: (context, state) => NoTransitionPage( child: CalendarsView(), ), ), @@ -140,14 +141,24 @@ final _router = GoRouter( GoRoute( path: "feedback", builder: (context, state) => const FeedbackFormScaffold(), + routes: [ + GoRoute( + path: "success", + builder: (context, state) => const FeedbackSuccessView(), + ), + ], ), ], ), GoRoute( path: lectureDetails, - builder: (context, state) => LectureDetailsScaffold( - lecture: state.extra as Lecture, - ), + builder: (context, state) { + final data = state as (Lecture?, CalendarEvent?); + return LectureDetailsScaffold( + lecture: data.$1, + event: data.$2, + ); + }, ), GoRoute( path: calendarDetails, diff --git a/lib/base/routing/routes.dart b/lib/base/routing/routes.dart index e1572b43..95ebc0d1 100644 --- a/lib/base/routing/routes.dart +++ b/lib/base/routing/routes.dart @@ -32,6 +32,7 @@ const studyRooms = "/studyRooms"; /// Settings const menuSettings = "/menu+settings"; const feedback = "$menuSettings/feedback"; +const feedbackSuccess = "$feedback/success"; /// General const search = "/search"; diff --git a/lib/base/services/location_service.dart b/lib/base/services/location_service.dart index 87150a56..8496b957 100644 --- a/lib/base/services/location_service.dart +++ b/lib/base/services/location_service.dart @@ -30,6 +30,10 @@ class LocationService { } static Future getLastKnown() async { - return await Geolocator.getLastKnownPosition(); + try { + return await Geolocator.getLastKnownPosition(); + } catch (_) { + return null; + } } } diff --git a/lib/base/views/color_picker_view.dart b/lib/base/views/color_picker_view.dart new file mode 100644 index 00000000..77c16030 --- /dev/null +++ b/lib/base/views/color_picker_view.dart @@ -0,0 +1,80 @@ +import 'package:campus_flutter/base/extensions/context.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +class ColorPickerView extends StatefulWidget { + const ColorPickerView({ + super.key, + required this.color, + required this.onColorChanged, + }); + + final Color? color; + final Function(Color)? onColorChanged; + + @override + State createState() => _ColorPickerViewState(); +} + +class _ColorPickerViewState extends State { + late Color selectedColor; + + @override + void didChangeDependencies() { + selectedColor = widget.color ?? context.primaryColor; + super.didChangeDependencies(); + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + titlePadding: const EdgeInsets.all(0), + contentPadding: const EdgeInsets.all(0), + content: SingleChildScrollView( + child: ColorPicker( + pickerColor: selectedColor, + onColorChanged: (color) { + setState(() { + selectedColor = color; + }); + if (widget.onColorChanged != null) { + widget.onColorChanged!(color); + } + }, + ), + ), + ); + }, + ); + }, + child: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + color: selectedColor, + shape: BoxShape.circle, + border: Border.all( + color: (() { + final luminance = selectedColor.computeLuminance(); + if (luminance >= 0.5) { + return Theme.of(context).brightness == Brightness.light + ? Colors.grey + : selectedColor; + } else { + return Theme.of(context).brightness == Brightness.light + ? selectedColor + : Colors.white; + } + })(), + width: 1, + ), + ), + ), + ); + } +} diff --git a/lib/calendarComponent/model/calendar_data_source.dart b/lib/calendarComponent/model/calendar_data_source.dart index d746b9e2..14428b8f 100644 --- a/lib/calendarComponent/model/calendar_data_source.dart +++ b/lib/calendarComponent/model/calendar_data_source.dart @@ -23,7 +23,7 @@ class MeetingDataSource extends CalendarDataSource { @override String getSubject(int index) { final calendarEvent = cast(appointments![index])!; - return "${calendarEvent.title}\n${calendarEvent.location}"; + return "${calendarEvent.title}\n${calendarEvent.location ?? ""}"; } @override @@ -34,6 +34,6 @@ class MeetingDataSource extends CalendarDataSource { @override Color getColor(int index) { final appointment = appointments![index]! as CalendarEvent; - return appointment.getEventColor(context); + return appointment.getColor(context); } } diff --git a/lib/calendarComponent/model/calendar_event.dart b/lib/calendarComponent/model/calendar_event.dart index e1232491..7d374f63 100644 --- a/lib/calendarComponent/model/calendar_event.dart +++ b/lib/calendarComponent/model/calendar_event.dart @@ -22,6 +22,8 @@ class CalendarEvent extends Searchable { final DateTime endDate; final String? location; + int? color; + Duration get duration { return endDate.difference(startDate); } @@ -77,16 +79,24 @@ class CalendarEvent extends Searchable { } } - Color getEventColor(BuildContext context) { - switch (type) { - case CalendarEventType.canceled: - return Colors.red; - case CalendarEventType.lecture: - return Colors.green; - case CalendarEventType.exercise: - return Colors.orange; - default: - return Theme.of(context).primaryColor; + void setColor(Color? color) { + this.color = color?.value; + } + + Color getColor(BuildContext context) { + if (color == null) { + switch (type) { + case CalendarEventType.canceled: + return Colors.red; + case CalendarEventType.lecture: + return Colors.green; + case CalendarEventType.exercise: + return Colors.orange; + default: + return context.primaryColor; + } + } else { + return Color(color!); } } @@ -106,6 +116,7 @@ class CalendarEvent extends Searchable { required this.startDate, required this.endDate, this.location, + this.color, }); factory CalendarEvent.fromJson(Map json) => diff --git a/lib/calendarComponent/model/calendar_event.g.dart b/lib/calendarComponent/model/calendar_event.g.dart index 67fa7e57..95696148 100644 --- a/lib/calendarComponent/model/calendar_event.g.dart +++ b/lib/calendarComponent/model/calendar_event.g.dart @@ -16,6 +16,7 @@ CalendarEvent _$CalendarEventFromJson(Map json) => startDate: DateTime.parse(json['dtstart'] as String), endDate: DateTime.parse(json['dtend'] as String), location: json['location'] as String?, + color: json['color'] as int?, ); Map _$CalendarEventToJson(CalendarEvent instance) => @@ -28,6 +29,7 @@ Map _$CalendarEventToJson(CalendarEvent instance) => 'dtstart': instance.startDate.toIso8601String(), 'dtend': instance.endDate.toIso8601String(), 'location': instance.location, + 'color': instance.color, }; CalendarEvents _$CalendarEventsFromJson(Map json) => diff --git a/lib/calendarComponent/model/color_preferences.dart b/lib/calendarComponent/model/color_preferences.dart new file mode 100644 index 00000000..94edb094 --- /dev/null +++ b/lib/calendarComponent/model/color_preferences.dart @@ -0,0 +1,15 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'color_preferences.g.dart'; + +@JsonSerializable() +class ColorPreferences { + final Map preferences; + + ColorPreferences(this.preferences); + + factory ColorPreferences.fromJson(Map json) => + _$ColorPreferencesFromJson(json); + + Map toJson() => _$ColorPreferencesToJson(this); +} diff --git a/lib/calendarComponent/model/color_preferences.g.dart b/lib/calendarComponent/model/color_preferences.g.dart new file mode 100644 index 00000000..73cbcf70 --- /dev/null +++ b/lib/calendarComponent/model/color_preferences.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'color_preferences.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ColorPreferences _$ColorPreferencesFromJson(Map json) => + ColorPreferences( + Map.from(json['preferences'] as Map), + ); + +Map _$ColorPreferencesToJson(ColorPreferences instance) => + { + 'preferences': instance.preferences, + }; diff --git a/lib/calendarComponent/services/calendar_color_service.dart b/lib/calendarComponent/services/calendar_color_service.dart new file mode 100644 index 00000000..ffc2b077 --- /dev/null +++ b/lib/calendarComponent/services/calendar_color_service.dart @@ -0,0 +1,50 @@ +import 'dart:convert'; + +import 'package:campus_flutter/calendarComponent/model/color_preferences.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class CalendarColorService { + static const key = "calendarColors"; + + final SharedPreferences sharedPreferences; + + Map colorPreferences = {}; + + CalendarColorService(this.sharedPreferences); + + void saveColorPreference(String id, Color color) { + colorPreferences[id] = color.value; + try { + sharedPreferences.setString( + key, + jsonEncode(ColorPreferences(colorPreferences).toJson()), + ); + } catch (_) {} + } + + Color? getColorPreference(String key) { + if (colorPreferences.isEmpty) { + loadColorPreferences(); + } + + final color = colorPreferences[key]; + return color != null ? Color(color) : null; + } + + void loadColorPreferences() { + try { + final data = sharedPreferences.getString(key); + if (data != null) { + final json = jsonDecode(data); + colorPreferences = ColorPreferences.fromJson( + json as Map, + ).preferences; + } + } catch (_) {} + } + + void resetColorPreferences() { + sharedPreferences.remove(key); + } +} diff --git a/lib/calendarComponent/viewModels/calendar_viewmodel.dart b/lib/calendarComponent/viewModels/calendar_viewmodel.dart index ba48f9f0..fcb19fa3 100644 --- a/lib/calendarComponent/viewModels/calendar_viewmodel.dart +++ b/lib/calendarComponent/viewModels/calendar_viewmodel.dart @@ -1,7 +1,10 @@ import 'dart:convert'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; +import 'package:campus_flutter/calendarComponent/services/calendar_color_service.dart'; import 'package:campus_flutter/calendarComponent/services/calendar_service.dart'; +import 'package:campus_flutter/main.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:home_widget/home_widget.dart'; import 'package:rxdart/rxdart.dart'; @@ -20,6 +23,15 @@ class CalendarViewModel { CalendarService.fetchCalendar(forcedRefresh).then( (response) { lastFetched.add(response.$1); + getIt().loadColorPreferences(); + for (var element in response.$2) { + final eventColor = getIt().getColorPreference( + element.lvNr ?? element.id, + ); + if (eventColor != null) { + element.setColor(eventColor); + } + } events.add(response.$2); updateHomeWidget(response.$2); }, @@ -86,4 +98,26 @@ class CalendarViewModel { Future deleteCalendarElement(String id) async { await CalendarService.deleteCalendarEvent(id).then((value) => fetch(true)); } + + void setEventColor(String key, Color color) { + getIt().saveColorPreference( + key, + color, + ); + final elements = events.value; + elements?.forEach((element) { + if (element.id == key || element.lvNr == key) { + element.setColor(color); + } + }); + events.add(elements); + updateHomeWidget(events.value ?? []); + } + + void resetEventColors() { + final elements = events.value; + elements?.forEach((element) => element.setColor(null)); + events.add(elements); + updateHomeWidget(events.value ?? []); + } } diff --git a/lib/calendarComponent/views/calendar_week_view.dart b/lib/calendarComponent/views/calendar_week_view.dart index 3858c8bb..fb72d772 100644 --- a/lib/calendarComponent/views/calendar_week_view.dart +++ b/lib/calendarComponent/views/calendar_week_view.dart @@ -3,6 +3,7 @@ import 'package:campus_flutter/calendarComponent/services/calendar_view_service. import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; import 'package:campus_flutter/calendarComponent/views/calendars_view.dart'; import 'package:campus_flutter/main.dart'; +import 'package:campus_flutter/settingsComponent/views/settings_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; @@ -27,7 +28,9 @@ class CalendarWeekView extends ConsumerWidget { backgroundColor: Colors.transparent, ), child: SfCalendar( - view: CalendarView.week, + view: ref.read(showWeekends) + ? CalendarView.week + : CalendarView.workWeek, controller: calendarController, dataSource: MeetingDataSource( snapshot.data ?? [], @@ -53,12 +56,10 @@ class CalendarWeekView extends ConsumerWidget { headerStyle: const CalendarHeaderStyle( backgroundColor: Colors.transparent, ), - timeSlotViewSettings: TimeSlotViewSettings( + timeSlotViewSettings: const TimeSlotViewSettings( startHour: 7, endHour: 22, timeFormat: "HH:mm", - numberOfDaysInView: - MediaQuery.sizeOf(context).width > 600 ? 7 : 4, ), ), ), diff --git a/lib/calendarComponent/views/calendars_view.dart b/lib/calendarComponent/views/calendars_view.dart index 744ccc20..ad0a709a 100644 --- a/lib/calendarComponent/views/calendars_view.dart +++ b/lib/calendarComponent/views/calendars_view.dart @@ -11,11 +11,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; import 'package:campus_flutter/base/extensions/context.dart'; -final selectedDate = - StateProvider<(DateTime?, CalendarView?)>((ref) => (null, null)); +final selectedDate = StateProvider<(DateTime?, CalendarView?)>( + (ref) => (null, null), +); + +final calendarsKey = GlobalKey<_CalendarsViewState>( + debugLabel: "calendarsKey", +); class CalendarsView extends ConsumerStatefulWidget { - const CalendarsView({super.key}); + CalendarsView({Key? key}) : super(key: calendarsKey); @override ConsumerState createState() => _CalendarsViewState(); diff --git a/lib/calendarComponent/views/custom_event_view.dart b/lib/calendarComponent/views/custom_event_view.dart index 56a8556e..61a53f71 100644 --- a/lib/calendarComponent/views/custom_event_view.dart +++ b/lib/calendarComponent/views/custom_event_view.dart @@ -1,8 +1,11 @@ import 'package:campus_flutter/base/extensions/context.dart'; +import 'package:campus_flutter/base/views/color_picker_view.dart'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; +import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class CustomEventView extends StatelessWidget { +class CustomEventView extends ConsumerWidget { const CustomEventView({ super.key, required this.calendarEvent, @@ -11,7 +14,7 @@ class CustomEventView extends StatelessWidget { final CalendarEvent calendarEvent; @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, @@ -31,6 +34,19 @@ class CustomEventView extends StatelessWidget { ), context, ), + _infoEntry( + context.localizations.color, + ColorPickerView( + color: calendarEvent.getColor(context), + onColorChanged: (color) { + ref.read(calendarViewModel).setEventColor( + calendarEvent.lvNr ?? calendarEvent.id, + color, + ); + }, + ), + context, + ), ], ); } diff --git a/lib/calendarComponent/views/event_creation_date_time_picker.dart b/lib/calendarComponent/views/event_creation_date_time_picker.dart index 5e10c0d3..2c60ed61 100644 --- a/lib/calendarComponent/views/event_creation_date_time_picker.dart +++ b/lib/calendarComponent/views/event_creation_date_time_picker.dart @@ -90,7 +90,7 @@ class EventCreationDateTimePicker extends StatelessWidget { child: Container( width: 100, decoration: BoxDecoration( - color: Theme.of(context).primaryColor, + color: context.primaryColor, borderRadius: BorderRadius.circular(5), ), child: Center( diff --git a/lib/calendarComponent/views/homeWidget/calendar_widget_event_view.dart b/lib/calendarComponent/views/homeWidget/calendar_widget_event_view.dart index 4bb42c30..12cd9516 100644 --- a/lib/calendarComponent/views/homeWidget/calendar_widget_event_view.dart +++ b/lib/calendarComponent/views/homeWidget/calendar_widget_event_view.dart @@ -54,7 +54,7 @@ class CalendarHomeWidgetEventView extends ConsumerWidget { decoration: BoxDecoration( border: Border( left: BorderSide( - color: calendarEvent.getEventColor(context), + color: calendarEvent.getColor(context), width: 2.0, ), ), diff --git a/lib/calendarComponent/views/homeWidget/calendar_widget_view.dart b/lib/calendarComponent/views/homeWidget/calendar_widget_view.dart index 308befe6..15c42814 100644 --- a/lib/calendarComponent/views/homeWidget/calendar_widget_view.dart +++ b/lib/calendarComponent/views/homeWidget/calendar_widget_view.dart @@ -126,7 +126,7 @@ class _CalendarHomeWidgetView extends ConsumerState { children: [ Text( DateFormat.EEEE(context.localizations.localeName).format(today), - style: TextStyle(color: Theme.of(context).primaryColor), + style: TextStyle(color: context.primaryColor), ), Text( DateFormat.MMMd(context.localizations.localeName).format(today), diff --git a/lib/departuresComponent/viewModel/departures_viewmodel.dart b/lib/departuresComponent/viewModel/departures_viewmodel.dart index dd67d22d..2fbea895 100644 --- a/lib/departuresComponent/viewModel/departures_viewmodel.dart +++ b/lib/departuresComponent/viewModel/departures_viewmodel.dart @@ -88,6 +88,9 @@ class DeparturesViewModel { widgetCampus.add(closestCampus); assignSelectedStation(); + } else { + widgetCampus.add(Campus.garching); + assignSelectedStation(); } }, onError: (error) { diff --git a/lib/departuresComponent/views/departures_details_view.dart b/lib/departuresComponent/views/departures_details_view.dart index 05c05c4d..9869f94e 100644 --- a/lib/departuresComponent/views/departures_details_view.dart +++ b/lib/departuresComponent/views/departures_details_view.dart @@ -99,7 +99,7 @@ class _DeparturesDetailsViewState extends ConsumerState { .name, style: TextStyle( fontWeight: FontWeight.bold, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), ), ], diff --git a/lib/departuresComponent/views/homeWidget/departures_widget_view.dart b/lib/departuresComponent/views/homeWidget/departures_widget_view.dart index cec25835..e448e0b6 100644 --- a/lib/departuresComponent/views/homeWidget/departures_widget_view.dart +++ b/lib/departuresComponent/views/homeWidget/departures_widget_view.dart @@ -49,7 +49,7 @@ class _DeparturesHomeWidgetState extends ConsumerState { InkWell( child: Icon( Icons.filter_list, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), onTap: () => showModalBottomSheet( builder: (context) => PreferenceSelectionView( @@ -125,7 +125,7 @@ class _DeparturesHomeWidgetState extends ConsumerState { TextSpan( text: station.name, style: TextStyle( - color: Theme.of(context).primaryColor, + color: context.primaryColor, fontWeight: FontWeight.bold, ), ), diff --git a/lib/feedbackComponent/viewModels/feedback_viewmodel.dart b/lib/feedbackComponent/viewModels/feedback_viewmodel.dart index 7b549c03..9f2a764d 100644 --- a/lib/feedbackComponent/viewModels/feedback_viewmodel.dart +++ b/lib/feedbackComponent/viewModels/feedback_viewmodel.dart @@ -1,6 +1,8 @@ -import 'dart:developer'; - +import 'package:campus_flutter/base/enums/error_handling_view_type.dart'; +import 'package:campus_flutter/base/errorHandling/error_handling_router.dart'; +import 'package:campus_flutter/base/extensions/context.dart'; import 'package:campus_flutter/base/networking/apis/tumdev/campus_backend.pb.dart'; +import 'package:campus_flutter/base/routing/routes.dart'; import 'package:campus_flutter/base/services/location_service.dart'; import 'package:campus_flutter/feedbackComponent/services/feedback_service.dart'; import 'package:campus_flutter/personDetailedComponent/viewModel/person_details_viewmodel.dart'; @@ -8,6 +10,7 @@ import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:geolocator/geolocator.dart'; +import 'package:go_router/go_router.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:rxdart/rxdart.dart'; @@ -16,9 +19,9 @@ final feedbackViewModel = Provider((ref) => FeedbackViewModel(ref)); class FeedbackViewModel { BehaviorSubject shareLocation = BehaviorSubject.seeded(false); BehaviorSubject activeButton = BehaviorSubject.seeded(false); - BehaviorSubject validEmail = BehaviorSubject.seeded(null); + BehaviorSubject validName = BehaviorSubject.seeded(null); BehaviorSubject validMessage = BehaviorSubject.seeded(null); - BehaviorSubject successfullySent = BehaviorSubject.seeded(null); + final TextEditingController name = TextEditingController(); final TextEditingController emailAddress = TextEditingController(); final TextEditingController message = TextEditingController(); @@ -27,17 +30,22 @@ class FeedbackViewModel { FeedbackViewModel(this.ref); initForm() { - final email = ref.read(profileDetailsViewModel).personDetails.value?.email; - if (email != null) { - emailAddress.text = email; - validEmail.add(true); + final personDetails = ref.read(profileDetailsViewModel).personDetails.value; + if (personDetails != null) { + name.text = personDetails.fullName; + emailAddress.text = personDetails.email; + validName.add(true); } } - Future sendFeedBack() async { + Future sendFeedBack(BuildContext context) async { Position? position; if (shareLocation.value) { - position = await LocationService.getLastKnown(); + try { + position = await LocationService.getLastKnown(); + } catch (_) { + position = null; + } } DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); @@ -50,6 +58,7 @@ class FeedbackViewModel { final feedback = CreateFeedbackRequest( recipient: CreateFeedbackRequest_Recipient.TUM_DEV, + fromName: name.text, fromEmail: emailAddress.text, message: message.text, location: Coordinate( @@ -61,11 +70,33 @@ class FeedbackViewModel { ); FeedbackService.sendFeedback(feedback).then( - (value) => successfullySent.add(true), - onError: (error) { - log(error.toString()); - successfullySent.addError(error); + (value) { + context.pushReplacement(feedbackSuccess); }, + onError: (error) => _errorDialog(error, context), + ); + } + + void _errorDialog(dynamic error, BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text( + context.localizations.unableToSend, + textAlign: TextAlign.center, + ), + content: ErrorHandlingRouter( + error: error, + errorHandlingViewType: ErrorHandlingViewType.descriptionOnly, + ), + actionsAlignment: MainAxisAlignment.center, + actions: [ + ElevatedButton( + onPressed: () => context.pop(), + child: Text(context.localizations.back), + ), + ], + ), ); } @@ -78,32 +109,22 @@ class FeedbackViewModel { checkButton(); } - void checkEmailValidity() { - final RegExp validEmailRegex = RegExp( - r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+", - ); - if (emailAddress.value.text.isNotEmpty) { - if (validEmailRegex.hasMatch(emailAddress.value.text)) { - validEmail.add(true); - } else { - validEmail.add(false); - } - } - checkButton(); + void checkNameValidity() { + validName.add(name.value.text.isNotEmpty); } void checkButton() { activeButton - .add((validEmail.value ?? false) && (validMessage.value ?? false)); + .add((validName.value ?? false) && (validMessage.value ?? false)); } void clearForm() { + name.text = ""; emailAddress.text = ""; message.text = ""; shareLocation.add(false); activeButton.add(false); validMessage.add(null); - validEmail.add(null); - successfullySent.add(null); + validName.add(null); } } diff --git a/lib/feedbackComponent/views/feedback_form_view.dart b/lib/feedbackComponent/views/feedback_form_view.dart index 73ee0ec1..33f5b8e1 100644 --- a/lib/feedbackComponent/views/feedback_form_view.dart +++ b/lib/feedbackComponent/views/feedback_form_view.dart @@ -1,6 +1,4 @@ -import 'package:campus_flutter/base/enums/error_handling_view_type.dart'; import 'package:campus_flutter/base/extensions/context.dart'; -import 'package:campus_flutter/base/errorHandling/error_handling_router.dart'; import 'package:campus_flutter/base/util/custom_back_button.dart'; import 'package:campus_flutter/base/views/seperated_list.dart'; import 'package:campus_flutter/feedbackComponent/viewModels/feedback_viewmodel.dart'; @@ -47,87 +45,56 @@ class _FeedbackFormViewState extends ConsumerState { @override Widget build(BuildContext context) { - return Form( - child: Column( - children: [ - FeedbackTextField( - title: context.localizations.yourEmailAddress, - textEditingController: ref.read(feedbackViewModel).emailAddress, - validInput: ref.watch(feedbackViewModel).validEmail, - onChanged: (text) => - ref.read(feedbackViewModel).checkEmailValidity(), - invalidMessage: context.localizations.invalidEmail, - decorationMessage: context.localizations.yourEmail, - ), - FeedbackTextField( - title: context.localizations.message, - textEditingController: ref.read(feedbackViewModel).message, - validInput: ref.watch(feedbackViewModel).validMessage, - onChanged: (text) => - ref.read(feedbackViewModel).checkMessageValidity(), - invalidMessage: context.localizations.invalidMessage, - decorationMessage: context.localizations.yourMessage, - expanded: true, - ), - Card( - child: SeparatedList.widgets( - widgets: [ - FeedbackCheckMarkView( - text: context.localizations.shareLocation, - isChecked: ref.read(feedbackViewModel).shareLocation, - ), - ], + return SingleChildScrollView( + child: Form( + child: Column( + children: [ + FeedbackTextField( + title: context.localizations.name, + textEditingController: ref.read(feedbackViewModel).name, + validInput: ref.watch(feedbackViewModel).validName, + onChanged: (text) => + ref.read(feedbackViewModel).checkNameValidity(), + invalidMessage: context.localizations.invalidName, + decorationMessage: context.localizations.yourName, ), - ), - StreamBuilder( - stream: ref.watch(feedbackViewModel).activeButton, - builder: (context, snapshot) { - return Padding( - padding: EdgeInsets.all(context.padding), - child: ElevatedButton( - onPressed: (snapshot.data != null && snapshot.data!) - ? () => ref.read(feedbackViewModel).sendFeedBack() - : null, - child: Text(context.localizations.submit), - ), - ); - }, - ), - StreamBuilder( - stream: ref.watch(feedbackViewModel).successfullySent, - builder: (context, snapshot) { - if (snapshot.hasData) { - return Text( - context.localizations.successfullySent, - style: context.theme.textTheme.bodyLarge - ?.copyWith(color: context.theme.primaryColor), - ); - } else if (snapshot.hasError) { - return Column( - children: [ - Text( - context.localizations.unableToSend, - style: context.theme.textTheme.bodyLarge - ?.copyWith(color: context.theme.primaryColor), - ), - Padding( - padding: EdgeInsets.symmetric( - vertical: context.halfPadding / 2, - ), - ), - ErrorHandlingRouter( - error: snapshot.error!, - errorHandlingViewType: - ErrorHandlingViewType.descriptionOnly, - ), - ], + FeedbackTextField( + title: context.localizations.message, + textEditingController: ref.read(feedbackViewModel).message, + validInput: ref.watch(feedbackViewModel).validMessage, + onChanged: (text) => + ref.read(feedbackViewModel).checkMessageValidity(), + invalidMessage: context.localizations.invalidMessage, + decorationMessage: context.localizations.yourMessage, + expanded: true, + ), + Card( + child: SeparatedList.widgets( + widgets: [ + FeedbackCheckMarkView( + text: context.localizations.shareLocation, + isChecked: ref.read(feedbackViewModel).shareLocation, + ), + ], + ), + ), + StreamBuilder( + stream: ref.watch(feedbackViewModel).activeButton, + builder: (context, snapshot) { + return Padding( + padding: EdgeInsets.all(context.padding), + child: ElevatedButton( + onPressed: (snapshot.data != null && snapshot.data!) + ? () => + ref.read(feedbackViewModel).sendFeedBack(context) + : null, + child: Text(context.localizations.submit), + ), ); - } else { - return const SizedBox(); - } - }, - ), - ], + }, + ), + ], + ), ), ); } diff --git a/lib/feedbackComponent/views/feedback_success_view.dart b/lib/feedbackComponent/views/feedback_success_view.dart new file mode 100644 index 00000000..ac442b83 --- /dev/null +++ b/lib/feedbackComponent/views/feedback_success_view.dart @@ -0,0 +1,40 @@ +import 'package:campus_flutter/base/extensions/context.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class FeedbackSuccessView extends StatelessWidget { + const FeedbackSuccessView({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: const BackButton(), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Padding( + padding: EdgeInsets.symmetric(horizontal: 32.0), + child: Image( + image: AssetImage("assets/images/tower.png"), + fit: BoxFit.contain, + ), + ), + Padding( + padding: EdgeInsets.symmetric(vertical: context.padding * 2), + child: Text( + context.localizations.successfullySent, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ElevatedButton( + onPressed: () => context.pop(), + child: Text(context.localizations.back), + ), + ], + ), + ); + } +} diff --git a/lib/feedbackComponent/views/feedback_textfield.dart b/lib/feedbackComponent/views/feedback_textfield.dart index 4a5eb43d..8f69fb79 100644 --- a/lib/feedbackComponent/views/feedback_textfield.dart +++ b/lib/feedbackComponent/views/feedback_textfield.dart @@ -33,13 +33,15 @@ class FeedbackTextField extends ConsumerWidget { child: CardWithPadding( child: TextFormField( controller: textEditingController, - minLines: expanded ? 3 : null, - maxLines: expanded ? 6 : null, + minLines: expanded ? 4 : null, + maxLines: expanded ? 8 : null, onChanged: onChanged, decoration: InputDecoration( hintText: decorationMessage, errorText: (snapshot.data ?? true) ? null : invalidMessage, ), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ), ), ); diff --git a/lib/gradeComponent/model/grade.dart b/lib/gradeComponent/model/grade.dart index e37a4e4c..fbad9789 100644 --- a/lib/gradeComponent/model/grade.dart +++ b/lib/gradeComponent/model/grade.dart @@ -35,9 +35,9 @@ class Grade extends Searchable { @JsonKey(name: "st_studium_nr") final String studyNumber; @JsonKey(name: "abschluss_name") - final String degree; + final String? degree; @JsonKey(name: "abschluss_name_kurz") - final String degreeShort; + final String? degreeShort; String modeShort(BuildContext context) { switch (mode) { @@ -66,8 +66,8 @@ class Grade extends Searchable { required this.studyID, required this.studyDesignation, required this.studyNumber, - required this.degree, - required this.degreeShort, + this.degree, + this.degreeShort, }); factory Grade.fromJson(Map json) => _$GradeFromJson(json); diff --git a/lib/gradeComponent/model/grade.g.dart b/lib/gradeComponent/model/grade.g.dart index aeac75d4..01d21586 100644 --- a/lib/gradeComponent/model/grade.g.dart +++ b/lib/gradeComponent/model/grade.g.dart @@ -20,8 +20,8 @@ Grade _$GradeFromJson(Map json) => Grade( studyID: json['studienidentifikator'] as String, studyDesignation: json['studienbezeichnung'] as String, studyNumber: json['st_studium_nr'] as String, - degree: json['abschluss_name'] as String, - degreeShort: json['abschluss_name_kurz'] as String, + degree: json['abschluss_name'] as String?, + degreeShort: json['abschluss_name_kurz'] as String?, ); Map _$GradeToJson(Grade instance) => { diff --git a/lib/gradeComponent/views/grade_view.dart b/lib/gradeComponent/views/grade_view.dart index 0b07e03b..c9a18172 100644 --- a/lib/gradeComponent/views/grade_view.dart +++ b/lib/gradeComponent/views/grade_view.dart @@ -1,5 +1,6 @@ import 'dart:core'; +import 'package:campus_flutter/base/extensions/context.dart'; import 'package:campus_flutter/base/util/icon_text.dart'; import 'package:campus_flutter/gradeComponent/model/grade.dart'; import 'package:campus_flutter/gradeComponent/views/grade_rectangle.dart'; @@ -44,7 +45,7 @@ class GradeRow extends StatelessWidget { iconData: iconData, label: text, style: TextStyle(color: Theme.of(context).colorScheme.secondary), - iconColor: Theme.of(context).primaryColor, + iconColor: context.primaryColor, multipleLines: false, ); } diff --git a/lib/homeComponent/widgetComponent/views/home_settings_view.dart b/lib/homeComponent/widgetComponent/views/home_settings_view.dart index 694df5c8..bb75859a 100644 --- a/lib/homeComponent/widgetComponent/views/home_settings_view.dart +++ b/lib/homeComponent/widgetComponent/views/home_settings_view.dart @@ -16,7 +16,7 @@ class HomeSettingsView extends ConsumerWidget { style: Theme.of(context) .textTheme .titleLarge - ?.apply(color: Theme.of(context).primaryColor), + ?.apply(color: context.primaryColor), ), Text(context.localizations.reorderDisable), Padding( diff --git a/lib/lectureComponent/views/lecture_details_view.dart b/lib/lectureComponent/views/lecture_details_view.dart index aa11f401..3cb66e71 100644 --- a/lib/lectureComponent/views/lecture_details_view.dart +++ b/lib/lectureComponent/views/lecture_details_view.dart @@ -4,6 +4,8 @@ import 'package:campus_flutter/base/util/delayed_loading_indicator.dart'; import 'package:campus_flutter/base/util/last_updated_text.dart'; import 'package:campus_flutter/base/errorHandling/error_handling_router.dart'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; +import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; +import 'package:campus_flutter/base/views/color_picker_view.dart'; import 'package:campus_flutter/lectureComponent/model/lecture.dart'; import 'package:campus_flutter/lectureComponent/model/lecture_details.dart'; import 'package:campus_flutter/lectureComponent/viewModels/lecture_details_viewmodel.dart'; @@ -16,7 +18,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; -class LectureDetailsScaffold extends StatelessWidget { +class LectureDetailsScaffold extends ConsumerStatefulWidget { const LectureDetailsScaffold({ super.key, this.scrollController, @@ -28,14 +30,47 @@ class LectureDetailsScaffold extends StatelessWidget { final Lecture? lecture; final ScrollController? scrollController; + @override + ConsumerState createState() => + _LectureDetailsScaffoldState(); +} + +class _LectureDetailsScaffoldState + extends ConsumerState { + late Color selectedColor; + + @override + void didChangeDependencies() { + selectedColor = widget.event?.getColor(context) ?? Colors.red; + super.didChangeDependencies(); + } + @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(leading: const CustomBackButton()), + appBar: AppBar( + leading: const CustomBackButton(), + actions: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: context.padding), + child: ColorPickerView( + color: widget.event?.getColor(context) ?? context.primaryColor, + onColorChanged: (color) { + if (widget.event != null) { + ref.read(calendarViewModel).setEventColor( + widget.event!.lvNr ?? widget.event!.id, + color, + ); + } + }, + ), + ), + ], + ), body: LectureDetailsView( - event: event, - lecture: lecture, - scrollController: scrollController, + event: widget.event, + lecture: widget.lecture, + scrollController: widget.scrollController, ), ); } diff --git a/lib/lectureComponent/views/lecture_view.dart b/lib/lectureComponent/views/lecture_view.dart index 260fcfd2..29ef2121 100644 --- a/lib/lectureComponent/views/lecture_view.dart +++ b/lib/lectureComponent/views/lecture_view.dart @@ -1,3 +1,4 @@ +import 'package:campus_flutter/base/extensions/context.dart'; import 'package:campus_flutter/base/util/icon_text.dart'; import 'package:campus_flutter/base/routing/routes.dart'; import 'package:campus_flutter/lectureComponent/model/lecture.dart'; @@ -37,7 +38,7 @@ class LectureView extends ConsumerWidget { _subtitle(lecture.speaker!, Icons.person, context), ], ), - onTap: () => context.push(lectureDetails, extra: lecture), + onTap: () => context.push(lectureDetails, extra: (lecture, null)), ); } @@ -46,7 +47,7 @@ class LectureView extends ConsumerWidget { iconData: iconData, label: text, style: TextStyle(color: Theme.of(context).colorScheme.secondary), - iconColor: Theme.of(context).primaryColor, + iconColor: context.primaryColor, multipleLines: false, ); } diff --git a/lib/main.dart b/lib/main.dart index 3e646fee..9b1d0873 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,6 +11,7 @@ import 'package:campus_flutter/base/routing/router_service.dart'; import 'package:campus_flutter/base/routing/routes.dart'; import 'package:campus_flutter/base/theme/dark_theme.dart'; import 'package:campus_flutter/base/theme/light_theme.dart'; +import 'package:campus_flutter/calendarComponent/services/calendar_color_service.dart'; import 'package:campus_flutter/calendarComponent/services/calendar_view_service.dart'; import 'package:campus_flutter/onboardingComponent/services/onboarding_service.dart'; import 'package:campus_flutter/navigation_service.dart'; @@ -84,6 +85,9 @@ Future _initializeServices() async { getIt.registerSingleton( UserPreferencesService(sharedPreferences), ); + getIt.registerSingleton( + CalendarColorService(sharedPreferences), + ); } Future _initializeHomeWidgets() async { diff --git a/lib/navigaTumComponent/views/navigatum_room_details_view.dart b/lib/navigaTumComponent/views/navigatum_room_details_view.dart index 8a8de9b4..4db1b8ec 100644 --- a/lib/navigaTumComponent/views/navigatum_room_details_view.dart +++ b/lib/navigaTumComponent/views/navigatum_room_details_view.dart @@ -37,7 +37,7 @@ class NavigaTumRoomDetailsView extends ConsumerWidget { return ListTile( leading: Icon( iconData, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), title: Text(detail), ); diff --git a/lib/navigation_service.dart b/lib/navigation_service.dart index 5ad2c391..3a9cfdc9 100644 --- a/lib/navigation_service.dart +++ b/lib/navigation_service.dart @@ -2,13 +2,8 @@ import 'dart:io'; import 'package:campus_flutter/base/enums/credentials.dart'; import 'package:campus_flutter/base/routing/routes.dart'; -import 'package:campus_flutter/calendarComponent/views/calendars_view.dart'; -import 'package:campus_flutter/gradeComponent/views/grades_view.dart'; -import 'package:campus_flutter/homeComponent/home_screen.dart'; import 'package:campus_flutter/homeComponent/widgetComponent/views/widget_screen.dart'; -import 'package:campus_flutter/lectureComponent/views/lectures_view.dart'; import 'package:campus_flutter/onboardingComponent/viewModels/onboarding_viewmodel.dart'; -import 'package:campus_flutter/placesComponent/views/places_screen.dart'; import 'package:campus_flutter/searchComponent/viewModels/global_search_viewmodel.dart'; import 'package:campus_flutter/studentCardComponent/views/student_card_view.dart'; import 'package:campus_flutter/base/extensions/context.dart'; @@ -18,7 +13,6 @@ import 'package:go_router/go_router.dart'; class NavigationService { double? _navigationBarHeight; - double? _leadingWidth; NavigationService() { if (Platform.isIOS) { @@ -28,16 +22,6 @@ class NavigationService { double? get navigationBarHeight => _navigationBarHeight; - double? get leadingWidth => _leadingWidth; - - List get getContent => [ - const HomeScreen(), - const GradesView(), - const LecturesView(), - const CalendarsView(), - const PlacesScreen(), - ]; - Widget title(int index, BuildContext context) { switch (index) { case 0: diff --git a/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart b/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart index 128c2986..28edba56 100644 --- a/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart +++ b/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart @@ -6,12 +6,15 @@ import 'package:campus_flutter/base/networking/protocols/api.dart'; import 'package:campus_flutter/base/networking/base/rest_client.dart'; import 'package:campus_flutter/base/routing/router_service.dart'; import 'package:campus_flutter/base/routing/routes.dart'; +import 'package:campus_flutter/calendarComponent/services/calendar_color_service.dart'; +import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; import 'package:campus_flutter/onboardingComponent/model/confirm.dart'; import 'package:campus_flutter/onboardingComponent/services/onboarding_service.dart'; import 'package:campus_flutter/main.dart'; import 'package:campus_flutter/personDetailedComponent/viewModel/person_details_viewmodel.dart'; import 'package:campus_flutter/profileComponent/viewModel/profile_viewmodel.dart'; import 'package:campus_flutter/settingsComponent/service/user_preferences_service.dart'; +import 'package:campus_flutter/settingsComponent/viewModels/user_preferences_viewmodel.dart'; import 'package:campus_flutter/studentCardComponent/viewModel/student_card_viewmodel.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -140,6 +143,13 @@ class OnboardingViewModel { context.go(home); } + Future resetPreferences(WidgetRef ref) async { + getIt().resetAll(); + getIt().resetColorPreferences(); + ref.read(userPreferencesViewModel).loadPreferences(); + ref.read(calendarViewModel).resetEventColors(); + } + Future logout(WidgetRef ref) async { ref.invalidate(profileViewModel); ref.invalidate(personDetailsViewModel); @@ -153,6 +163,7 @@ class OnboardingViewModel { androidName: "widgets.calendar.CalendarWidget", ); getIt().resetAll(); + getIt().resetColorPreferences(); Api.tumToken = ""; credentials.add(Credentials.none); } diff --git a/lib/onboardingComponent/views/confirm_view.dart b/lib/onboardingComponent/views/confirm_view.dart index ca7d5d4a..9030c26e 100644 --- a/lib/onboardingComponent/views/confirm_view.dart +++ b/lib/onboardingComponent/views/confirm_view.dart @@ -61,29 +61,29 @@ class _ConfirmViewState extends ConsumerState { 1 && value.compareTo(const Duration(seconds: 9, milliseconds: 2)) == -1) { - setState(() { - if (mounted) { + if (mounted) { + setState(() { currentText = 1; - } - }); + }); + } } else if (value .compareTo(const Duration(seconds: 9, milliseconds: 3)) == 1 && value.compareTo(const Duration(seconds: 16, milliseconds: 24)) == -1) { - setState(() { - if (mounted) { + if (mounted) { + setState(() { currentText = 2; - } - }); + }); + } } else if (value.compareTo(Duration.zero) == 1 && value.compareTo(const Duration(seconds: 5, milliseconds: 16)) == -1) { - setState(() { - if (mounted) { + if (mounted) { + setState(() { currentText = 0; - } - }); + }); + } } } }); @@ -213,7 +213,7 @@ class _ConfirmViewState extends ConsumerState { } }, onError: (error) { - ScaffoldMessenger.of(context).showSnackBar( + ScaffoldMessenger.maybeOf(context)?.showSnackBar( SnackBar( duration: const Duration(seconds: 10), content: ErrorHandlingRouter( @@ -252,7 +252,7 @@ class _ConfirmViewState extends ConsumerState { onPressed: () => context.push(feedback), child: Text( context.localizations.contactSupport, - style: TextStyle(color: Theme.of(context).primaryColor), + style: TextStyle(color: context.primaryColor), ), ), ); diff --git a/lib/onboardingComponent/views/login_view.dart b/lib/onboardingComponent/views/login_view.dart index 5d4cdcf7..41392c5a 100644 --- a/lib/onboardingComponent/views/login_view.dart +++ b/lib/onboardingComponent/views/login_view.dart @@ -248,7 +248,7 @@ class _LoginViewState extends ConsumerState { style: Theme.of(context) .textTheme .bodySmall - ?.apply(color: Theme.of(context).primaryColor), + ?.apply(color: context.primaryColor), ), ); } diff --git a/lib/onboardingComponent/views/permission_view.dart b/lib/onboardingComponent/views/permission_view.dart index f2c74b96..0a122162 100644 --- a/lib/onboardingComponent/views/permission_view.dart +++ b/lib/onboardingComponent/views/permission_view.dart @@ -38,7 +38,7 @@ class PermissionView extends StatelessWidget { Text( title, style: Theme.of(context).textTheme.headlineMedium?.apply( - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), ), Padding( diff --git a/lib/placesComponent/viewModels/cafeterias_viewmodel.dart b/lib/placesComponent/viewModels/cafeterias_viewmodel.dart index 6c6a827e..8331c098 100644 --- a/lib/placesComponent/viewModels/cafeterias_viewmodel.dart +++ b/lib/placesComponent/viewModels/cafeterias_viewmodel.dart @@ -277,7 +277,7 @@ class CafeteriasViewModel { return "🍰"; default: - return " "; + return "🍴"; } } diff --git a/lib/placesComponent/views/cafeterias/dish_card_view.dart b/lib/placesComponent/views/cafeterias/dish_card_view.dart index 73b043fd..74b2c267 100644 --- a/lib/placesComponent/views/cafeterias/dish_card_view.dart +++ b/lib/placesComponent/views/cafeterias/dish_card_view.dart @@ -1,3 +1,4 @@ +import 'package:campus_flutter/base/extensions/context.dart'; import 'package:campus_flutter/base/util/card_with_padding.dart'; import 'package:campus_flutter/placesComponent/model/cafeterias/dish.dart'; import 'package:campus_flutter/placesComponent/viewModels/cafeterias_viewmodel.dart'; @@ -35,7 +36,7 @@ class DishCardView extends StatelessWidget { onPressed: () => _dishInfoAlert(dish.$1, price, context), icon: Icon( Icons.info_outline, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), padding: EdgeInsets.zero, alignment: Alignment.centerRight, diff --git a/lib/placesComponent/views/campuses/campus_card_view.dart b/lib/placesComponent/views/campuses/campus_card_view.dart index 5486a900..bda74567 100644 --- a/lib/placesComponent/views/campuses/campus_card_view.dart +++ b/lib/placesComponent/views/campuses/campus_card_view.dart @@ -43,14 +43,14 @@ class CampusCardView extends ConsumerWidget { Text( campus.name, style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: Theme.of(context).primaryColor, + color: context.primaryColor, fontWeight: FontWeight.w500, ), ), const Spacer(), Icon( Icons.place, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), ], ), diff --git a/lib/placesComponent/views/campuses/campus_most_searched_view.dart b/lib/placesComponent/views/campuses/campus_most_searched_view.dart index d6afc37a..08e6fa42 100644 --- a/lib/placesComponent/views/campuses/campus_most_searched_view.dart +++ b/lib/placesComponent/views/campuses/campus_most_searched_view.dart @@ -64,8 +64,8 @@ class CampusMostSearchedView extends ConsumerWidget { } else { return Padding( padding: EdgeInsets.all(context.padding), - child: const DelayedLoadingIndicator( - name: "Most Searched Rooms", + child: DelayedLoadingIndicator( + name: context.localizations.mostSearchedRooms, ), ); } diff --git a/lib/placesComponent/views/homeWidget/cafeteria_widget_view.dart b/lib/placesComponent/views/homeWidget/cafeteria_widget_view.dart index 930dde07..e3b9c367 100644 --- a/lib/placesComponent/views/homeWidget/cafeteria_widget_view.dart +++ b/lib/placesComponent/views/homeWidget/cafeteria_widget_view.dart @@ -53,7 +53,7 @@ class _CafeteriaWidgetViewState extends ConsumerState { InkWell( child: Icon( Icons.filter_list, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), onTap: () => showModalBottomSheet( builder: (context) => PreferenceSelectionView( diff --git a/lib/placesComponent/views/homeWidget/study_room_widget_view.dart b/lib/placesComponent/views/homeWidget/study_room_widget_view.dart index 5f35cb7f..9d1cb928 100644 --- a/lib/placesComponent/views/homeWidget/study_room_widget_view.dart +++ b/lib/placesComponent/views/homeWidget/study_room_widget_view.dart @@ -73,7 +73,7 @@ class _StudyRoomWidgetViewState extends ConsumerState { InkWell( child: Icon( Icons.filter_list, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), onTap: () => showModalBottomSheet( builder: (context) => diff --git a/lib/placesComponent/views/map_widget.dart b/lib/placesComponent/views/map_widget.dart index f02f5355..2ddd5747 100644 --- a/lib/placesComponent/views/map_widget.dart +++ b/lib/placesComponent/views/map_widget.dart @@ -159,11 +159,13 @@ class _MapWidgetState extends ConsumerState { _controller.complete(controller); Future.delayed( const Duration(milliseconds: 250), - () => setState(() { + () { if (mounted) { - isMapVisible = true; + setState(() { + isMapVisible = true; + }); } - }), + }, ); }, ), diff --git a/lib/searchComponent/views/appWideSearch/resultViews/calendar_search_result_view.dart b/lib/searchComponent/views/appWideSearch/resultViews/calendar_search_result_view.dart index 3b7ed868..3b3c768c 100644 --- a/lib/searchComponent/views/appWideSearch/resultViews/calendar_search_result_view.dart +++ b/lib/searchComponent/views/appWideSearch/resultViews/calendar_search_result_view.dart @@ -1,13 +1,13 @@ -import 'package:campus_flutter/base/util/custom_back_button.dart'; +import 'package:campus_flutter/base/routing/routes.dart'; import 'package:campus_flutter/base/util/icon_text.dart'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; -import 'package:campus_flutter/lectureComponent/views/lecture_details_view.dart'; import 'package:campus_flutter/base/enums/search_category.dart'; import 'package:campus_flutter/searchComponent/viewModels/searchableViewModels/calendar_search_viewmodel.dart'; import 'package:campus_flutter/searchComponent/views/appWideSearch/search_result_card_view.dart'; import 'package:campus_flutter/base/extensions/context.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; class CalendarSearchResultView extends ConsumerWidget { const CalendarSearchResultView({super.key}); @@ -28,7 +28,7 @@ class CalendarSearchResultView extends ConsumerWidget { style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.secondary, ), - iconColor: Theme.of(context).primaryColor, + iconColor: context.primaryColor, ), IconText( iconData: Icons.location_pin, @@ -36,27 +36,11 @@ class CalendarSearchResultView extends ConsumerWidget { style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.secondary, ), - iconColor: Theme.of(context).primaryColor, + iconColor: context.primaryColor, ), ], ), - // TODO: - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => Scaffold( - appBar: AppBar( - leading: const CustomBackButton(), - ), - body: SafeArea( - child: LectureDetailsView( - event: calendarEvent, - ), - ), - ), - ), - ); - }, + onTap: () => context.push(lectureDetails, extra: (null, calendarEvent)), ), ); } diff --git a/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart b/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart index 6669fd28..b25000e2 100644 --- a/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart +++ b/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart @@ -1,5 +1,6 @@ import 'package:campus_flutter/base/enums/appearance.dart'; import 'package:campus_flutter/base/enums/user_preference.dart'; +import 'package:campus_flutter/base/extensions/context.dart'; import 'package:campus_flutter/base/util/icon_text.dart'; import 'package:campus_flutter/main.dart'; import 'package:campus_flutter/settingsComponent/service/user_preferences_service.dart'; @@ -31,6 +32,8 @@ class UserPreferencesViewModel { ref.read(useWebView.notifier).state = value as bool; case UserPreference.failedGrades: ref.read(hideFailedGrades.notifier).state = value as bool; + case UserPreference.weekends: + ref.read(showWeekends.notifier).state = value as bool; case UserPreference.locale: ref.read(customLocale.notifier).state = Locale(value as String); default: @@ -51,6 +54,8 @@ class UserPreferencesViewModel { ref.read(useWebView.notifier).state = value as bool; case UserPreference.failedGrades: ref.read(hideFailedGrades.notifier).state = value as bool; + case UserPreference.weekends: + ref.read(showWeekends.notifier).state = value as bool; case UserPreference.locale: ref.read(customLocale.notifier).state = value as Locale?; value = value?.languageCode; @@ -75,7 +80,7 @@ class UserPreferencesViewModel { value: e, child: IconText( iconData: e.icon, - iconColor: Theme.of(context).primaryColor, + iconColor: context.primaryColor, label: Localizations.localeOf(context).languageCode == "de" ? e.german : e.english, diff --git a/lib/settingsComponent/views/appearance_settings_view.dart b/lib/settingsComponent/views/appearance_settings_view.dart index 0a3c1bcb..4eaf7041 100644 --- a/lib/settingsComponent/views/appearance_settings_view.dart +++ b/lib/settingsComponent/views/appearance_settings_view.dart @@ -4,6 +4,7 @@ import 'package:campus_flutter/base/enums/appearance.dart'; import 'package:campus_flutter/base/enums/user_preference.dart'; import 'package:campus_flutter/base/extensions/context.dart'; import 'package:campus_flutter/base/views/seperated_list.dart'; +import 'package:campus_flutter/calendarComponent/views/calendars_view.dart'; import 'package:campus_flutter/gradeComponent/viewModels/grade_viewmodel.dart'; import 'package:campus_flutter/homeComponent/widgetComponent/views/widget_frame_view.dart'; import 'package:campus_flutter/main.dart'; @@ -11,6 +12,7 @@ import 'package:campus_flutter/settingsComponent/viewModels/user_preferences_vie import 'package:campus_flutter/settingsComponent/views/settings_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:syncfusion_flutter_calendar/calendar.dart'; class AppearanceSettingsView extends ConsumerWidget { const AppearanceSettingsView({super.key}); @@ -25,6 +27,7 @@ class AppearanceSettingsView extends ConsumerWidget { _appearanceSelection(context, ref), if (Platform.isIOS) _useWebView(context, ref), _hideFailedGrades(context, ref), + _showWeeks(context, ref), ], ), ), @@ -92,4 +95,25 @@ class AppearanceSettingsView extends ConsumerWidget { ), ); } + + Widget _showWeeks(BuildContext context, WidgetRef ref) { + return ListTile( + dense: true, + title: Text( + context.localizations.showWeekends, + style: Theme.of(context).textTheme.bodyMedium, + ), + trailing: Switch( + value: ref.watch(showWeekends), + onChanged: (value) { + ref.read(userPreferencesViewModel).savePreference( + UserPreference.weekends, + value, + ); + calendarsKey.currentState?.weekController.view = + value ? CalendarView.week : CalendarView.workWeek; + }, + ), + ); + } } diff --git a/lib/settingsComponent/views/general_settings_view.dart b/lib/settingsComponent/views/general_settings_view.dart index 0d7578a0..9acfb478 100644 --- a/lib/settingsComponent/views/general_settings_view.dart +++ b/lib/settingsComponent/views/general_settings_view.dart @@ -34,7 +34,7 @@ class GeneralSettingsView extends ConsumerWidget { Widget _tokenPermission(BuildContext context) { return ListTile( dense: true, - leading: Icon(Icons.key, size: 20, color: Theme.of(context).primaryColor), + leading: Icon(Icons.key, size: 20, color: context.primaryColor), title: Text( context.localizations.tokenPermissions, style: Theme.of(context).textTheme.bodyMedium, @@ -50,7 +50,7 @@ class GeneralSettingsView extends ConsumerWidget { leading: Icon( Icons.language, size: 20, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), title: Text( context.localizations.language, @@ -87,7 +87,7 @@ class GeneralSettingsView extends ConsumerWidget { leading: Icon( Icons.settings, size: 20, - color: Theme.of(context).primaryColor, + color: context.primaryColor, ), title: Text(context.localizations.deviceSettings), trailing: const Icon(Icons.arrow_forward_ios, size: 15), diff --git a/lib/settingsComponent/views/settings_view.dart b/lib/settingsComponent/views/settings_view.dart index b2883252..c0ce5f62 100644 --- a/lib/settingsComponent/views/settings_view.dart +++ b/lib/settingsComponent/views/settings_view.dart @@ -1,5 +1,6 @@ import 'package:campus_flutter/base/enums/credentials.dart'; import 'package:campus_flutter/base/routing/routes.dart'; +import 'package:campus_flutter/base/util/padded_divider.dart'; import 'package:campus_flutter/homeComponent/widgetComponent/views/widget_frame_view.dart'; import 'package:campus_flutter/onboardingComponent/viewModels/onboarding_viewmodel.dart'; import 'package:campus_flutter/settingsComponent/views/appearance_settings_view.dart'; @@ -13,6 +14,7 @@ import 'package:package_info_plus/package_info_plus.dart'; final useWebView = StateProvider((ref) => true); final hideFailedGrades = StateProvider((ref) => false); +final showWeekends = StateProvider((ref) => false); class SettingsView extends ConsumerWidget { const SettingsView({super.key}); @@ -34,7 +36,7 @@ class SettingsView extends ConsumerWidget { child: Column( children: [ const ContactView(), - _authenticationButton(context, ref), + _resetButtons(context, ref), _versionNumberText(), ], ), @@ -47,49 +49,77 @@ class SettingsView extends ConsumerWidget { const GeneralSettingsView(), const AppearanceSettingsView(), const ContactView(), - _authenticationButton(context, ref), + _resetButtons(context, ref), _versionNumberText(), ], ); } } - Widget _authenticationButton(BuildContext context, WidgetRef ref) { - final login = ref.read(onboardingViewModel).credentials.value; + Widget _resetButtons(BuildContext context, WidgetRef ref) { + final List widgets = [ + _resetPreferencesButton(context, ref), + _resetAllButton(context, ref), + ]; return WidgetFrameView( - child: GestureDetector( - onTap: () { - if (login != Credentials.none) { - ref.read(onboardingViewModel).logout(ref); - } - context.go(onboarding); - }, - child: Card( - child: ListTile( - dense: true, - title: login != Credentials.tumId - ? Text( - context.localizations.login, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Colors.green, - fontWeight: FontWeight.w500, - ), - textAlign: TextAlign.center, - ) - : Text( - context.localizations.reset, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Colors.red, - fontWeight: FontWeight.w500, - ), - textAlign: TextAlign.center, - ), - ), + child: Card( + child: ListView.separated( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) => widgets[index], + separatorBuilder: (context, index) => const PaddedDivider(), + itemCount: widgets.length, ), ), ); } + Widget _resetPreferencesButton(BuildContext context, WidgetRef ref) { + return ListTile( + onTap: () => ref.read(onboardingViewModel).resetPreferences(ref), + dense: true, + title: Text( + context.localizations.resetPreferences, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Colors.red, + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ), + ); + } + + Widget _resetAllButton(BuildContext context, WidgetRef ref) { + final loginStatus = ref.read(onboardingViewModel).credentials.value; + return ListTile( + dense: true, + title: loginStatus != Credentials.tumId + ? Text( + context.localizations.login, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Colors.green, + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ) + : Text( + context.localizations.resetAll, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Colors.red, + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ), + onTap: () { + if (loginStatus != Credentials.none) { + ref.read(onboardingViewModel).logout(ref); + } + context.go(onboarding); + }, + ); + } + Widget _versionNumberText() { return Center( child: FutureBuilder( diff --git a/lib/studentCardComponent/views/information_view.dart b/lib/studentCardComponent/views/information_view.dart index 022deb6e..07ebff38 100644 --- a/lib/studentCardComponent/views/information_view.dart +++ b/lib/studentCardComponent/views/information_view.dart @@ -108,7 +108,7 @@ class InformationView extends StatelessWidget { style: Theme.of(context) .textTheme .titleLarge - ?.apply(color: Theme.of(context).primaryColor), + ?.apply(color: context.primaryColor), ); } @@ -118,7 +118,7 @@ class InformationView extends StatelessWidget { style: Theme.of(context) .textTheme .titleLarge - ?.copyWith(color: Theme.of(context).primaryColor), + ?.copyWith(color: context.primaryColor), ); } diff --git a/lib/studentCardComponent/views/student_card_view.dart b/lib/studentCardComponent/views/student_card_view.dart index 1b6e1505..980e1713 100644 --- a/lib/studentCardComponent/views/student_card_view.dart +++ b/lib/studentCardComponent/views/student_card_view.dart @@ -76,17 +76,17 @@ class StudentCardView extends ConsumerWidget { Widget _warningCard(BuildContext context) { return CardWithPadding( elevation: 0, - color: Theme.of(context).primaryColor.withOpacity(0.2), + color: context.primaryColor.withOpacity(0.2), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Icon(Icons.warning, color: Theme.of(context).primaryColor), + Icon(Icons.warning, color: context.primaryColor), const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0)), Expanded( child: Text( context.localizations.currentlyInBeta, - style: TextStyle(color: Theme.of(context).primaryColor), + style: TextStyle(color: context.primaryColor), textAlign: TextAlign.center, ), ), diff --git a/protos/tumdev/campus_backend.proto b/protos/tumdev/campus_backend.proto index 9c587da2..4ce9a519 100644 --- a/protos/tumdev/campus_backend.proto +++ b/protos/tumdev/campus_backend.proto @@ -472,6 +472,8 @@ message CreateFeedbackRequest { Recipient recipient = 1; // the email address of the user string from_email = 2; + // how the person wants to be called + string from_name = 8; // The actual message string message = 3; // Optional location which the user can choose (data protection) to attach or not diff --git a/pubspec.lock b/pubspec.lock index 938648ba..ff266fb2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "53d06f578b8e988f60324f46fcd6ab919ccdc2dc8cbf0cd4161829b1dba7a62b" + sha256: "0cb43f83f36ba8cb20502dee0c205e3f3aafb751732d724aeac3f2e044212cc2" url: "https://pub.dev" source: hosted - version: "1.3.27" + version: "1.3.29" analyzer: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: built_value - sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.1" + version: "8.9.2" cached_network_image: dependency: "direct main" description: @@ -269,10 +269,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: "50fb435ed30c6d2525cbfaaa0f46851ea6131315f213c0d921b0e407b34e3b84" + sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91 url: "https://pub.dev" source: hosted - version: "10.0.1" + version: "10.1.0" device_info_plus_platform_interface: dependency: transitive description: @@ -317,10 +317,10 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "4e8728edb3053ffcc194315cb0c10f4676947db793581409e36040065918c94f" + sha256: a864d1b6afd25497a3b57b016886d1763df52baaa69758a46723164de8d187fe url: "https://pub.dev" source: hosted - version: "2.27.2" + version: "2.29.0" firebase_core_platform_interface: dependency: transitive description: @@ -333,26 +333,26 @@ packages: dependency: transitive description: name: firebase_core_web - sha256: "6afef1b46818eabdc6058df1148307f80e5653c0eaf26beeec693c89154752d4" + sha256: c8b02226e548f35aace298e2bb2e6c24e34e8a203d614e742bb1146e5a4ad3c8 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.15.0" firebase_crashlytics: dependency: "direct main" description: name: firebase_crashlytics - sha256: "7ba408d144ebd2d6426fe9830536db7c94809521956e695f21c6a245fea10a33" + sha256: a4e2c0ef8a595d2fbbaa325ffb15179583db3a01da8ffc2ecd97a46d76ae7546 url: "https://pub.dev" source: hosted - version: "3.4.20" + version: "3.5.1" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: "206dde24e1e69250df19d8a3120566581066a862a75ce2ed6a09c822d9ef9228" + sha256: "897e8814773b83848ce8967b94d1ad5e780671253d3cd7862bf4a442f29db811" url: "https://pub.dev" source: hosted - version: "3.6.27" + version: "3.6.29" fixnum: dependency: transitive description: @@ -374,6 +374,15 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.1" + flutter_colorpicker: + dependency: "direct main" + description: + path: "." + ref: master + resolved-ref: "92bdb69a313a56c391ef148c12ef6539bd31253d" + url: "https://github.com/mchome/flutter_colorpicker.git" + source: git + version: "1.0.3" flutter_linkify: dependency: "direct main" description: @@ -407,10 +416,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + sha256: "592dc01a18961a51c24ae5d963b724b2b7fa4a95c100fe8eb6ca8a5a4732cadf" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.18" flutter_riverpod: dependency: "direct main" description: @@ -553,10 +562,10 @@ packages: dependency: "direct main" description: name: get_it - sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + sha256: "36524bfb3f0b4ec952c3202466fdd69ad1f7ac1dd9b0a7564177707e45bfaeb9" url: "https://pub.dev" source: hosted - version: "7.6.7" + version: "7.6.8" glob: dependency: transitive description: @@ -569,10 +578,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "5ed2687bc961f33a752017ccaa7edead3e5601b28b6376a5901bf24728556b85" + sha256: f6ba8eed5fa831e461122de577d4a26674a1d836e2956abe6c0f6c4d952e6673 url: "https://pub.dev" source: hosted - version: "13.2.2" + version: "13.2.3" google_identity_services_web: dependency: transitive description: @@ -610,7 +619,7 @@ packages: description: path: "packages/google_maps_flutter/google_maps_flutter_ios" ref: main - resolved-ref: "76ec0f6a67acefeff16dba1dcbd3ec7323ec7883" + resolved-ref: "33c1f4f32a84058e49f0eef62a7219405bccf398" url: "https://github.com/jakobkoerber/packages.git" source: git version: "2.5.2" @@ -659,10 +668,10 @@ packages: dependency: "direct main" description: name: home_widget - sha256: "29565bfee4b32eaf9e7e8b998d504618b779a74b2b1ac62dd4dac7468e66f1a3" + sha256: c58a9e6d3b94490f1a8d5ddcbeeeeebc79abd0befe5889c26b0713fb09be6857 url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.4.1" html: dependency: transitive description: @@ -843,10 +852,10 @@ packages: dependency: "direct main" description: name: map_launcher - sha256: b9c11a1d32740ef8393559148716cc0fec38a569fdcf3fb569375114cf30988a + sha256: "00627d34724dcaabb613c0a4ce08aa5887865a9516de37f238ed49c84345d12b" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.3.0" matcher: dependency: transitive description: @@ -907,18 +916,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: cb44f49b6e690fa766f023d5b22cac6b9affe741dd792b6ac7ad4fabe0d7b097 + sha256: "2c582551839386fa7ddbc7770658be7c0f87f388a4bff72066478f597c34d17f" url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "7.0.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.0" path: dependency: transitive description: @@ -947,10 +956,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: "51f0d2c554cfbc9d6a312ab35152fc77e2f0b758ce9f1a444a3a1e5b8f3c6b7f" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" path_provider_foundation: dependency: transitive description: @@ -1059,10 +1068,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333" url: "https://pub.dev" source: hosted - version: "3.7.4" + version: "3.8.0" pool: dependency: transitive description: @@ -1312,10 +1321,10 @@ packages: dependency: transitive description: name: sqflite - sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + sha256: "5ce2e1a15e822c3b4bfb5400455775e421da7098eed8adc8f26298ada7c9308c" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" sqflite_common: dependency: transitive description: @@ -1368,34 +1377,34 @@ packages: dependency: "direct main" description: name: syncfusion_flutter_calendar - sha256: "358fa20fb8e6348e10087d8bc610c470d74386e301bf13aa385460905f20d8b1" + sha256: "74a0ea2350dec01b14a9e2df511d7bfc079f3546c3b623c9bfe02b9af9061d8b" url: "https://pub.dev" source: hosted - version: "25.1.37+1" + version: "25.1.39" syncfusion_flutter_charts: dependency: "direct main" description: name: syncfusion_flutter_charts - sha256: c702a611ebb21f13b7107a470d3751ed852a1ec5de0cae7ef9339ccb761b574f + sha256: d80656b44dfc24e42affae9e2ad0741c7480454ca414df7541c3def387299d27 url: "https://pub.dev" source: hosted - version: "25.1.37" + version: "25.1.39+1" syncfusion_flutter_core: dependency: "direct main" description: name: syncfusion_flutter_core - sha256: d098e3cf5ee0c5a37b083f2efdb7c6bdfaabf871f68758bb491b10b61b3dd0d7 + sha256: "159b125f55d95534c0c39a5efd644f50a310821191946e15eac50a49032fb42c" url: "https://pub.dev" source: hosted - version: "25.1.37" + version: "25.1.39" syncfusion_flutter_datepicker: dependency: "direct main" description: name: syncfusion_flutter_datepicker - sha256: e5b41308be78c10fe90d7ca5cd60017d2b70bafb756a4cc18f43617c8eaeb069 + sha256: "742bbe6aba9df10553a177e3f6e4a3c07bbea39244e3af3f898864823b003de9" url: "https://pub.dev" source: hosted - version: "25.1.37" + version: "25.1.39" synchronized: dependency: transitive description: @@ -1552,10 +1561,10 @@ packages: dependency: "direct main" description: name: uuid - sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" url: "https://pub.dev" source: hosted - version: "4.3.3" + version: "4.4.0" vector_graphics: dependency: transitive description: @@ -1592,10 +1601,10 @@ packages: dependency: "direct main" description: name: video_player - sha256: afc65f4b8bcb2c188f64a591f84fb471f4f2e19fc607c65fd8d2f8fedb3dec23 + sha256: efa2e24042166906ddf836dd131258d0371d0009cdf0476f6a83fd992a17f5d0 url: "https://pub.dev" source: hosted - version: "2.8.3" + version: "2.8.5" video_player_android: dependency: transitive description: @@ -1656,10 +1665,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.4.5" webkit_inspection_protocol: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ed863e99..37af1336 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: campus_flutter description: "A new Flutter project." publish_to: 'none' -version: 5.0.1+1 +version: 5.0.2+1 environment: sdk: '>=3.2.3 <4.0.0' @@ -37,7 +37,7 @@ dependencies: flutter_staggered_grid_view: ^0.7.0 flutter_svg: ^2.0.9 flutter_linkify: ^6.0.0 - home_widget: ^0.5.0 + home_widget: "0.4.1" auto_size_text: ^3.0.0 quick_actions: ^1.0.7 flutter_native_splash: ^2.2.19 @@ -50,12 +50,16 @@ dependencies: barcode_widget: ^2.0.4 lottie: ^3.0.0 timeago: ^3.4.0 + flutter_colorpicker: + git: + url: https://github.com/mchome/flutter_colorpicker.git + ref: master # helpers device_info_plus: ^10.0.1 flutter_secure_storage: ^9.0.0 geolocator: ^11.0.0 - package_info_plus: ^6.0.0 + package_info_plus: ^7.0.0 path_provider: ^2.0.15 url_launcher: ^6.1.10 permission_handler: ^11.1.0