Merge remote-tracking branch 'origin/develop' into develop-customTimetableEvents

This commit is contained in:
2024-02-09 16:42:45 +01:00
21 changed files with 208 additions and 188 deletions

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:marianum_mobile/api/mhsl/server/feedback/addFeedback.dart';
import 'package:marianum_mobile/api/mhsl/server/feedback/addFeedbackParams.dart';
import 'package:marianum_mobile/model/accountData.dart';
import 'package:package_info/package_info.dart';
class FeedbackDialog extends StatefulWidget {
const FeedbackDialog({super.key});
@override
State<FeedbackDialog> createState() => _FeedbackDialogState();
}
class _FeedbackDialogState extends State<FeedbackDialog> {
final TextEditingController _feedbackInput = TextEditingController();
String? _error;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text("Feedback"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text("Feedback, Anregungen, Ideen, Fehler und Verbesserungen"),
const SizedBox(height: 10),
const Text("Bitte gib keine geheimen Daten wie z.B. Passwörter weiter.", style: TextStyle(fontSize: 10)),
const SizedBox(height: 10),
TextField(
controller: _feedbackInput,
autofocus: true,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("Feedback und Verbesserungen")
),
// style: TextStyle(),
// expands: true,
minLines: 3,
maxLines: 5,
),
Visibility(
visible: _error != null,
child: Text("Senden fehlgeschlagen: $_error", style: const TextStyle(color: Colors.red))
)
],
),
actions: [
TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text("Abbrechen")),
TextButton(
onPressed: () async {
AddFeedback(
AddFeedbackParams(
user: AccountData().getUserId(),
feedback: _feedbackInput.text,
appVersion: int.parse((await PackageInfo.fromPlatform()).buildNumber)
)
)
.run()
.then((value) => Navigator.of(context).pop())
.catchError((error, trace) {
setState(() {
_error = error.toString();
});
});
},
child: const Text("Senden"),
)
],
);
}
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
import 'package:marianum_mobile/view/pages/more/feedback/feedbackDialog.dart';
import 'package:marianum_mobile/widget/centeredLeading.dart';
import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
import '../../../widget/ListItem.dart';
import '../../settings/settings.dart';
@ -20,7 +22,7 @@ class Overhang extends StatelessWidget {
appBar: AppBar(
title: const Text("Mehr"),
actions: [
IconButton(onPressed: () => PersistentNavBarNavigator.pushNewScreen(context, screen: const Settings(), withNavBar: false), icon: const Icon(Icons.settings))
IconButton(onPressed: () => pushNewScreen(context, screen: const Settings(), withNavBar: false), icon: const Icon(Icons.settings))
],
),
body: ListView(
@ -36,6 +38,13 @@ class Overhang extends StatelessWidget {
trailing: const Icon(Icons.arrow_right),
onTap: () => showDialog(context: context, builder: (context) => const SelectShareTypeDialog())
),
ListTile(
leading: const CenteredLeading(Icon(Icons.feedback_outlined)),
title: const Text("Du hast eine Idee?"),
subtitle: const Text("Fehler und Verbessungsvorschläge"),
trailing: const Icon(Icons.arrow_right),
onTap: () => showDialog(context: context, barrierDismissible: false, builder: (context) => const FeedbackDialog()),
)
],
),
);

View File

