made app modules movable in their order
This commit is contained in:
parent
8868914a76
commit
d833cdb733
@ -3,7 +3,6 @@ import 'dart:convert';
|
|||||||
import 'package:localstore/localstore.dart';
|
import 'package:localstore/localstore.dart';
|
||||||
|
|
||||||
import 'apiResponse.dart';
|
import 'apiResponse.dart';
|
||||||
import 'webuntis/webuntisError.dart';
|
|
||||||
|
|
||||||
abstract class RequestCache<T extends ApiResponse?> {
|
abstract class RequestCache<T extends ApiResponse?> {
|
||||||
static const int cacheNothing = 0;
|
static const int cacheNothing = 0;
|
||||||
@ -40,7 +39,7 @@ abstract class RequestCache<T extends ApiResponse?> {
|
|||||||
'json': jsonEncode(newValue),
|
'json': jsonEncode(newValue),
|
||||||
'lastupdate': DateTime.now().millisecondsSinceEpoch
|
'lastupdate': DateTime.now().millisecondsSinceEpoch
|
||||||
});
|
});
|
||||||
} on WebuntisError catch(e) {
|
} on Exception catch(e) {
|
||||||
onError(e);
|
onError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
lib/app.dart
29
lib/app.dart
@ -8,7 +8,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'state/app/modules/app_modules.dart';
|
import 'state/app/modules/app_modules.dart';
|
||||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:badges/badges.dart' as badges;
|
|
||||||
|
|
||||||
import 'api/mhsl/breaker/getBreakers/getBreakersResponse.dart';
|
import 'api/mhsl/breaker/getBreakers/getBreakersResponse.dart';
|
||||||
import 'api/mhsl/server/userIndex/update/updateUserindex.dart';
|
import 'api/mhsl/server/userIndex/update/updateUserindex.dart';
|
||||||
@ -93,7 +92,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => PersistentTabView(
|
Widget build(BuildContext context) => Consumer<SettingsProvider>(builder: (context, settings, child) => PersistentTabView(
|
||||||
controller: Main.bottomNavigator,
|
controller: Main.bottomNavigator,
|
||||||
navBarOverlap: const NavBarOverlap.none(),
|
navBarOverlap: const NavBarOverlap.none(),
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
@ -101,29 +100,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||||||
|
|
||||||
screenTransitionAnimation: const ScreenTransitionAnimation(curve: Curves.easeOutQuad, duration: Duration(milliseconds: 200)),
|
screenTransitionAnimation: const ScreenTransitionAnimation(curve: Curves.easeOutQuad, duration: Duration(milliseconds: 200)),
|
||||||
tabs: [
|
tabs: [
|
||||||
AppModule.getModule(Modules.timetable).toBottomTab(context),
|
...AppModule.getBottomBarModules(context).map((e) => e.toBottomTab(context)),
|
||||||
AppModule.getModule(Modules.talk).toBottomTab(
|
|
||||||
context,
|
|
||||||
itemBuilder: (icon) => Consumer<ChatListProps>(
|
|
||||||
builder: (context, value, child) {
|
|
||||||
if(value.primaryLoading()) return Icon(icon);
|
|
||||||
var messages = value.getRoomsResponse.data.map((e) => e.unreadMessages).reduce((a, b) => a+b);
|
|
||||||
return badges.Badge(
|
|
||||||
showBadge: messages > 0,
|
|
||||||
position: badges.BadgePosition.topEnd(top: -3, end: -3),
|
|
||||||
stackFit: StackFit.loose,
|
|
||||||
badgeStyle: badges.BadgeStyle(
|
|
||||||
padding: const EdgeInsets.all(3),
|
|
||||||
badgeColor: Theme.of(context).primaryColor,
|
|
||||||
elevation: 1,
|
|
||||||
),
|
|
||||||
badgeContent: Text('$messages', style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold)),
|
|
||||||
child: Icon(icon),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
AppModule.getModule(Modules.files).toBottomTab(context),
|
|
||||||
|
|
||||||
PersistentTabConfig(
|
PersistentTabConfig(
|
||||||
screen: const Breaker(breaker: BreakerArea.more, child: Overhang()),
|
screen: const Breaker(breaker: BreakerArea.more, child: Overhang()),
|
||||||
@ -142,7 +119,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
@ -23,7 +23,11 @@ class _BreakerState extends State<Breaker> {
|
|||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
var blocked = value.isBlocked(widget.breaker);
|
var blocked = value.isBlocked(widget.breaker);
|
||||||
if(blocked != null) {
|
if(blocked != null) {
|
||||||
return PlaceholderView(icon: Icons.security_outlined, text: "Die App/ Dieser Bereich wurde als Schutzmaßnahme deaktiviert!\n\n${blocked.isEmpty ? "Es wurde vom Server kein Grund übermittelt." : blocked}");
|
return PlaceholderView(
|
||||||
|
icon: Icons.app_blocking_outlined,
|
||||||
|
text: 'Die App / Dieser Bereich ist zurzeit nicht verfügbar!\n\n'
|
||||||
|
"${blocked.isEmpty ? "Es wurde vom Server kein Grund übermittelt.\nAktualisiere die App und versuche es später erneut" : blocked}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return widget.child;
|
return widget.child;
|
||||||
|
@ -44,7 +44,7 @@ class NotificationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> onAppOpenedByNotification(RemoteMessage message, BuildContext context) async {
|
static Future<void> onAppOpenedByNotification(RemoteMessage message, BuildContext context) async {
|
||||||
NotificationTasks.navigateToTalk();
|
NotificationTasks.navigateToTalk(context);
|
||||||
NotificationTasks.updateProviders(context);
|
NotificationTasks.updateProviders(context);
|
||||||
|
|
||||||
DebugTile(context).run(() {
|
DebugTile(context).run(() {
|
||||||
|
@ -6,6 +6,7 @@ import 'package:provider/provider.dart';
|
|||||||
import '../main.dart';
|
import '../main.dart';
|
||||||
import '../model/chatList/chatListProps.dart';
|
import '../model/chatList/chatListProps.dart';
|
||||||
import '../model/chatList/chatProps.dart';
|
import '../model/chatList/chatProps.dart';
|
||||||
|
import '../state/app/modules/app_modules.dart';
|
||||||
|
|
||||||
class NotificationTasks {
|
class NotificationTasks {
|
||||||
static void updateBadgeCount(RemoteMessage notification) {
|
static void updateBadgeCount(RemoteMessage notification) {
|
||||||
@ -17,7 +18,9 @@ class NotificationTasks {
|
|||||||
Provider.of<ChatProps>(context, listen: false).run();
|
Provider.of<ChatProps>(context, listen: false).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void navigateToTalk() {
|
static void navigateToTalk(BuildContext context) {
|
||||||
Main.bottomNavigator.jumpToTab(1);
|
var talkTab = AppModule.getBottomBarModules(context).map((e) => e.module).toList().indexOf(Modules.talk);
|
||||||
|
if(talkTab == -1) return;
|
||||||
|
Main.bottomNavigator.jumpToTab(talkTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../../../api/mhsl/breaker/getBreakers/getBreakersResponse.dart';
|
import '../../../api/mhsl/breaker/getBreakers/getBreakersResponse.dart';
|
||||||
import '../../../model/breakers/Breaker.dart';
|
import '../../../model/breakers/Breaker.dart';
|
||||||
|
import '../../../model/chatList/chatListProps.dart';
|
||||||
|
import '../../../storage/base/settingsProvider.dart';
|
||||||
import '../../../view/pages/files/files.dart';
|
import '../../../view/pages/files/files.dart';
|
||||||
import '../../../view/pages/more/roomplan/roomplan.dart';
|
import '../../../view/pages/more/roomplan/roomplan.dart';
|
||||||
import '../../../view/pages/talk/chatList.dart';
|
import '../../../view/pages/talk/chatList.dart';
|
||||||
@ -12,38 +15,115 @@ import 'gradeAverages/view/grade_averages_view.dart';
|
|||||||
import 'holidays/view/holidays_view.dart';
|
import 'holidays/view/holidays_view.dart';
|
||||||
import 'marianumMessage/view/marianum_message_list_view.dart';
|
import 'marianumMessage/view/marianum_message_list_view.dart';
|
||||||
|
|
||||||
|
import 'package:badges/badges.dart' as badges;
|
||||||
|
|
||||||
class AppModule {
|
class AppModule {
|
||||||
|
Modules module;
|
||||||
String name;
|
String name;
|
||||||
IconData icon;
|
Widget Function() icon;
|
||||||
|
BreakerArea breakerArea;
|
||||||
Widget Function() create;
|
Widget Function() create;
|
||||||
|
|
||||||
AppModule(this.name, this.icon, this.create);
|
AppModule(this.module, {required this.name, required this.icon, this.breakerArea = BreakerArea.global, required this.create});
|
||||||
|
|
||||||
static Map<Modules, AppModule> modules() => {
|
static Map<Modules, AppModule> modules(BuildContext context, { showFiltered = false }) {
|
||||||
Modules.timetable: AppModule('Vertretung', Icons.calendar_month, Timetable.new),
|
var settings = Provider.of<SettingsProvider>(context, listen: false);
|
||||||
Modules.talk: AppModule('Talk', Icons.chat, ChatList.new),
|
var available = {
|
||||||
Modules.files: AppModule('Files', Icons.folder, Files.new),
|
Modules.timetable: AppModule(
|
||||||
Modules.marianumMessage: AppModule('Marianum Message', Icons.newspaper, MarianumMessageListView.new),
|
Modules.timetable,
|
||||||
Modules.roomPlan: AppModule('Raumplan', Icons.location_pin, Roomplan.new),
|
name: 'Vertretung',
|
||||||
Modules.gradeAveragesCalculator: AppModule('Notendurschnittsrechner', Icons.calculate, GradeAveragesView.new),
|
icon: () => Icon(Icons.calendar_month),
|
||||||
Modules.holidays: AppModule('Schulferien', Icons.flight, HolidaysView.new),
|
breakerArea: BreakerArea.timetable,
|
||||||
|
create: Timetable.new,
|
||||||
|
),
|
||||||
|
Modules.talk: AppModule(
|
||||||
|
Modules.talk,
|
||||||
|
name: 'Talk',
|
||||||
|
icon: () => Consumer<ChatListProps>(
|
||||||
|
builder: (context, value, child) {
|
||||||
|
if(value.primaryLoading()) return Icon(Icons.chat);
|
||||||
|
var messages = value.getRoomsResponse.data.map((e) => e.unreadMessages).reduce((a, b) => a+b);
|
||||||
|
return badges.Badge(
|
||||||
|
showBadge: messages > 0,
|
||||||
|
position: badges.BadgePosition.topEnd(top: -3, end: -3),
|
||||||
|
stackFit: StackFit.loose,
|
||||||
|
badgeStyle: badges.BadgeStyle(
|
||||||
|
padding: const EdgeInsets.all(3),
|
||||||
|
badgeColor: Theme.of(context).primaryColor,
|
||||||
|
elevation: 1,
|
||||||
|
),
|
||||||
|
badgeContent: Text('$messages', style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold)),
|
||||||
|
child: Icon(Icons.chat),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
breakerArea: BreakerArea.talk,
|
||||||
|
create: ChatList.new,
|
||||||
|
),
|
||||||
|
Modules.files: AppModule(
|
||||||
|
Modules.files,
|
||||||
|
name: 'Files',
|
||||||
|
icon: () => Icon(Icons.folder),
|
||||||
|
breakerArea: BreakerArea.files,
|
||||||
|
create: Files.new,
|
||||||
|
),
|
||||||
|
Modules.marianumMessage: AppModule(
|
||||||
|
Modules.marianumMessage,
|
||||||
|
name: 'Marianum Message',
|
||||||
|
icon: () => Icon(Icons.newspaper),
|
||||||
|
breakerArea: BreakerArea.more,
|
||||||
|
create: MarianumMessageListView.new,
|
||||||
|
),
|
||||||
|
Modules.roomPlan: AppModule(
|
||||||
|
Modules.roomPlan,
|
||||||
|
name: 'Raumplan',
|
||||||
|
icon: () => Icon(Icons.location_pin),
|
||||||
|
breakerArea: BreakerArea.more,
|
||||||
|
create: Roomplan.new,
|
||||||
|
),
|
||||||
|
Modules.gradeAveragesCalculator: AppModule(
|
||||||
|
Modules.gradeAveragesCalculator,
|
||||||
|
name: 'Notendurschnittsrechner',
|
||||||
|
icon: () => Icon(Icons.calculate),
|
||||||
|
breakerArea: BreakerArea.more,
|
||||||
|
create: GradeAveragesView.new,
|
||||||
|
),
|
||||||
|
Modules.holidays: AppModule(
|
||||||
|
Modules.holidays,
|
||||||
|
name: 'Schulferien',
|
||||||
|
icon: () => Icon(Icons.flight),
|
||||||
|
breakerArea: BreakerArea.more,
|
||||||
|
create: HolidaysView.new,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
static AppModule getModule(Modules module) => modules()[module]!;
|
if(!showFiltered) available.removeWhere((key, value) => settings.val().modulesSettings.hiddenModules.contains(key));
|
||||||
|
|
||||||
Widget toListTile(BuildContext context) => ListTile(
|
return { for (var element in settings.val().modulesSettings.moduleOrder.where((element) => available.containsKey(element))) element : available[element]! };
|
||||||
leading: CenteredLeading(Icon(icon)),
|
}
|
||||||
|
|
||||||
|
static List<AppModule> getBottomBarModules(BuildContext context) => modules(context).values.toList().getRange(0, 3).toList();
|
||||||
|
static List<AppModule> getOverhangModules(BuildContext context) => modules(context).values.skip(3).toList();
|
||||||
|
|
||||||
|
Widget toListTile(BuildContext context, {Key? key, bool isReorder = false, Function()? onVisibleChange, bool isVisible = true}) => ListTile(
|
||||||
|
key: key,
|
||||||
|
leading: CenteredLeading(icon()),
|
||||||
title: Text(name),
|
title: Text(name),
|
||||||
onTap: () => pushScreen(context, withNavBar: false, screen: create()),
|
onTap: isReorder ? null : () => pushScreen(context, withNavBar: false, screen: create()),
|
||||||
trailing: const Icon(Icons.arrow_right),
|
trailing: isReorder
|
||||||
|
? Row(mainAxisSize: MainAxisSize.min, children: [
|
||||||
|
IconButton(onPressed: onVisibleChange, icon: Icon(isVisible ? Icons.visibility_outlined : Icons.visibility_off_outlined)),
|
||||||
|
Icon(Icons.drag_handle_outlined)
|
||||||
|
])
|
||||||
|
: const Icon(Icons.arrow_right),
|
||||||
);
|
);
|
||||||
|
|
||||||
PersistentTabConfig toBottomTab(BuildContext context, {Widget Function(IconData icon)? itemBuilder}) => PersistentTabConfig(
|
PersistentTabConfig toBottomTab(BuildContext context, {Widget Function(IconData icon)? iconBuilder}) => PersistentTabConfig(
|
||||||
screen: Breaker(breaker: BreakerArea.global, child: create()),
|
screen: Breaker(breaker: breakerArea, child: create()),
|
||||||
item: ItemConfig(
|
item: ItemConfig(
|
||||||
activeForegroundColor: Theme.of(context).primaryColor,
|
activeForegroundColor: Theme.of(context).primaryColor,
|
||||||
inactiveForegroundColor: Theme.of(context).colorScheme.secondary,
|
inactiveForegroundColor: Theme.of(context).colorScheme.secondary,
|
||||||
icon: itemBuilder == null ? Icon(icon) : itemBuilder(icon),
|
icon: icon(),
|
||||||
title: name
|
title: name
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -4,6 +4,7 @@ import 'package:json_annotation/json_annotation.dart';
|
|||||||
import '../devTools/devToolsSettings.dart';
|
import '../devTools/devToolsSettings.dart';
|
||||||
import '../file/fileSettings.dart';
|
import '../file/fileSettings.dart';
|
||||||
import '../fileView/fileViewSettings.dart';
|
import '../fileView/fileViewSettings.dart';
|
||||||
|
import '../general/modulesSettings.dart';
|
||||||
import '../holidays/holidaysSettings.dart';
|
import '../holidays/holidaysSettings.dart';
|
||||||
import '../notification/notificationSettings.dart';
|
import '../notification/notificationSettings.dart';
|
||||||
import '../talk/talkSettings.dart';
|
import '../talk/talkSettings.dart';
|
||||||
@ -20,6 +21,7 @@ class Settings {
|
|||||||
ThemeMode appTheme;
|
ThemeMode appTheme;
|
||||||
bool devToolsEnabled;
|
bool devToolsEnabled;
|
||||||
|
|
||||||
|
ModulesSettings modulesSettings;
|
||||||
TimetableSettings timetableSettings;
|
TimetableSettings timetableSettings;
|
||||||
TalkSettings talkSettings;
|
TalkSettings talkSettings;
|
||||||
FileSettings fileSettings;
|
FileSettings fileSettings;
|
||||||
@ -31,6 +33,7 @@ class Settings {
|
|||||||
Settings({
|
Settings({
|
||||||
required this.appTheme,
|
required this.appTheme,
|
||||||
required this.devToolsEnabled,
|
required this.devToolsEnabled,
|
||||||
|
required this.modulesSettings,
|
||||||
required this.timetableSettings,
|
required this.timetableSettings,
|
||||||
required this.talkSettings,
|
required this.talkSettings,
|
||||||
required this.fileSettings,
|
required this.fileSettings,
|
||||||
|
@ -9,6 +9,8 @@ part of 'settings.dart';
|
|||||||
Settings _$SettingsFromJson(Map<String, dynamic> json) => Settings(
|
Settings _$SettingsFromJson(Map<String, dynamic> json) => Settings(
|
||||||
appTheme: Settings._themeFromJson(json['appTheme'] as String),
|
appTheme: Settings._themeFromJson(json['appTheme'] as String),
|
||||||
devToolsEnabled: json['devToolsEnabled'] as bool,
|
devToolsEnabled: json['devToolsEnabled'] as bool,
|
||||||
|
modulesSettings: ModulesSettings.fromJson(
|
||||||
|
json['modulesSettings'] as Map<String, dynamic>),
|
||||||
timetableSettings: TimetableSettings.fromJson(
|
timetableSettings: TimetableSettings.fromJson(
|
||||||
json['timetableSettings'] as Map<String, dynamic>),
|
json['timetableSettings'] as Map<String, dynamic>),
|
||||||
talkSettings:
|
talkSettings:
|
||||||
@ -28,6 +30,7 @@ Settings _$SettingsFromJson(Map<String, dynamic> json) => Settings(
|
|||||||
Map<String, dynamic> _$SettingsToJson(Settings instance) => <String, dynamic>{
|
Map<String, dynamic> _$SettingsToJson(Settings instance) => <String, dynamic>{
|
||||||
'appTheme': Settings._themeToJson(instance.appTheme),
|
'appTheme': Settings._themeToJson(instance.appTheme),
|
||||||
'devToolsEnabled': instance.devToolsEnabled,
|
'devToolsEnabled': instance.devToolsEnabled,
|
||||||
|
'modulesSettings': instance.modulesSettings.toJson(),
|
||||||
'timetableSettings': instance.timetableSettings.toJson(),
|
'timetableSettings': instance.timetableSettings.toJson(),
|
||||||
'talkSettings': instance.talkSettings.toJson(),
|
'talkSettings': instance.talkSettings.toJson(),
|
||||||
'fileSettings': instance.fileSettings.toJson(),
|
'fileSettings': instance.fileSettings.toJson(),
|
||||||
|
19
lib/storage/general/modulesSettings.dart
Normal file
19
lib/storage/general/modulesSettings.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
import '../../state/app/modules/app_modules.dart';
|
||||||
|
|
||||||
|
part 'modulesSettings.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class ModulesSettings {
|
||||||
|
List<Modules> moduleOrder;
|
||||||
|
List<Modules> hiddenModules;
|
||||||
|
|
||||||
|
ModulesSettings({
|
||||||
|
required this.moduleOrder,
|
||||||
|
required this.hiddenModules
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ModulesSettings.fromJson(Map<String, dynamic> json) => _$ModulesSettingsFromJson(json);
|
||||||
|
Map<String, dynamic> toJson() => _$ModulesSettingsToJson(this);
|
||||||
|
}
|
35
lib/storage/general/modulesSettings.g.dart
Normal file
35
lib/storage/general/modulesSettings.g.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'modulesSettings.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
ModulesSettings _$ModulesSettingsFromJson(Map<String, dynamic> json) =>
|
||||||
|
ModulesSettings(
|
||||||
|
moduleOrder: (json['moduleOrder'] as List<dynamic>)
|
||||||
|
.map((e) => $enumDecode(_$ModulesEnumMap, e))
|
||||||
|
.toList(),
|
||||||
|
hiddenModules: (json['hiddenModules'] as List<dynamic>)
|
||||||
|
.map((e) => $enumDecode(_$ModulesEnumMap, e))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$ModulesSettingsToJson(ModulesSettings instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'moduleOrder':
|
||||||
|
instance.moduleOrder.map((e) => _$ModulesEnumMap[e]!).toList(),
|
||||||
|
'hiddenModules':
|
||||||
|
instance.hiddenModules.map((e) => _$ModulesEnumMap[e]!).toList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const _$ModulesEnumMap = {
|
||||||
|
Modules.timetable: 'timetable',
|
||||||
|
Modules.talk: 'talk',
|
||||||
|
Modules.files: 'files',
|
||||||
|
Modules.marianumMessage: 'marianumMessage',
|
||||||
|
Modules.roomPlan: 'roomPlan',
|
||||||
|
Modules.gradeAveragesCalculator: 'gradeAveragesCalculator',
|
||||||
|
Modules.holidays: 'holidays',
|
||||||
|
};
|
@ -3,33 +3,82 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:in_app_review/in_app_review.dart';
|
import 'package:in_app_review/in_app_review.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import '../../extensions/renderNotNull.dart';
|
import '../../extensions/renderNotNull.dart';
|
||||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||||
|
|
||||||
import '../../state/app/modules/app_modules.dart';
|
import '../../state/app/modules/app_modules.dart';
|
||||||
|
import '../../storage/base/settingsProvider.dart';
|
||||||
import '../../widget/centeredLeading.dart';
|
import '../../widget/centeredLeading.dart';
|
||||||
import '../../widget/infoDialog.dart';
|
import '../../widget/infoDialog.dart';
|
||||||
|
import '../settings/defaultSettings.dart';
|
||||||
import '../settings/settings.dart';
|
import '../settings/settings.dart';
|
||||||
import 'more/feedback/feedbackDialog.dart';
|
import 'more/feedback/feedbackDialog.dart';
|
||||||
import 'more/share/selectShareTypeDialog.dart';
|
import 'more/share/selectShareTypeDialog.dart';
|
||||||
|
|
||||||
class Overhang extends StatelessWidget {
|
class Overhang extends StatefulWidget {
|
||||||
const Overhang({super.key});
|
const Overhang({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
State<Overhang> createState() => _OverhangState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OverhangState extends State<Overhang> {
|
||||||
|
bool editMode = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Consumer<SettingsProvider>(builder: (context, settings, child) => Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Mehr'),
|
title: const Text('Mehr'),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(onPressed: () => pushScreen(context, screen: const Settings(), withNavBar: false), icon: const Icon(Icons.settings))
|
if(editMode) IconButton(
|
||||||
|
onPressed: settings.val().modulesSettings.toJson().toString() != DefaultSettings.get().modulesSettings.toJson().toString()
|
||||||
|
? () => settings.val(write: true).modulesSettings = DefaultSettings.get().modulesSettings
|
||||||
|
: null,
|
||||||
|
icon: Icon(Icons.undo_outlined)
|
||||||
|
),
|
||||||
|
IconButton(onPressed: () => setState(() => editMode = !editMode), icon: Icon(Icons.edit_note_outlined), color: editMode ? Theme.of(context).primaryColor : null),
|
||||||
|
IconButton(onPressed: editMode ? null : () => pushScreen(context, screen: const Settings(), withNavBar: false), icon: const Icon(Icons.settings)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: editMode ? _sorting() : _overhang(),
|
||||||
|
));
|
||||||
|
|
||||||
|
Widget _sorting() => Consumer<SettingsProvider>(builder: (context, settings, child) {
|
||||||
|
void changeVisibility(Modules module) {
|
||||||
|
var hidden = settings.val(write: true).modulesSettings.hiddenModules;
|
||||||
|
hidden.contains(module) ? hidden.remove(module) : (hidden.length < 3 ? hidden.add(module) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReorderableListView(
|
||||||
|
header: const Center(
|
||||||
|
heightFactor: 2,
|
||||||
|
child: Text('Halte und ziehe einen Eintrag, um ihn zu verschieben.\nEs können 3 Bereiche ausgeblendet werden.', textAlign: TextAlign.center)
|
||||||
|
),
|
||||||
|
children: AppModule.modules(context, showFiltered: true)
|
||||||
|
.map((key, value) => MapEntry(key, value.toListTile(
|
||||||
|
context,
|
||||||
|
key: Key(key.name),
|
||||||
|
isReorder: true,
|
||||||
|
onVisibleChange: () => changeVisibility(key),
|
||||||
|
isVisible: !settings.val().modulesSettings.hiddenModules.contains(key)
|
||||||
|
)))
|
||||||
|
.values
|
||||||
|
.toList(),
|
||||||
|
onReorder: (oldIndex, newIndex) {
|
||||||
|
if (newIndex > oldIndex) newIndex -= 1;
|
||||||
|
|
||||||
|
var order = settings.val().modulesSettings.moduleOrder.toList();
|
||||||
|
final movedModule = order.removeAt(oldIndex);
|
||||||
|
order.insert(newIndex, movedModule);
|
||||||
|
settings.val(write: true).modulesSettings.moduleOrder = order;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Widget _overhang() => ListView(
|
||||||
children: [
|
children: [
|
||||||
AppModule.getModule(Modules.marianumMessage).toListTile(context),
|
...AppModule.getOverhangModules(context).map((e) => e.toListTile(context)),
|
||||||
AppModule.getModule(Modules.roomPlan).toListTile(context),
|
|
||||||
AppModule.getModule(Modules.gradeAveragesCalculator).toListTile(context),
|
|
||||||
AppModule.getModule(Modules.holidays).toListTile(context),
|
|
||||||
|
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
|
||||||
@ -73,6 +122,5 @@ class Overhang extends StatelessWidget {
|
|||||||
onTap: () => pushScreen(context, withNavBar: false, screen: const FeedbackDialog()),
|
onTap: () => pushScreen(context, withNavBar: false, screen: const FeedbackDialog()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,12 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../state/app/modules/app_modules.dart';
|
||||||
import '../../storage/base/settings.dart';
|
import '../../storage/base/settings.dart';
|
||||||
import '../../storage/devTools/devToolsSettings.dart';
|
import '../../storage/devTools/devToolsSettings.dart';
|
||||||
import '../../storage/file/fileSettings.dart';
|
import '../../storage/file/fileSettings.dart';
|
||||||
import '../../storage/fileView/fileViewSettings.dart';
|
import '../../storage/fileView/fileViewSettings.dart';
|
||||||
|
import '../../storage/general/modulesSettings.dart';
|
||||||
import '../../storage/holidays/holidaysSettings.dart';
|
import '../../storage/holidays/holidaysSettings.dart';
|
||||||
import '../../storage/notification/notificationSettings.dart';
|
import '../../storage/notification/notificationSettings.dart';
|
||||||
import '../../storage/talk/talkSettings.dart';
|
import '../../storage/talk/talkSettings.dart';
|
||||||
@ -17,6 +19,18 @@ class DefaultSettings {
|
|||||||
static Settings get() => Settings(
|
static Settings get() => Settings(
|
||||||
appTheme: ThemeMode.system,
|
appTheme: ThemeMode.system,
|
||||||
devToolsEnabled: false,
|
devToolsEnabled: false,
|
||||||
|
modulesSettings: ModulesSettings(
|
||||||
|
moduleOrder: [
|
||||||
|
Modules.timetable,
|
||||||
|
Modules.talk,
|
||||||
|
Modules.files,
|
||||||
|
Modules.marianumMessage,
|
||||||
|
Modules.roomPlan,
|
||||||
|
Modules.gradeAveragesCalculator,
|
||||||
|
Modules.holidays
|
||||||
|
],
|
||||||
|
hiddenModules: [],
|
||||||
|
),
|
||||||
timetableSettings: TimetableSettings(
|
timetableSettings: TimetableSettings(
|
||||||
connectDoubleLessons: false,
|
connectDoubleLessons: false,
|
||||||
timetableNameMode: TimetableNameMode.name
|
timetableNameMode: TimetableNameMode.name
|
||||||
|
@ -7,22 +7,19 @@ class PlaceholderView extends StatelessWidget {
|
|||||||
const PlaceholderView({super.key, required this.icon, required this.text, this.button});
|
const PlaceholderView({super.key, required this.icon, required this.text, this.button});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => DefaultTextStyle(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
style: const TextStyle(),
|
body: Center(
|
||||||
child: Center(
|
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.only(top: 100, left: 20, right: 20),
|
margin: const EdgeInsets.only(top: 100, left: 20, right: 20),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.all(30),
|
margin: const EdgeInsets.all(30),
|
||||||
child: Icon(icon, color: Colors.grey, size: 60),
|
child: Icon(icon, size: 60),
|
||||||
),
|
|
||||||
Text(text,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
),
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style: const TextStyle(fontSize: 20,),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user