Skip to content

Commit

Permalink
User Interface Enhancements (#221)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobkoerber authored Mar 16, 2024
1 parent c8cfb6d commit 3e651f0
Show file tree
Hide file tree
Showing 174 changed files with 1,847 additions and 1,245 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/lint_test_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ jobs:
- name: Build Android
run: flutter build apk

- name: Build Website
run: flutter build web --base-href /
#- name: Build Website
# run: flutter build web --base-href /
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Check out our detailed information at [CONTRIBUTING.md](https://github.com/TCA-T
-->

## Beta
If you want to participate in the beta of this app, enter your details [here](https://testflight.apple.com/join/4Ddi6f2f) to get invited via TestFlight or [here](https://play.google.com/store/apps/details?id=de.tum.tca_flutter) to get invited via the Google Play Beta Program. You can also test the preliminary [web app](https://web.tum.app/). We would appreciate your feedback regarding bugs and improvement suggestions!
If you want to participate in the beta of this app, enter your details [here](https://testflight.apple.com/join/4Ddi6f2f) to get invited via TestFlight or [here](https://play.google.com/store/apps/details?id=de.tum.tca_flutter) to get invited via the Google Play Beta Program. We would appreciate your feedback regarding bugs and improvement suggestions!

## Policies
- [Privacy policy](https://app.tum.de/landing/privacy/)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.View
import android.widget.RemoteViews
import de.tum.`in`.tumcampus.MainActivity
import de.tum.`in`.tumcampus.R
import de.tum.`in`.tumcampus.util.deserializeStringToDate
import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetPlugin
import org.joda.time.DateTime
import org.joda.time.Days
import org.joda.time.LocalDate
import org.joda.time.format.DateTimeFormat
import org.ocpsoft.prettytime.PrettyTime
import java.util.Locale
Expand Down Expand Up @@ -48,32 +51,31 @@ private fun updateAppWidget(
val p = PrettyTime()
val widgetData = HomeWidgetPlugin.getData(context)
val lastSaved = widgetData.getString("calendar_save", null)
val lastSavedDate = p.format(deserializeStringToDate(lastSaved).toDate())
remoteViews.setTextViewText(R.id.calendar_widget_updated_on, lastSavedDate)
val lastSavedDate = deserializeStringToDate(lastSaved).toLocalDate()
val lastSavedDateString = p.format( deserializeStringToDate(lastSaved).toDate())
remoteViews.setTextViewText(R.id.calendar_widget_updated_on, lastSavedDateString)

// dee
val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("tumCampusApp://message?homeWidget=calendar"))
remoteViews.setOnClickPendingIntent(R.id.calendar_widget, pendingIntentWithData)

// Set up the calendar activity listeners
val pendingCalendarIntent = HomeWidgetLaunchIntent.getActivity(context, MainActivity::class.java, Uri.parse("/calendar"))
remoteViews.setOnClickPendingIntent(R.id.calendar_widget_header, pendingCalendarIntent)
remoteViews.setPendingIntentTemplate(R.id.calendar_widget_listview, pendingCalendarIntent)
if (Days.daysBetween(lastSavedDate, LocalDate.now()).days < 14) {
// Set up the intent that starts the calendarWidgetService
val intent = Intent(context, CalendarWidgetService::class.java)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))
remoteViews.setRemoteAdapter(R.id.calendar_widget_listview, intent)

// Set up the intent that starts the calendarWidgetService, which will
// provide the departure times for this station
val intent = Intent(context, CalendarWidgetService::class.java)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))
remoteViews.setRemoteAdapter(R.id.calendar_widget_listview, intent)

// The empty view is displayed when the collection has no items.
// It should be in the same layout used to instantiate the RemoteViews
// object above.
remoteViews.setEmptyView(R.id.calendar_widget_listview, R.id.empty_list_item)
// The empty view is displayed when the collection has no items.
// It should be in the same layout used to instantiate the RemoteViews
// object above.
remoteViews.setEmptyView(R.id.calendar_widget_listview, R.id.empty_list_item)
} else {
remoteViews.setViewVisibility(R.id.calendar_widget_listview, View.INVISIBLE)
remoteViews.setViewVisibility(R.id.old_data_item, View.VISIBLE)
}

// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
Expand Down
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions android/app/src/main/res/layout/calendar_widget.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@
android:visibility="gone"
tools:visibility="visible" />

<TextView
android:id="@+id/old_data_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/calendar_widget_old_data"
android:textAlignment="center"
android:textColor="@color/text_primary"
android:visibility="gone"
tools:visibility="visible" />

</FrameLayout>

</LinearLayout>
1 change: 1 addition & 0 deletions android/app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<string name="calendar_widget">Calendar Widget TUM</string>
<string name="calendar_widget_select_lectures">Vorlesungen auswählen</string>
<string name="calendar_widget_no_lectures">Keine Vorlesungen geplannt :)</string>
<string name="calendar_widget_old_data">Dieses Widget wurde zuletzt vor über 2 Wochen aktualisiert. Öffne die Applikation, um die Daten zu aktualisieren</string>
<string name="IN">in</string>
<string name="MINUTES">Minuten</string>
<string name="just_now">Jetzt</string>
Expand Down
1 change: 1 addition & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<string name="calendar_widget">calendar Widget TUM</string>
<string name="calendar_widget_select_lectures">Select lectures</string>
<string name="calendar_widget_no_lectures">No lectures planned :)</string>
<string name="calendar_widget_old_data">This widget was last updated over 2 weeks ago.Open the application to update the data</string>
<string name="IN">in</string>
<string name="MINUTES">minutes</string>
<string name="just_now">Just now</string>
Expand Down
4 changes: 2 additions & 2 deletions android/app/src/main/res/xml/calendar_widget_info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
android:minResizeHeight="110dp"
android:minWidth="180dp"
android:minResizeWidth="180dp"
android:previewImage="@drawable/example_appwidget_preview"
android:previewImage="@drawable/appwidget_preview"
android:previewLayout="@layout/calendar_widget"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen" />
<!-- android:targetCellWidth="1"
android:targetCellHeight="1" -->
android:targetCellHeight="1" -->
39 changes: 28 additions & 11 deletions ios/CalendarWidget/CalendarWidgetContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,29 @@
//