@ -22,12 +22,11 @@ class SelectShareTypeDialog extends StatelessWidget {
),
ListTile(
leading: const Icon(Icons.link_outlined),
title: const Text("Per Link"),
title: const Text("Per Link teilen"),
trailing: const Icon(Icons.arrow_right),
onTap: () {
final box = context.findRenderObject() as RenderBox?;
Share.share(
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
sharePositionOrigin: Rect.fromLTWH(0, 0, MediaQuery.of(context).size.width, MediaQuery.of(context).size.height / 2),
subject: "App Teilen",
"Hol dir die für das Marianum maßgeschneiderte App:"
"\n\nAndroid: https://play.google.com/store/apps/details?id=eu.mhsl.marianum.mobile.client "

View File

@ -84,9 +84,8 @@ class _ChatTextfieldState extends State<ChatTextfield> {
Align(
alignment: Alignment.bottomLeft,
child: Container(
padding: const EdgeInsets.only(left: 10, bottom: 1, top: 1, right: 10),
padding: const EdgeInsets.only(left: 10, bottom: 3, top: 3, right: 10),
width: double.infinity,
color: Theme.of(context).primaryColor,
child: Row(
children: <Widget>[
GestureDetector(
@ -135,7 +134,7 @@ class _ChatTextfieldState extends State<ChatTextfield> {
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(30),
),
child: const Icon(Icons.add, color: Colors.white, size: 20, ),
child: const Icon(Icons.attach_file_outlined, color: Colors.white, size: 20, ),
),
)
),
@ -144,18 +143,13 @@ class _ChatTextfieldState extends State<ChatTextfield> {
child: TextField(
autocorrect: true,
textCapitalization: TextCapitalization.sentences,
style: const TextStyle(
color: Colors.white,
),
controller: _textBoxController,
maxLines: 7,
minLines: 1,
decoration: InputDecoration(
decoration: const InputDecoration(
hintText: "Nachricht schreiben...",
hintStyle: TextStyle(color: Theme.of(context).colorScheme.onSecondary),
border: InputBorder.none,
),
cursorColor: Colors.white,
onChanged: (String text) {
if(text.trim().toLowerCase() == "marbot marbot marbot") {
var newText = "Roboter sind cool und so, aber marbots sind besser!";

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_split_view/flutter_split_view.dart';
import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
class TalkNavigator {
static bool hasSplitViewState(BuildContext context) => context.findAncestorStateOfType<SplitViewState>() != null;
@ -12,7 +12,7 @@ class TalkNavigator {
SplitViewState splitView = SplitView.of(context);
overrideToSingleSubScreen ? splitView.setSecondary(view) : splitView.push(view);
} else {
PersistentNavBarNavigator.pushNewScreen(context, screen: view, withNavBar: false);
pushNewScreen(context, screen: view, withNavBar: false);
}
}
}

View File

@ -18,10 +18,6 @@ class _AppointmentComponentState extends State<AppointmentComponent> {
Widget build(BuildContext context) {
final Appointment meeting = widget.details.appointments.first;
final appointmentHeight = widget.details.bounds.height;
double headerHeight = 50;
const double footerHeight = 5;
final double infoHeight = appointmentHeight - (headerHeight + footerHeight);
if (infoHeight < 0) headerHeight += infoHeight;
return Stack(
children: [
@ -29,14 +25,11 @@ class _AppointmentComponentState extends State<AppointmentComponent> {
children: [
Container(
padding: const EdgeInsets.all(3),
height: headerHeight,
height: appointmentHeight,
alignment: Alignment.topLeft,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(5),
),
borderRadius: const BorderRadius.all(Radius.circular(5)),
color: meeting.color,
),
child: SingleChildScrollView(
@ -60,7 +53,7 @@ class _AppointmentComponentState extends State<AppointmentComponent> {
FittedBox(
fit: BoxFit.fitWidth,
child: Text(
meeting.location ?? "?",
meeting.location ?? "-",
maxLines: 3,
overflow: TextOverflow.ellipsis,
softWrap: true,
@ -74,45 +67,6 @@ class _AppointmentComponentState extends State<AppointmentComponent> {
),
),
),
Visibility(
visible: meeting.notes != null && infoHeight > 10,
replacement: Container(
color: meeting.color,
height: infoHeight,
),
child: Container(
height: infoHeight,
padding: const EdgeInsets.fromLTRB(3, 5, 3, 2),
color: meeting.color.withOpacity(0.8),
alignment: Alignment.topLeft,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
meeting.notes ?? "",
style: const TextStyle(
color: Colors.white,
fontSize: 10,
),
)
],
),
),
),
),
Container(
height: footerHeight,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(5),
bottomRight: Radius.circular(5),
),
color: meeting.color,
),
),
],
),
Visibility(

View File

@ -3,7 +3,7 @@ import 'package:bottom_sheet/bottom_sheet.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
import '../../../api/webuntis/queries/getRooms/getRoomsResponse.dart';
@ -49,20 +49,18 @@ class AppointmentDetails {
maxHeaderHeight: 150,
context: context,
headerBuilder: (context, bottomSheetOffset) => Padding(
padding: const EdgeInsets.symmetric(vertical: 30),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("${_getEventPrefix(timetableData.code)}${subject.alternateName} - (${subject.longName})", style: const TextStyle(fontSize: 30)),
Text("${Jiffy.parseFromDateTime(appointment.startTime).format(pattern: "HH:mm")} - ${Jiffy.parseFromDateTime(appointment.endTime).format(pattern: "HH:mm")}", style: const TextStyle(fontSize: 15)),
],
),
headerBuilder: (context, bottomSheetOffset) => Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("${_getEventPrefix(timetableData.code)}${subject.alternateName} - (${subject.longName})", style: const TextStyle(fontSize: 25), overflow: TextOverflow.ellipsis),
Text("${Jiffy.parseFromDateTime(appointment.startTime).format(pattern: "HH:mm")} - ${Jiffy.parseFromDateTime(appointment.endTime).format(pattern: "HH:mm")}", style: const TextStyle(fontSize: 15)),
],
),
),
bodyBuilder: (context, bottomSheetOffset) => SliverChildListDelegate(
[
const Divider(),
ListTile(
leading: const Icon(Icons.notifications_active),
title: Text("Status: ${timetableData.code != null ? "Geändert" : "Regulär"}"),
@ -73,13 +71,15 @@ class AppointmentDetails {
trailing: IconButton(
icon: const Icon(Icons.house_outlined),
onPressed: () {
PersistentNavBarNavigator.pushNewScreen(context, withNavBar: false, screen: const Roomplan());
pushNewScreen(context, withNavBar: false, screen: const Roomplan());
},
),
),
ListTile(
leading: const Icon(Icons.person),
title: Text("Lehrkraft: ${timetableData.te[0].name} ${timetableData.te[0].longname.isNotEmpty ? "(${timetableData.te[0].longname})" : ""}"),
title: timetableData.te.isNotEmpty
? Text("Lehrkraft: ${timetableData.te[0].name} ${timetableData.te[0].longname.isNotEmpty ? "(${timetableData.te[0].longname})" : ""}")
: const Text("?"),
trailing: Visibility(
visible: !kReleaseMode,
child: IconButton(

View File

@ -163,10 +163,9 @@ class _TimetableState extends State<Timetable> {
}
List<TimeRegion> _buildSpecialTimeRegions(GetHolidaysResponse holidays) {
DateTime lastMonday = DateTime.now().subtract(Duration(days: DateTime.now().weekday - 1));
DateTime lastMonday = DateTime.now().subtract(const Duration(days: 14)).nextWeekday(DateTime.monday);
DateTime firstBreak = lastMonday.copyWith(hour: 10, minute: 15);
DateTime secondBreak = lastMonday.copyWith(hour: 13, minute: 50);
DateTime beforeSchool = lastMonday.copyWith(hour: 7, minute: 30);
Iterable<TimeRegion> holidayList = holidays.result.map((holiday) {
DateTime startDay = _parseWebuntisTimestamp(holiday.startDate, 0);
@ -200,7 +199,7 @@ class _TimetableState extends State<Timetable> {
TimeRegion(
startTime: firstBreak,
endTime: firstBreak.add(const Duration(minutes: 20)),
recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5',
recurrenceRule: 'FREQ=DAILY;INTERVAL=1',
text: 'centerIcon',
color: Theme.of(context).primaryColor.withAlpha(50),
iconData: Icons.restaurant
@ -210,20 +209,11 @@ class _TimetableState extends State<Timetable> {
TimeRegion(
startTime: secondBreak,
endTime: secondBreak.add(const Duration(minutes: 15)),
recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5',
recurrenceRule: 'FREQ=DAILY;INTERVAL=1',
text: 'centerIcon',
color: Theme.of(context).primaryColor.withAlpha(50),
iconData: Icons.restaurant
),
if(!isInHoliday(beforeSchool))
TimeRegion(
startTime: beforeSchool,
endTime: beforeSchool.add(const Duration(minutes: 25)),
recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5',
color: Theme.of(context).disabledColor.withAlpha(50),
text: "centerIcon",
),
];
}