#23 Upgrade MaterialUI

General UI improvements and cleanup
This commit is contained in:
Elias Müller 2024-02-07 21:17:30 +01:00
parent 538ebd27bf
commit 095b663bf1
11 changed files with 43 additions and 173 deletions

View File

@ -3,7 +3,7 @@ import 'dart:async';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
@ -75,11 +75,11 @@ class _AppState extends State<App> {
navBarStyle: NavBarStyle.style6, navBarStyle: NavBarStyle.style6,
hideNavigationBarWhenKeyboardShows: true, hideNavigationBarWhenKeyboardShows: true,
navBarHeight: MediaQuery.of(context).viewInsets.bottom > 0 ? 0.0 : kBottomNavigationBarHeight, navBarHeight: MediaQuery.of(context).viewInsets.bottom > 0 ? 0.0 : kBottomNavigationBarHeight,
backgroundColor: Theme.of(context).colorScheme.surface, backgroundColor: Theme.of(context).colorScheme.background,
decoration: const NavBarDecoration( decoration: const NavBarDecoration(
border: Border(top: BorderSide(width: 1, color: Colors.grey)), border: Border(top: BorderSide(width: 1, color: Colors.grey)),
), ),
screenTransitionAnimation: const ScreenTransitionAnimation(animateTabTransition: true, curve: Curves.ease, duration: Duration(milliseconds: 200)), screenTransitionAnimation: const ScreenTransitionAnimation(animateTabTransition: true, curve: Curves.ease, duration: Duration(milliseconds: 150)),
screens: const [ screens: const [
Breaker(breaker: BreakerArea.timetable, child: Timetable()), Breaker(breaker: BreakerArea.timetable, child: Timetable()),
Breaker(breaker: BreakerArea.talk, child: ChatList()), Breaker(breaker: BreakerArea.talk, child: ChatList()),

View File

@ -4,51 +4,10 @@ class DarkAppTheme {
static const Color marianumRed = Color.fromARGB(255, 153, 51, 51); static const Color marianumRed = Color.fromARGB(255, 153, 51, 51);
static final theme = ThemeData( static final theme = ThemeData(
useMaterial3: false, colorScheme: ColorScheme.fromSeed(
brightness: Brightness.dark, seedColor: marianumRed,
primaryColor: marianumRed,
hintColor: marianumRed,
colorScheme: const ColorScheme(
brightness: Brightness.dark, brightness: Brightness.dark,
surface: Colors.black54,
onSurface: Colors.white,
primary: marianumRed,
onPrimary: Colors.white,
secondary: Colors.grey,
onSecondary: Colors.white,
background: Colors.black26,
onBackground: Colors.white,
error: marianumRed,
onError: marianumRed,
),
inputDecorationTheme: const InputDecorationTheme(
border: UnderlineInputBorder(borderSide: BorderSide(color: marianumRed)),
),
appBarTheme: const AppBarTheme(
backgroundColor: marianumRed,
),
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: marianumRed,
),
iconButtonTheme: IconButtonThemeData(
style: ButtonStyle(
textStyle: MaterialStateProperty.all(const TextStyle(color: Colors.white)),
backgroundColor: MaterialStateProperty.all(Colors.white),
)
),
checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.selected) ? marianumRed : Colors.transparent),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: marianumRed.withOpacity(0.5),
),
), ),
primaryColor: marianumRed,
); );
} }

View File