import SwiftUI
import WidgetKit

struct CalendarWidgetContent: View {
@Environment(\.colorScheme) var colorScheme

var availableItems: Int
var widgetFamily: WidgetFamily
var events: [Date: [CalendarEntry]] = [:]
var updatedAt: Date

init(entry: CalendarWidgetEntry) {
self.availableItems = entry.size == .systemLarge ? 5 : 2
self.widgetFamily = entry.size
self.updatedAt = entry.date
self.events = groupEntriesByDate(entries: Array(entry.entries.prefix(availableItems)))
}

private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.setLocalizedDateFormatFromTemplate("MMMM d, yyyy")
return formatter
}

var body: some View {
VStack {
VStack(alignment: .leading) {
Expand All @@ -40,20 +43,34 @@ struct CalendarWidgetContent: View {
.background(.accent)
.foregroundStyle(.white)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 2, trailing: 0))

ForEach(events.keys.sorted(), id: \.self) { eventDate in
ForEach((events[eventDate] ?? []).indices, id: \.self) { eventIndex in
let event = events[eventDate]![eventIndex]
CalendarEventView(event: event, color: event.eventColor, isFirst: eventIndex == 0)

if (events.isEmpty) {
Spacer()
Text("No lectures planned :)")
.font(.footnote)
.padding()
} else if (Date().timeIntervalSince(updatedAt) > (14 * 24 * 60 * 60)) {
// 14 days * 24 hours * 60 minutes * 60 seconds
Spacer()
Text(widgetFamily != .systemSmall ? "This widget was last updated over 2 weeks ago.\nOpen the application to update the data" : "Open the application to update the widget")
.font(.footnote)
.multilineTextAlignment(.center)
.padding()
} else {
ForEach(events.keys.sorted(), id: \.self) { eventDate in
ForEach((events[eventDate] ?? []).indices, id: \.self) { eventIndex in
let event = events[eventDate]![eventIndex]
CalendarEventView(event: event, color: event.eventColor, isFirst: eventIndex == 0)
}
}
}
Spacer()
}
}

func groupEntriesByDate(entries: [CalendarEntry]) -> [Date: [CalendarEntry]] {
var groupedEntries: [Date: [CalendarEntry]] = [:]

for entry in entries {
let calendar = Calendar.current
let startDateComponents = calendar.dateComponents([.year, .month, .day], from: entry.startDate)
Expand Down
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ PODS:
- GoogleUtilities/Privacy
- home_widget (0.0.1):
- Flutter
- isar_flutter_libs (1.0.0):
- Flutter
- map_launcher (0.0.1):
- Flutter
- nanopb (2.30910.0):
Expand Down Expand Up @@ -116,6 +118,7 @@ DEPENDENCIES:
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
- google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`)
- home_widget (from `.symlinks/plugins/home_widget/ios`)
- isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`)
- map_launcher (from `.symlinks/plugins/map_launcher/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
Expand Down Expand Up @@ -161,6 +164,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/google_maps_flutter_ios/ios"
home_widget:
:path: ".symlinks/plugins/home_widget/ios"
isar_flutter_libs:
:path: ".symlinks/plugins/isar_flutter_libs/ios"
map_launcher:
:path: ".symlinks/plugins/map_launcher/ios"
package_info_plus:
Expand Down Expand Up @@ -200,6 +205,7 @@ SPEC CHECKSUMS:
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
map_launcher: e325db1261d029ff33e08e03baccffe09593ffea
nanopb: 438bc412db1928dac798aa6fd75726007be04262
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
Expand Down
2 changes: 1 addition & 1 deletion ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1520;
LastUpgradeCheck = 1530;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
28C6B8952B6AEB8500DD5E9A = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
30 changes: 30 additions & 0 deletions ios/Runner/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,36 @@
}
}
}
},
"No lectures planned :)" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Keine Veranstaltungen geplant :)"
}
}
}
},
"Open the application to update the widget" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Öffne die Applikation, um das Widget zu aktualisieren"
}
}
}
},
"This widget was last updated over 2 weeks ago.\nOpen the application to update the data" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Dieses Widget wurde zuletzt vor über 2 Wochen aktualisiert.\nÖffne die Applikation, um die Daten zu aktualisieren"
}
}
}
}
},
"version" : "1.0"
Expand Down
1 change: 0 additions & 1 deletion lib/base/enums/user_preference.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ enum UserPreference {
theme(int),
browser(bool),
failedGrades(bool),
defaultMapsApplication(String),
locale(String);

final Type type;
Expand Down
13 changes: 12 additions & 1 deletion lib/base/errorHandling/error_handling_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:campus_flutter/base/enums/error_handling_view_type.dart';
import 'package:campus_flutter/base/errorHandling/campus_exception_router.dart';
import 'package:campus_flutter/base/errorHandling/default_error_router.dart';
import 'package:campus_flutter/base/errorHandling/dio_exception_router.dart';
import 'package:campus_flutter/base/errorHandling/grpc_error_router.dart';
import 'package:campus_flutter/base/errorHandling/search_exception_router.dart';
import 'package:campus_flutter/base/errorHandling/tum_online_api_exception_router.dart';
import 'package:campus_flutter/base/errorHandling/type_error_router.dart';
Expand All @@ -15,6 +16,7 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grpc/grpc.dart';

class ErrorHandlingRouter extends ConsumerWidget {
const ErrorHandlingRouter({
Expand Down Expand Up @@ -121,6 +123,15 @@ class ErrorHandlingRouter extends ConsumerWidget {
titleColor: titleColor,
bodyColor: bodyColor,
);
case GrpcError grpcError:
return GrpcErrorRouter(
grpcError: grpcError,
errorHandlingViewType: errorHandlingViewType,
retry: retry,
retryWithContext: retryWithContext,
titleColor: titleColor,
bodyColor: bodyColor,
);
default:
if (error != null) {
recordFlutterError(
Expand All @@ -141,7 +152,7 @@ class ErrorHandlingRouter extends ConsumerWidget {
}

void recordFlutterError(FlutterErrorDetails flutterErrorDetails) {
if (!kIsWeb && !kDebugMode) {
if (!kDebugMode) {
FirebaseCrashlytics.instance.recordFlutterFatalError(flutterErrorDetails);
}
}
Expand Down
34 changes: 34 additions & 0 deletions lib/base/errorHandling/grpc_error_router.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'package:campus_flutter/base/enums/error_handling_view_type.dart';
import 'package:campus_flutter/base/errorHandling/error_handling_view.dart';
import 'package:campus_flutter/base/extensions/context.dart';
import 'package:flutter/material.dart';
import 'package:grpc/grpc.dart';

class GrpcErrorRouter extends StatelessWidget with ErrorHandlingView {
GrpcErrorRouter({
super.key,
required this.grpcError,
required ErrorHandlingViewType errorHandlingViewType,
Future<dynamic> Function(bool)? retry,
Future<dynamic> Function(bool, BuildContext)? retryWithContext,
Color? titleColor,
Color? bodyColor,
}) {
this.errorHandlingViewType = errorHandlingViewType;
this.retry = retry;
this.retryWithContext = retryWithContext;
this.titleColor = titleColor;
this.bodyColor = bodyColor;
}

final GrpcError grpcError;

@override
Widget build(BuildContext context) {
return exceptionMessage(
context,
grpcError.message ?? context.localizations.unknownError,
null,
);
}
}
Loading

0 comments on commit 3e651f0

Please sign in to comment.