@ -4,39 +4,10 @@ class LightAppTheme {
static const Color marianumRed = Color.fromARGB(255, 153, 51, 51); static const Color marianumRed = Color.fromARGB(255, 153, 51, 51);
static final theme = ThemeData( static final theme = ThemeData(
useMaterial3: false,
brightness: Brightness.light, brightness: Brightness.light,
primaryColor: marianumRed, colorScheme: ColorScheme.fromSeed(seedColor: marianumRed),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
colorScheme: const ColorScheme( foregroundColor: Colors.white
brightness: Brightness.light, )
surface: Colors.white,
onSurface: Colors.black,
secondary: Colors.grey,
onSecondary: Colors.white,
primary: marianumRed,
onPrimary: Colors.white,
background: Colors.white,
onBackground: Colors.black,
error: marianumRed,
onError: marianumRed,
),
inputDecorationTheme: const InputDecorationTheme(
border: UnderlineInputBorder(borderSide: BorderSide(color: marianumRed)),
),
appBarTheme: const AppBarTheme(
backgroundColor: marianumRed,
),
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: marianumRed,
),
checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.selected) ? marianumRed : Colors.transparent),
),
); );
} }

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
import '../../../widget/ListItem.dart'; import '../../../widget/ListItem.dart';
import '../../settings/settings.dart'; import '../../settings/settings.dart';
@ -20,7 +20,7 @@ class Overhang extends StatelessWidget {
appBar: AppBar( appBar: AppBar(
title: const Text("Mehr"), title: const Text("Mehr"),
actions: [ 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( body: ListView(

View File

@ -84,9 +84,8 @@ class _ChatTextfieldState extends State<ChatTextfield> {
Align( Align(
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
child: Container( 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, width: double.infinity,
color: Theme.of(context).primaryColor,
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
GestureDetector( GestureDetector(
@ -135,7 +134,7 @@ class _ChatTextfieldState extends State<ChatTextfield> {
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(30), 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( child: TextField(
autocorrect: true, autocorrect: true,
textCapitalization: TextCapitalization.sentences, textCapitalization: TextCapitalization.sentences,
style: const TextStyle(
color: Colors.white,
),
controller: _textBoxController, controller: _textBoxController,
maxLines: 7, maxLines: 7,
minLines: 1, minLines: 1,
decoration: InputDecoration( decoration: const InputDecoration(
hintText: "Nachricht schreiben...", hintText: "Nachricht schreiben...",
hintStyle: TextStyle(color: Theme.of(context).colorScheme.onSecondary),
border: InputBorder.none, border: InputBorder.none,
), ),
cursorColor: Colors.white,
onChanged: (String text) { onChanged: (String text) {
if(text.trim().toLowerCase() == "marbot marbot marbot") { if(text.trim().toLowerCase() == "marbot marbot marbot") {
var newText = "Roboter sind cool und so, aber marbots sind besser!"; 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/material.dart';
import 'package:flutter_split_view/flutter_split_view.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 { class TalkNavigator {
static bool hasSplitViewState(BuildContext context) => context.findAncestorStateOfType<SplitViewState>() != null; static bool hasSplitViewState(BuildContext context) => context.findAncestorStateOfType<SplitViewState>() != null;
@ -12,7 +12,7 @@ class TalkNavigator {
SplitViewState splitView = SplitView.of(context); SplitViewState splitView = SplitView.of(context);
overrideToSingleSubScreen ? splitView.setSecondary(view) : splitView.push(view); overrideToSingleSubScreen ? splitView.setSecondary(view) : splitView.push(view);
} else { } 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) { Widget build(BuildContext context) {
final Appointment meeting = widget.details.appointments.first; final Appointment meeting = widget.details.appointments.first;
final appointmentHeight = widget.details.bounds.height; 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( return Stack(
children: [ children: [
@ -29,14 +25,11 @@ class _AppointmentComponentState extends State<AppointmentComponent> {
children: [ children: [
Container( Container(
padding: const EdgeInsets.all(3), padding: const EdgeInsets.all(3),
height: headerHeight, height: appointmentHeight,
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.rectangle, shape: BoxShape.rectangle,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.all(Radius.circular(5)),
topLeft: Radius.circular(5),
topRight: Radius.circular(5),
),
color: meeting.color, color: meeting.color,
), ),
child: SingleChildScrollView( child: SingleChildScrollView(
@ -60,7 +53,7 @@ class _AppointmentComponentState extends State<AppointmentComponent> {
FittedBox( FittedBox(
fit: BoxFit.fitWidth, fit: BoxFit.fitWidth,
child: Text( child: Text(
meeting.location ?? "?", meeting.location ?? "-",
maxLines: 3, maxLines: 3,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
softWrap: true, 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( Visibility(

View File

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

View File

@ -156,10 +156,9 @@ class _TimetableState extends State<Timetable> {
} }
List<TimeRegion> _buildSpecialTimeRegions(GetHolidaysResponse holidays) { 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 firstBreak = lastMonday.copyWith(hour: 10, minute: 15);
DateTime secondBreak = lastMonday.copyWith(hour: 13, minute: 50); DateTime secondBreak = lastMonday.copyWith(hour: 13, minute: 50);
DateTime beforeSchool = lastMonday.copyWith(hour: 7, minute: 30);
Iterable<TimeRegion> holidayList = holidays.result.map((holiday) { Iterable<TimeRegion> holidayList = holidays.result.map((holiday) {
DateTime startDay = _parseWebuntisTimestamp(holiday.startDate, 0); DateTime startDay = _parseWebuntisTimestamp(holiday.startDate, 0);
@ -193,7 +192,7 @@ class _TimetableState extends State<Timetable> {
TimeRegion( TimeRegion(
startTime: firstBreak, startTime: firstBreak,
endTime: firstBreak.add(const Duration(minutes: 20)), endTime: firstBreak.add(const Duration(minutes: 20)),
recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5', recurrenceRule: 'FREQ=DAILY;INTERVAL=1',
text: 'centerIcon', text: 'centerIcon',
color: Theme.of(context).primaryColor.withAlpha(50), color: Theme.of(context).primaryColor.withAlpha(50),
iconData: Icons.restaurant iconData: Icons.restaurant
@ -203,20 +202,11 @@ class _TimetableState extends State<Timetable> {
TimeRegion( TimeRegion(
startTime: secondBreak, startTime: secondBreak,
endTime: secondBreak.add(const Duration(minutes: 15)), endTime: secondBreak.add(const Duration(minutes: 15)),
recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5', recurrenceRule: 'FREQ=DAILY;INTERVAL=1',
text: 'centerIcon', text: 'centerIcon',
color: Theme.of(context).primaryColor.withAlpha(50), color: Theme.of(context).primaryColor.withAlpha(50),
iconData: Icons.restaurant 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",
),
]; ];
} }

View File

@ -1,7 +1,9 @@
import 'package:filesize/filesize.dart'; import 'package:filesize/filesize.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -186,11 +188,11 @@ class _SettingsState extends State<Settings> {
context: context, context: context,
applicationIcon: const Icon(Icons.apps), applicationIcon: const Icon(Icons.apps),
applicationName: "MarianumMobile", applicationName: "MarianumMobile",
applicationVersion: "${appInfo.appName}\n\nPackage: ${appInfo.packageName}\n\nVersion: ${appInfo.version}\nBuild: ${appInfo.buildNumber}", applicationVersion: "${appInfo.appName}\n\nPackage: ${appInfo.packageName}\nVersion: ${appInfo.version}\nBuild: ${appInfo.buildNumber}",
applicationLegalese: "Dies ist ein Inoffizieller Nextcloud & Webuntis Client und wird nicht vom Marianum selbst betrieben.\n" applicationLegalese: "Dies ist ein Inoffizieller Nextcloud & Webuntis Client und wird nicht vom Marianum selbst betrieben.\n"
"Keinerlei Gewähr für Vollständigkeit, Richtigkeit und Aktualität!\n\n" "Keinerlei Gewähr für Vollständigkeit, Richtigkeit und Aktualität!\n\n"
"Development build\n" "${kReleaseMode ? "Production" : "Development"} build\n"
"Marianum Fulda 2023 Elias Müller", "Marianum Fulda 2023-${Jiffy.now().year}\nElias Müller",
); );
}); });
}, },

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 0.0.5+29 version: 0.0.6+30
environment: environment:
sdk: '>3.0.0' sdk: '>3.0.0'
@ -68,7 +68,7 @@ dependencies:
flowder: flowder:
git: git:
url: https://github.com/Harsh223/flowder.git url: https://github.com/Harsh223/flowder.git
persistent_bottom_nav_bar: ^5.0.2 persistent_bottom_nav_bar_v2: ^4.2.8
badges: ^3.0.2 badges: ^3.0.2
image_picker: ^1.0.0 image_picker: ^1.0.0
file_picker: ^6.1.1 file_picker: ^6.1.1