Browse Source

Merge pull request #1 from colinin/master

merge
pull/855/head
leehom0123 2 years ago
committed by GitHub
parent
commit
2faaf6cf51
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      apps/flutter/components/lib/widgets/index.dart
  2. 87
      apps/flutter/components/lib/widgets/menu/index.dart
  3. 3
      apps/flutter/components/lib/widgets/menu/state.dart
  4. 23
      apps/flutter/core/lib/models/common.dart
  5. 2
      apps/flutter/core/lib/models/environment.dart
  6. 6
      apps/flutter/core/lib/models/environment.g.dart
  7. 16
      apps/flutter/core/lib/utils/color.utils.dart
  8. 1
      apps/flutter/core/lib/utils/index.dart
  9. 4
      apps/flutter/dev_app/.gitignore
  10. 7
      apps/flutter/dev_app/lib/main.dart
  11. 3
      apps/flutter/dev_app/lib/main.module.dart
  12. 13
      apps/flutter/dev_app/lib/pages/main/controller.dart
  13. 6
      apps/flutter/dev_app/lib/pages/public/center/controller.dart
  14. 1
      apps/flutter/dev_app/lib/pages/public/error/index.dart
  15. 1
      apps/flutter/dev_app/lib/pages/public/error/not_found/index.dart
  16. 23
      apps/flutter/dev_app/lib/pages/public/error/not_found/view.dart
  17. 49
      apps/flutter/dev_app/lib/pages/public/home/controller.dart
  18. 28
      apps/flutter/dev_app/lib/pages/public/home/state.dart
  19. 99
      apps/flutter/dev_app/lib/pages/public/home/view.dart
  20. 5
      apps/flutter/dev_app/lib/pages/public/home/widget/index.dart
  21. 76
      apps/flutter/dev_app/lib/pages/public/home/widget/menu_drawer.dart
  22. 42
      apps/flutter/dev_app/lib/pages/public/home/widget/my_favorite.dart
  23. 55
      apps/flutter/dev_app/lib/pages/public/home/widget/notification_bar.dart
  24. 33
      apps/flutter/dev_app/lib/pages/public/home/widget/quick_navigation.dart
  25. 23
      apps/flutter/dev_app/lib/pages/public/home/widget/search.dart
  26. 1
      apps/flutter/dev_app/lib/pages/public/index.dart
  27. 2
      apps/flutter/dev_app/lib/pages/public/route.name.dart
  28. 6
      apps/flutter/dev_app/lib/pages/public/route.public.dart
  29. 17
      apps/flutter/dev_app/lib/services/notification.send.local.service.dart
  30. 20
      apps/flutter/dev_app/lib/services/translation.service.res.service.dart
  31. 56
      apps/flutter/dev_app/pubspec.lock
  32. 1
      apps/flutter/dev_app/pubspec.yaml
  33. 14
      apps/flutter/dev_app/res/config/demo.json
  34. BIN
      apps/flutter/dev_app/res/images/no_data.png
  35. BIN
      apps/flutter/dev_app/res/images/notification.png
  36. BIN
      apps/flutter/dev_app/res/images/profile.png
  37. BIN
      apps/flutter/dev_app/res/images/setting.png
  38. 7
      apps/flutter/dev_app/res/translations/en.json
  39. 9
      apps/flutter/dev_app/res/translations/zh-Hans.json
  40. 1
      apps/flutter/notifications/lib/models/notification.state.dart
  41. 11
      apps/flutter/notifications/lib/services/notification.state.service.dart
  42. 14
      apps/flutter/platform/lib/services/favorite.menu.state.service.dart
  43. 14
      apps/flutter/platform/lib/services/menu.state.service.dart

1
apps/flutter/components/lib/widgets/index.dart

@ -3,3 +3,4 @@ export 'action-button/index.dart';
export 'back-to-top/index.dart'; export 'back-to-top/index.dart';
export 'bottom-button/index.dart'; export 'bottom-button/index.dart';
export 'empty/index.dart'; export 'empty/index.dart';
export 'menu/index.dart';

87
apps/flutter/components/lib/widgets/menu/index.dart

@ -0,0 +1,87 @@
import 'package:core/models/common.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Navigation extends StatefulWidget {
const Navigation({
super.key,
this.activedMenu,
this.menus = const [],
this.onMenuExpanded,
});
final List<Menu> menus;
final String? activedMenu;
final void Function(Menu menu)? onMenuExpanded;
@override
State<Navigation> createState() => _NavigationState();
}
class _NavigationState extends State<Navigation> {
@override
Widget build(BuildContext context) {
return _renderNavigations(widget.menus);
}
Widget _renderNavigations(List<Menu> menus) {
var mainMenus = menus.where((menu) => menu.children?.isNotEmpty == false);
var subMenus = menus.where((menu) => menu.children?.isNotEmpty == true);
return Column(
children: [
_renderMenus(subMenus.toList()),
...mainMenus.map((menu) => _buildMenuItem(menu)),
],
);
}
Widget _renderMenus(List<Menu> menus) {
return ExpansionPanelList.radio(
initialOpenPanelValue: widget.activedMenu,
expandedHeaderPadding: const EdgeInsets.all(0),
expansionCallback: (panelIndex, isExpanded) {
if (widget.onMenuExpanded != null) {
widget.onMenuExpanded!(menus[panelIndex]);
}
},
children: menus.map<ExpansionPanelRadio>((Menu menu) {
var body = menu.children?.isNotEmpty == true
? _renderNavigations(menu.children!)
: _buildMenuItem(menu);
return ExpansionPanelRadio(
canTapOnHeader: true,
headerBuilder: (BuildContext context, bool isExpanded) {
return SizedBox(
height: 30,
child: ListTile(
title: Text(
(menu.meta?['displayName']?.toString().tr ?? menu.displayName).padLeft(menu.level * 4)),
),
);
},
body: body,
value: menu.name,
);
}).toList(),
);
}
Widget _buildMenuItem(Menu menu) {
return InkWell(
onTap: () {
Get.toNamed(menu.path);
},
child: FractionallySizedBox(
widthFactor: 1,
child: Container(
height: 30,
margin: const EdgeInsets.only(top: 10),
child: Text(
(menu.meta?['displayName']?.toString().tr ?? menu.displayName).padLeft(menu.level * 8),
),
),
),
);
}
}

3
apps/flutter/components/lib/widgets/menu/state.dart

@ -0,0 +1,3 @@
class MenuState {
}

23
apps/flutter/core/lib/models/common.dart

@ -42,3 +42,26 @@ class SignalrMessage {
String method; String method;
List<Object?> data; List<Object?> data;
} }
class Menu {
Menu({
required this.path,
required this.name,
required this.displayName,
this.id = 0,
this.level = 0,
this.description,
this.redirect,
this.meta,
this.children,
});
String path;
String name;
String displayName;
String? description;
String? redirect;
int level;
int id;
Map<String, dynamic>? meta;
List<Menu>? children;
}

2
apps/flutter/core/lib/models/environment.dart

@ -177,10 +177,12 @@ class LocalizationConfig {
this.defaultLanguage, this.defaultLanguage,
this.useLocalResources = true, this.useLocalResources = true,
this.supportedLocales = const [], this.supportedLocales = const [],
this.translationFiles = const {},
}); });
String? defaultLanguage; String? defaultLanguage;
bool? useLocalResources; bool? useLocalResources;
List<LanguageInfo>? supportedLocales; List<LanguageInfo>? supportedLocales;
Map<String, List<String>>? translationFiles;
factory LocalizationConfig.fromJson(Map<String, dynamic> json) => _$LocalizationConfigFromJson(json); factory LocalizationConfig.fromJson(Map<String, dynamic> json) => _$LocalizationConfigFromJson(json);
Map<String, dynamic> toJson() => _$LocalizationConfigToJson(this); Map<String, dynamic> toJson() => _$LocalizationConfigToJson(this);

6
apps/flutter/core/lib/models/environment.g.dart

@ -102,6 +102,11 @@ LocalizationConfig _$LocalizationConfigFromJson(Map<String, dynamic> json) =>
supportedLocales: json['supportedLocales'] != null supportedLocales: json['supportedLocales'] != null
? (json['supportedLocales'] as List<dynamic>).map((e) => LanguageInfo.fromJson(e)).toList() ? (json['supportedLocales'] as List<dynamic>).map((e) => LanguageInfo.fromJson(e)).toList()
: null, : null,
translationFiles: json['translationFiles'] != null
? (json['translationFiles'] as Map<String, dynamic>)
.map((key, value) => MapEntry(key, (value as List<dynamic>)
.map((e) => e as String).toList()))
: null,
); );
Map<String, dynamic> _$LocalizationConfigToJson(LocalizationConfig instance) => Map<String, dynamic> _$LocalizationConfigToJson(LocalizationConfig instance) =>
@ -109,6 +114,7 @@ Map<String, dynamic> _$LocalizationConfigToJson(LocalizationConfig instance) =>
'defaultLanguage': instance.defaultLanguage, 'defaultLanguage': instance.defaultLanguage,
'useLocalResources': instance.useLocalResources, 'useLocalResources': instance.useLocalResources,
'supportedLocales': instance.supportedLocales, 'supportedLocales': instance.supportedLocales,
'translationFiles': instance.translationFiles,
}; };
RemoteService _$RemoteServiceFromJson(Map<String, dynamic> json) => RemoteService _$RemoteServiceFromJson(Map<String, dynamic> json) =>

16
apps/flutter/core/lib/utils/color.utils.dart

@ -0,0 +1,16 @@
import 'dart:ui';
class ColorUtils {
static Color fromHex(String hexString) {
final buffer = StringBuffer();
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
buffer.write(hexString.replaceFirst('#', ''));
return Color(int.parse(buffer.toString(), radix: 16));
}
}
extension HexStringToColor on String {
Color toColor() {
return ColorUtils.fromHex(this);
}
}

1
apps/flutter/core/lib/utils/index.dart

@ -1,3 +1,4 @@
export 'color.utils.dart';
export 'environment.utils.dart'; export 'environment.utils.dart';
export 'internal.store.dart'; export 'internal.store.dart';
export 'localization.utils.dart'; export 'localization.utils.dart';

4
apps/flutter/dev_app/.gitignore

@ -45,3 +45,7 @@ app.*.map.json
# Environment config # Environment config
/res/config/development.json /res/config/development.json
# Ignored translations
/res/translations/merge-en.json
/res/translations/merge-zh-Hans.json

7
apps/flutter/dev_app/lib/main.dart

@ -2,10 +2,12 @@ import 'package:core/dependency/index.dart';
import 'package:core/utils/theme.utils.dart'; import 'package:core/utils/theme.utils.dart';
import 'package:core/utils/logging.dart'; import 'package:core/utils/logging.dart';
import 'package:dev_app/main.module.dart'; import 'package:dev_app/main.module.dart';
import 'package:dev_app/pages/index.dart';
import 'package:dev_app/pages/public/route.name.dart';
import 'package:dev_app/utils/localization.dart'; import 'package:dev_app/utils/localization.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
Future main() async { Future main() async {
@ -25,8 +27,9 @@ class MyApp extends StatelessWidget {
theme: ThemeUtils.lightTheme, theme: ThemeUtils.lightTheme,
darkTheme: ThemeUtils.darkTheme, darkTheme: ThemeUtils.darkTheme,
themeMode: ThemeMode.system, themeMode: ThemeMode.system,
initialRoute: '/', initialRoute: PublicRoutes.main,
getPages: module.getRoutes(), getPages: module.getRoutes(),
unknownRoute: PublicRoute.notFound,
debugShowMaterialGrid: false, debugShowMaterialGrid: false,
enableLog: true, enableLog: true,
builder: EasyLoading.init(), builder: EasyLoading.init(),

3
apps/flutter/dev_app/lib/main.module.dart

@ -1,5 +1,6 @@
import 'package:components/index.dart'; import 'package:components/index.dart';
import 'package:dev_app/pages/index.dart'; import 'package:dev_app/pages/index.dart';
import 'package:dev_app/pages/public/route.name.dart';
import 'package:dev_app/services/index.dart'; import 'package:dev_app/services/index.dart';
import 'package:dev_app/utils/initial.utils.dart'; import 'package:dev_app/utils/initial.utils.dart';
import 'package:dev_app/utils/loading.dart'; import 'package:dev_app/utils/loading.dart';
@ -30,7 +31,7 @@ class MainModule extends Module {
@override @override
List<GetPage> get routes => [ List<GetPage> get routes => [
GetPage( GetPage(
name: '/', name: PublicRoutes.main,
page: () => const MainPage(), page: () => const MainPage(),
bindings: [ bindings: [
MainBinding(), MainBinding(),

13
apps/flutter/dev_app/lib/pages/main/controller.dart

@ -1,13 +1,13 @@
import 'package:core/dependency/index.dart'; import 'package:core/dependency/index.dart';
import 'package:core/abstracts/signalr.service.dart'; import 'package:core/abstracts/signalr.service.dart';
import 'package:core/services/environment.service.dart'; import 'package:core/services/environment.service.dart';
import 'package:core/services/notification.send.service.dart';
import 'package:dev_app/handlers/index.dart'; import 'package:dev_app/handlers/index.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:core/services/session.service.dart'; import 'package:core/services/session.service.dart';
import 'package:core/services/subscription.service.dart'; import 'package:core/services/subscription.service.dart';
import 'package:core/utils/index.dart'; import 'package:core/utils/index.dart';
import 'package:notifications/models/index.dart'; import 'package:notifications/models/index.dart';
import 'package:notifications/services/notification.state.service.dart';
import 'package:notifications/tokens/index.dart'; import 'package:notifications/tokens/index.dart';
class MainController extends GetxController { class MainController extends GetxController {
@ -17,7 +17,7 @@ class MainController extends GetxController {
SessionService get _sessionService => injector.get(); SessionService get _sessionService => injector.get();
SubscriptionService get _subscriptionService => injector.get(tag: NotificationTokens.consumer); SubscriptionService get _subscriptionService => injector.get(tag: NotificationTokens.consumer);
SignalrService get _signalrService => injector.get(tag: NotificationTokens.producer); SignalrService get _signalrService => injector.get(tag: NotificationTokens.producer);
NotificationSendService get _notificationSendService => injector.get(); NotificationStateService get _notificationStateService => injector.get();
EnvironmentService get _environmentService => injector.get(); EnvironmentService get _environmentService => injector.get();
ErrorHandler get _errorHandler => injector.get(); ErrorHandler get _errorHandler => injector.get();
@ -37,14 +37,7 @@ class MainController extends GetxController {
if (data == null) continue; if (data == null) continue;
// //
var notification = NotificationInfo.fromJson(data as dynamic); var notification = NotificationInfo.fromJson(data as dynamic);
// _notificationStateService.addNotification(notification);
var payload = NotificationPaylod.fromNotification(notification);
//
await _notificationSendService.send(
payload.title,
payload.body,
payload.payload,
);
} }
}, },
); );

6
apps/flutter/dev_app/lib/pages/public/center/controller.dart

@ -44,15 +44,15 @@ class CenterController extends GetxController {
} }
void onClickFeedback() { void onClickFeedback() {
redirectToRoute('/feedback');
} }
void onClickHelp() { void onClickHelp() {
redirectToRoute('/help');
} }
void onClickInfo() { void onClickInfo() {
redirectToRoute('/info');
} }
void onClickMessage() { void onClickMessage() {

1
apps/flutter/dev_app/lib/pages/public/error/index.dart

@ -0,0 +1 @@
export './not_found/index.dart';

1
apps/flutter/dev_app/lib/pages/public/error/not_found/index.dart

@ -0,0 +1 @@
export 'view.dart';

23
apps/flutter/dev_app/lib/pages/public/error/not_found/view.dart

@ -0,0 +1,23 @@
import 'package:bruno/bruno.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class PageNotFound extends StatelessWidget {
const PageNotFound({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("404Message".tr)
),
body: BrnAbnormalStateWidget(
img: Image.asset(
'res/images/no_data.png',
scale: 3.0,
),
content: "404MessageDetail".tr,
),
);
}
}

49
apps/flutter/dev_app/lib/pages/public/home/controller.dart

@ -1,5 +1,7 @@
import 'package:core/models/common.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:core/dependency/index.dart'; import 'package:core/dependency/index.dart';
import 'package:notifications/services/notification.state.service.dart';
import 'package:platforms/services/index.dart'; import 'package:platforms/services/index.dart';
import 'state.dart'; import 'state.dart';
@ -7,6 +9,7 @@ import 'state.dart';
class HomeController extends GetxController { class HomeController extends GetxController {
MenuStateService get _menuStateService => injector.get<MenuStateService>(); MenuStateService get _menuStateService => injector.get<MenuStateService>();
FavoriteMenuStateService get _favoriteMenuStateService => injector.get<FavoriteMenuStateService>(); FavoriteMenuStateService get _favoriteMenuStateService => injector.get<FavoriteMenuStateService>();
NotificationStateService get _notificationStateService => injector.get<NotificationStateService>();
final Rx<HomeState> _state = Rx<HomeState>(HomeState()); final Rx<HomeState> _state = Rx<HomeState>(HomeState());
HomeState get state => _state.value; HomeState get state => _state.value;
@ -14,17 +17,39 @@ class HomeController extends GetxController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
// _menuStateService.getMyMenus$() _menuStateService.getMyMenus$()
// .listen((menus) { .listen((menus) {
// _state.update((val) { _state.update((val) {
// val?.menus = menus; val?.menus = menus;
// }); });
// }); });
// _favoriteMenuStateService.getFavoriteMenus$() _favoriteMenuStateService.getFavoriteMenus$()
// .listen((menus) { .listen((menus) {
// _state.update((val) { _state.update((val) {
// val?.favoriteMenus = menus; val?.favoriteMenus = menus;
// }); });
// }); });
_notificationStateService.getNotifications$()
.listen((payload) {
var notifications = state.notifications.reversed.take(5).toList();
notifications.add(payload);
_state.update((val) {
val?.notifications = notifications;
});
});
}
Future<void> refreshMenus() async {
await _menuStateService.refreshState();
}
void redirectToRoute(String route) {
Get.toNamed(route);
}
void onMenuExpanded(Menu menu) {
_state.update((val) {
val?.activedMenu = menu.name;
});
} }
} }

28
apps/flutter/dev_app/lib/pages/public/home/state.dart

@ -1,10 +1,38 @@
import 'package:core/models/common.dart';
import 'package:notifications/models/common.dart';
import 'package:platforms/modes/menu.dto.dart'; import 'package:platforms/modes/menu.dto.dart';
class HomeState { class HomeState {
HomeState({ HomeState({
this.activedMenu,
this.menus = const [], this.menus = const [],
this.favoriteMenus = const [], this.favoriteMenus = const [],
this.notifications = const [],
}); });
String? activedMenu;
List<MenuDto> menus; List<MenuDto> menus;
List<UserFavoriteMenuDto> favoriteMenus; List<UserFavoriteMenuDto> favoriteMenus;
List<NotificationPaylod> notifications;
List<Menu> getMenus() => _buildTreeRecursive(menus, null, 0);
List<Menu> _buildTreeRecursive(List<MenuDto> treeMenus, String? parentId, int level) {
List<Menu> results = [];
var tempList = treeMenus.where((menu) => menu.parentId == parentId).toList();
for (int i = 0; i < tempList.length; i++) {
var menu = Menu(
id: tempList[i].id.hashCode,
path: tempList[i].path,
name: tempList[i].name,
displayName: tempList[i].displayName,
description: tempList[i].description,
redirect: tempList[i].redirect,
meta: tempList[i].meta,
level: level + 1
);
menu.children = _buildTreeRecursive(treeMenus, tempList[i].id, menu.level);
results.add(menu);
}
return results;
}
} }

99
apps/flutter/dev_app/lib/pages/public/home/view.dart

@ -1,8 +1,13 @@
import 'package:account/pages/route.name.dart';
import 'package:components/index.dart'; import 'package:components/index.dart';
import 'package:dev_app/pages/public/home/widget/search.dart'; import 'package:core/utils/index.dart';
import 'package:dev_app/pages/system/route.name.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'controller.dart'; import 'controller.dart';
import './widget/index.dart';
class HomePage extends BasePage<HomeController> { class HomePage extends BasePage<HomeController> {
const HomePage({super.key}); const HomePage({super.key});
@ -20,27 +25,99 @@ class HomePage extends BasePage<HomeController> {
onPressed: () { onPressed: () {
showSearch(context: context, delegate: SearchBarDelegate(menus: bloc.state.menus)); showSearch(context: context, delegate: SearchBarDelegate(menus: bloc.state.menus));
}, },
child: const Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.search), const Icon(Icons.search),
Expanded(child: Text('搜索功能')) Expanded(child: Text('Label:SearchFeatures'.tr))
], ],
), ),
), ),
), ),
body: Column( body: ListView(
children: [ children: [
Expanded( Obx(() => NotificationBar(notifications: bloc.state.notifications)),
child: ListView.builder( QuickNavigation(
itemCount: bloc.state.favoriteMenus.length, menus: [
itemBuilder: (context, index) { _buildMenu(
var favoriteMenu = bloc.state.favoriteMenus[index]; SystemRoutes.settings,
return Text(favoriteMenu.displayName ?? favoriteMenu.name); SystemRoutes.settings,
icon: 'res/images/setting.png',
displayName: "Label:SystemSettings".tr,
color: Colors.red.hex),
_buildMenu(
AccountRoutes.profile,
AccountRoutes.profile,
icon: 'res/images/profile.png',
displayName: "Page:UserProfile".tr,
color: const Color.fromARGB(255, 68, 160, 206).hex),
],
),
Obx(() => MyFavorite(
favoriteMenus: bloc.state.favoriteMenus,
favoriteMenuBuilder: (favoriteMenu) {
return _buildMenu(
favoriteMenu.name,
favoriteMenu.path,
aliasName: favoriteMenu.aliasName,
//icon: favoriteMenu.icon,
// TODO:
icon: 'res/images/setting.png',
color: favoriteMenu.color,
displayName: favoriteMenu.displayName,
);
}, },
)),
],
),
drawer: SafeArea(
child: Obx(() => MenuDrawer(
activedMenu: bloc.state.activedMenu,
menus: bloc.state.getMenus(),
onMenuExpanded: bloc.onMenuExpanded,
onMenuRefresh: bloc.refreshMenus,
)),
), ),
);
}
Widget _buildMenu(
String name,
String path,
{
String? aliasName,
String? icon,
String? color,
String? displayName,
}
) {
return InkWell(
onTap: () {
bloc.redirectToRoute(path);
},
child: SizedBox(
height: 20,
width: 30,
child: Column(
children: [
const SizedBox(height: 10),
icon != null
? Image.asset(
icon,
height: 40,
width: 40,
color: color.isNullOrWhiteSpace() ? null : ColorUtils.fromHex(color!),
)
: Empty.none,
Text(
displayName ?? aliasName ?? name,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14
), ),
)
], ],
), ),
),
); );
} }
} }

5
apps/flutter/dev_app/lib/pages/public/home/widget/index.dart

@ -0,0 +1,5 @@
export 'search.dart';
export 'menu_drawer.dart';
export 'my_favorite.dart';
export 'notification_bar.dart';
export 'quick_navigation.dart';

76
apps/flutter/dev_app/lib/pages/public/home/widget/menu_drawer.dart

@ -0,0 +1,76 @@
import 'package:components/widgets/menu/index.dart';
import 'package:core/models/common.dart';
import 'package:flutter/material.dart';
class MenuDrawer extends StatelessWidget {
const MenuDrawer({
super.key,
this.activedMenu,
this.menus = const [],
required this.onMenuRefresh,
this.onMenuExpanded,
});
final String? activedMenu;
final List<Menu> menus;
final void Function(Menu menu)? onMenuExpanded;
final Future<void> Function() onMenuRefresh;
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: onMenuRefresh,
child: Drawer(
width: 260,
child: Column(
children: [
_buildLogo(),
Expanded(
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [
Navigation(
activedMenu: activedMenu,
menus: menus,
onMenuExpanded: onMenuExpanded,
),
],
),
)
),
],
),
),
);
}
Widget _buildLogo() {
return Container(
height: 24,
margin: const EdgeInsets.all(10),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 10),
child: Image.asset(
'res/images/logo.png',
height: 20,
width: 20,
),
),
const Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
'abp flutter',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w400,
),
),
),
],
),
);
}
}

42
apps/flutter/dev_app/lib/pages/public/home/widget/my_favorite.dart

@ -0,0 +1,42 @@
import 'package:components/widgets/empty/index.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:platforms/modes/menu.dto.dart';
class MyFavorite extends StatelessWidget {
const MyFavorite({
super.key,
required this.favoriteMenus,
required this.favoriteMenuBuilder,
});
final List<UserFavoriteMenuDto> favoriteMenus;
final Widget Function(UserFavoriteMenuDto favoriteMenu) favoriteMenuBuilder;
@override
Widget build(BuildContext context) {
return ExpansionTile(
initiallyExpanded: true,
title: Text('Label:MyFavorite'.tr,
style: Theme.of(context).textTheme.titleMedium,
),
children: [
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: favoriteMenus.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 5,
),
itemBuilder: (BuildContext context, int index) {
if (index >= favoriteMenus.length) {
return Empty.none;
}
return favoriteMenuBuilder(favoriteMenus[index]);
},
),
],
);
}
}

55
apps/flutter/dev_app/lib/pages/public/home/widget/notification_bar.dart

@ -0,0 +1,55 @@
import 'package:bruno/bruno.dart';
import 'package:components/widgets/empty/index.dart';
import 'package:flutter/material.dart';
import 'package:notifications/models/common.dart';
import 'package:notifications/models/notification.dart';
class NotificationBar extends StatelessWidget {
const NotificationBar({
super.key,
required this.notifications
});
final List<NotificationPaylod> notifications;
@override
Widget build(BuildContext context) {
if (notifications.isEmpty) {
return Empty.none;
}
return SizedBox(
height: 40,
child: SingleChildScrollView(
child: Column(
children: notifications.map<BrnNoticeBar>((payload) {
return BrnNoticeBar(
padding: const EdgeInsets.only(left: 5, right: 5, top: 3),
leftWidget: Image.asset(
'res/images/notification.png',
height: 30,
width: 30,
),
content: payload.title,
marquee: true,
noticeStyle: _mapNoticeStyles(payload.severity),
);
}).toList(),
),
),
);
}
NoticeStyle _mapNoticeStyles(NotificationSeverity? severity) {
if (severity == null) return NoticeStyles.normalNoticeWithArrow;
switch (severity) {
case NotificationSeverity.info:
case NotificationSeverity.success:
return NoticeStyles.succeedWithArrow;
case NotificationSeverity.fatal:
case NotificationSeverity.error:
return NoticeStyles.failWithArrow;
case NotificationSeverity.warn:
return NoticeStyles.warningWithArrow;
}
}
}

33
apps/flutter/dev_app/lib/pages/public/home/widget/quick_navigation.dart

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class QuickNavigation extends StatelessWidget {
const QuickNavigation({
super.key,
this.menus = const [],
});
final List<Widget> menus;
@override
Widget build(BuildContext context) {
return ExpansionTile(
initiallyExpanded: true,
title: Text('Label:QuickNavigation'.tr,
style: Theme.of(context).textTheme.titleMedium,
),
children: [
SizedBox(
height: 120,
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 4,
crossAxisSpacing: 5,
physics: const NeverScrollableScrollPhysics(),
children: menus,
),
),
],
);
}
}

23
apps/flutter/dev_app/lib/pages/public/home/widget/search.dart

@ -13,8 +13,7 @@ class SearchBarDelegate extends SearchDelegate<String> {
List<Widget>? buildActions(BuildContext context) { List<Widget>? buildActions(BuildContext context) {
Widget button = IconButton( Widget button = IconButton(
onPressed: () { onPressed: () {
query = ""; close(context, "error");
showSuggestions(context);
}, },
icon: const Icon(Icons.clear), icon: const Icon(Icons.clear),
); );
@ -24,15 +23,17 @@ class SearchBarDelegate extends SearchDelegate<String> {
@override @override
Widget? buildLeading(BuildContext context) { Widget? buildLeading(BuildContext context) {
return IconButton( // return IconButton(
onPressed: () { // onPressed: () {
close(context, "error"); // query = "";
}, // showSuggestions(context);
icon: AnimatedIcon( // },
icon: AnimatedIcons.menu_arrow, // icon: AnimatedIcon(
progress: transitionAnimation, // icon: AnimatedIcons.menu_arrow,
), // progress: transitionAnimation,
); // ),
// );
return null;
} }
@override @override

1
apps/flutter/dev_app/lib/pages/public/index.dart

@ -1,3 +1,4 @@
export './center/index.dart'; export './center/index.dart';
export './home/index.dart'; export './home/index.dart';
export './work/index.dart'; export './work/index.dart';
export './error/index.dart';

2
apps/flutter/dev_app/lib/pages/public/route.name.dart

@ -1,5 +1,7 @@
class PublicRoutes { class PublicRoutes {
static String main = '/main';
static String home = '/home'; static String home = '/home';
static String work = '/work'; static String work = '/work';
static String center = '/center'; static String center = '/center';
static String notFound = '/error/not_found';
} }

6
apps/flutter/dev_app/lib/pages/public/route.public.dart

@ -4,7 +4,13 @@ import 'index.dart';
import 'route.name.dart'; import 'route.name.dart';
class PublicRoute { class PublicRoute {
static GetPage notFound = GetPage(
name: PublicRoutes.notFound,
page: () => const PageNotFound(),
);
static List<GetPage> routes = [ static List<GetPage> routes = [
notFound,
GetPage( GetPage(
name: PublicRoutes.home, name: PublicRoutes.home,
page: () => const HomePage(), page: () => const HomePage(),

17
apps/flutter/dev_app/lib/services/notification.send.local.service.dart

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:core/index.dart'; import 'package:core/index.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:notifications/services/notification.state.service.dart';
import 'package:rxdart/rxdart.dart' hide Notification; import 'package:rxdart/rxdart.dart' hide Notification;
import 'package:core/models/notifications.dart'; import 'package:core/models/notifications.dart';
@ -14,6 +15,22 @@ class FlutterLocalNotificationsSendService extends NotificationSendService {
final Subject<String?> _selectedNotifications$ = BehaviorSubject<String?>(); final Subject<String?> _selectedNotifications$ = BehaviorSubject<String?>();
EnvironmentService get _environmentService => resolve<EnvironmentService>(); EnvironmentService get _environmentService => resolve<EnvironmentService>();
NotificationStateService get _notificationStateService => resolve<NotificationStateService>();
@override
void onInit() {
super.onInit();
_notificationStateService
.getNotifications$()
.listen((payload) async {
//
await send(
payload.title,
payload.body,
payload.payload,
);
});
}
Future<void> initAsync() async { Future<void> initAsync() async {
var environment = _environmentService.getEnvironment(); var environment = _environmentService.getEnvironment();

20
apps/flutter/dev_app/lib/services/translation.service.res.service.dart

@ -1,5 +1,6 @@
import 'dart:ui'; import 'dart:ui';
import 'package:core/services/environment.service.dart';
import 'package:core/services/localization.service.dart'; import 'package:core/services/localization.service.dart';
import 'package:core/services/service.base.dart'; import 'package:core/services/service.base.dart';
import 'package:core/services/session.service.dart'; import 'package:core/services/session.service.dart';
@ -17,6 +18,7 @@ class TranslationResService extends ServiceBase implements TranslationService {
final InternalStore<TranslationState> _store = InternalStore<TranslationState>(state: TranslationState()); final InternalStore<TranslationState> _store = InternalStore<TranslationState>(state: TranslationState());
SessionService get _sessionService => resolve<SessionService>(); SessionService get _sessionService => resolve<SessionService>();
EnvironmentService get _environmentService => resolve<EnvironmentService>();
LocalizationService get _localizationService => resolve<LocalizationService>(); LocalizationService get _localizationService => resolve<LocalizationService>();
@override @override
@ -44,13 +46,21 @@ class TranslationResService extends ServiceBase implements TranslationService {
Future<TranslationState> _mapTranslationsMap(String language) async { Future<TranslationState> _mapTranslationsMap(String language) async {
Map<String, Map<String, String>> translationsMap = {}; Map<String, Map<String, String>> translationsMap = {};
var filePath = 'res/translations/$language.json'; var environment = _environmentService.getEnvironment();
var translationFiles = environment.localization.translationFiles?[language] ?? ['$language.json'];
for (var translationFile in translationFiles) {
try {
var filePath = 'res/translations/$translationFile';
var content = await rootBundle.loadString(filePath); var content = await rootBundle.loadString(filePath);
var translationsObject = jsonDecode(content) as Map<String, dynamic>; var translationsObject = jsonDecode(content) as Map<String, dynamic>;
translationsMap.putIfAbsent( var translations = translationsMap[language] ?? {};
language, translations.addAll(translationsObject.map((key, value) => MapEntry(key, value)));
() => translationsObject.map((key, value) => MapEntry(key, value)) translationsMap.putIfAbsent(language, () => translations);
); } catch (e) {
logger.error(e);
}
}
return TranslationState( return TranslationState(
language: language, language: language,
translations: translationsMap, translations: translationsMap,

56
apps/flutter/dev_app/pubspec.lock

@ -40,6 +40,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.11.0" version: "2.11.0"
bindings_compatible:
dependency: transitive
description:
name: bindings_compatible
sha256: "5dd5189f7512aff8ec180a8a11bd59230aa34a2d743e65e427192b7292a78d87"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -48,6 +56,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
bruno:
dependency: "direct main"
description:
name: bruno
sha256: "8bd461a658996000eab1111a93fb4826ade878103f5a9afa29a414046805448b"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.4.1"
build: build:
dependency: transitive dependency: transitive
description: description:
@ -307,6 +323,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.5" version: "3.0.5"
flutter_easyrefresh:
dependency: transitive
description:
name: flutter_easyrefresh
sha256: "5d161ee5dcac34da9065116568147d742dd25fb9bff3b10024d9054b195087ad"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.2"
flutter_highlight: flutter_highlight:
dependency: transitive dependency: transitive
description: description:
@ -514,6 +538,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
lpinyin:
dependency: transitive
description:
name: lpinyin
sha256: "0bb843363f1f65170efd09fbdfc760c7ec34fc6354f9fcb2f89e74866a0d814a"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.3"
markdown: markdown:
dependency: transitive dependency: transitive
description: description:
@ -608,6 +640,22 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.3" version: "1.8.3"
path_drawing:
dependency: transitive
description:
name: path_drawing
sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
path_provider: path_provider:
dependency: transitive dependency: transitive
description: description:
@ -664,6 +712,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "5.4.0" version: "5.4.0"
photo_view:
dependency: transitive
description:
name: photo_view
sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.14.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:

1
apps/flutter/dev_app/pubspec.yaml

@ -49,6 +49,7 @@ dependencies:
platforms: platforms:
path: '../platform' path: '../platform'
bruno: ^3.3.0
dio: ^5.2.0+1 dio: ^5.2.0+1
flutter_easyloading: ^3.0.5 flutter_easyloading: ^3.0.5
flutter_picker: ^2.1.0 flutter_picker: ^2.1.0

14
apps/flutter/dev_app/res/config/demo.json

@ -13,6 +13,20 @@
"localization": { "localization": {
"useLocalResources": true, "useLocalResources": true,
"defaultLanguage": "zh-Hans", "defaultLanguage": "zh-Hans",
"translationFiles": {
"zh-Hans": [
"zh-Hans.json"
],
"zh_CN": [
"zh-Hans.json"
],
"en": [
"en.json"
],
"en_US": [
"en.json"
]
},
"supportedLocales": [ "supportedLocales": [
{ {
"cultureName": "en", "cultureName": "en",

BIN
apps/flutter/dev_app/res/images/no_data.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
apps/flutter/dev_app/res/images/notification.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
apps/flutter/dev_app/res/images/profile.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
apps/flutter/dev_app/res/images/setting.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

7
apps/flutter/dev_app/res/translations/en.json

@ -5,6 +5,7 @@
"404Message": "Page not found", "404Message": "Page not found",
"404MessageDetail": "Sorry, there's nothing at this address.", "404MessageDetail": "Sorry, there's nothing at this address.",
"500Message": "Internal Server Error", "500Message": "Internal Server Error",
"Avatar": "Avatar",
"Center:Feedback": "Feedback", "Center:Feedback": "Feedback",
"Center:Help": "Help", "Center:Help": "Help",
"Center:Info": "Info", "Center:Info": "Info",
@ -12,6 +13,9 @@
"Center:Settings": "Settings", "Center:Settings": "Settings",
"DisplayName:Abp.Localization.DefaultLanguage": "Default language", "DisplayName:Abp.Localization.DefaultLanguage": "Default language",
"Description:Abp.Localization.DefaultLanguage": "The default language of the application.", "Description:Abp.Localization.DefaultLanguage": "The default language of the application.",
"DisplayName:UserName": "User Name",
"DisplayName:Email": "Email",
"DisplayName:PhoneNumber": "Phone Number",
"DefaultErrorMessage": "An error has occurred!", "DefaultErrorMessage": "An error has occurred!",
"DefaultErrorMessageDetail": "Error detail not sent by server.", "DefaultErrorMessageDetail": "Error detail not sent by server.",
"DefaultErrorMessage401": "You are not authenticated!", "DefaultErrorMessage401": "You are not authenticated!",
@ -37,6 +41,7 @@
"Label:NotifierSettings": "Notifier Settings", "Label:NotifierSettings": "Notifier Settings",
"Label:PasswordRequired": "Please enter password", "Label:PasswordRequired": "Please enter password",
"Label:PhoneNumberNotBound": "PhoneNumber Not Bound", "Label:PhoneNumberNotBound": "PhoneNumber Not Bound",
"Label:SearchFeatures": "Search Features",
"Label:Submit": "Submit", "Label:Submit": "Submit",
"Label:SwitchTheme": "Switch Theme", "Label:SwitchTheme": "Switch Theme",
"Label:SystemSettings": "System Settings", "Label:SystemSettings": "System Settings",
@ -45,6 +50,8 @@
"Label:Cancel": "Cancel", "Label:Cancel": "Cancel",
"Label:Confirm": "Confirm", "Label:Confirm": "Confirm",
"Label:LoginToPortal": "Login To Portal", "Label:LoginToPortal": "Login To Portal",
"Label:QuickNavigation": "Quick navigation",
"Label:MyFavorite": "My favorites",
"Languages": "Languages", "Languages": "Languages",
"Page:Center": "Center", "Page:Center": "Center",
"Page:Home": "Home", "Page:Home": "Home",

9
apps/flutter/dev_app/res/translations/zh-Hans.json

@ -2,9 +2,10 @@
"401Message": "未授权", "401Message": "未授权",
"403Message": "禁止访问", "403Message": "禁止访问",
"403MessageDetail": "您没有权限执行此操作!", "403MessageDetail": "您没有权限执行此操作!",
"404Message": "页未找到", "404Message": "页未找到",
"404MessageDetail": "抱歉, 这个地址是空的.", "404MessageDetail": "抱歉, 这个地址是空的.",
"500Message": "内部服务器错误", "500Message": "内部服务器错误",
"Avatar": "头像",
"Center:Feedback": "意见反馈", "Center:Feedback": "意见反馈",
"Center:Help": "在线帮助", "Center:Help": "在线帮助",
"Center:Info": "关于", "Center:Info": "关于",
@ -12,6 +13,9 @@
"Center:Settings": "设置", "Center:Settings": "设置",
"DisplayName:Abp.Localization.DefaultLanguage": "默认语言", "DisplayName:Abp.Localization.DefaultLanguage": "默认语言",
"Description:Abp.Localization.DefaultLanguage": "应用程序的默认语言.", "Description:Abp.Localization.DefaultLanguage": "应用程序的默认语言.",
"DisplayName:UserName": "用户名",
"DisplayName:Email": "邮件地址",
"DisplayName:PhoneNumber": "手机号码",
"DefaultErrorMessage": "发生错误!", "DefaultErrorMessage": "发生错误!",
"DefaultErrorMessageDetail": "服务器未发送错误的详细信息.", "DefaultErrorMessageDetail": "服务器未发送错误的详细信息.",
"DefaultErrorMessage401": "未通过身份验证!", "DefaultErrorMessage401": "未通过身份验证!",
@ -37,6 +41,7 @@
"Label:NotifierSettings": "通知设置", "Label:NotifierSettings": "通知设置",
"Label:PasswordRequired": "请输入密码", "Label:PasswordRequired": "请输入密码",
"Label:PhoneNumberNotBound": "未绑定手机号", "Label:PhoneNumberNotBound": "未绑定手机号",
"Label:SearchFeatures": "搜索功能",
"Label:Submit": "提交", "Label:Submit": "提交",
"Label:SwitchTheme": "切换主题", "Label:SwitchTheme": "切换主题",
"Label:SystemSettings": "系统设置", "Label:SystemSettings": "系统设置",
@ -45,6 +50,8 @@
"Label:Cancel": "取消", "Label:Cancel": "取消",
"Label:Confirm": "确认", "Label:Confirm": "确认",
"Label:LoginToPortal": "登录到门户", "Label:LoginToPortal": "登录到门户",
"Label:QuickNavigation": "快捷导航",
"Label:MyFavorite": "我的收藏",
"Languages": "语言", "Languages": "语言",
"Page:Center": "个人中心", "Page:Center": "个人中心",
"Page:Home": "首页", "Page:Home": "首页",

1
apps/flutter/notifications/lib/models/notification.state.dart

@ -15,6 +15,7 @@ class NotificationState {
bool isEnabled; bool isEnabled;
List<NotificationGroup> groups; List<NotificationGroup> groups;
NotificationGroup? findGroup(String name) { NotificationGroup? findGroup(String name) {
return groups.firstWhereOrNull((item) => item.name == name); return groups.firstWhereOrNull((item) => item.name == name);
} }

11
apps/flutter/notifications/lib/services/notification.state.service.dart

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'package:notifications/models/common.dart';
import 'package:rxdart/rxdart.dart' hide Notification; import 'package:rxdart/rxdart.dart' hide Notification;
import 'package:notifications/models/notification.dart'; import 'package:notifications/models/notification.dart';
import 'package:core/services/session.service.dart'; import 'package:core/services/session.service.dart';
@ -20,6 +21,8 @@ class NotificationStateService extends ServiceBase {
NotificationService get _notificationService => resolve<NotificationService>(); NotificationService get _notificationService => resolve<NotificationService>();
SignalrService get _signalrService => resolve<SignalrService>(tag: NotificationTokens.producer); SignalrService get _signalrService => resolve<SignalrService>(tag: NotificationTokens.producer);
final BehaviorSubject<NotificationPaylod> _notifications = BehaviorSubject<NotificationPaylod>();
final InternalStore<NotificationState> _store = InternalStore<NotificationState>( final InternalStore<NotificationState> _store = InternalStore<NotificationState>(
state: _initState() state: _initState()
); );
@ -41,6 +44,10 @@ class NotificationStateService extends ServiceBase {
return _store.sliceUpdate((state) => state); return _store.sliceUpdate((state) => state);
} }
Stream<NotificationPaylod> getNotifications$() {
return _notifications;
}
NotificationGroup? findGroup(String name) { NotificationGroup? findGroup(String name) {
return _store.state.findGroup(name); return _store.state.findGroup(name);
} }
@ -75,6 +82,10 @@ class NotificationStateService extends ServiceBase {
return configState ?? NotificationState(isEnabled: true, groups: []); return configState ?? NotificationState(isEnabled: true, groups: []);
} }
void addNotification(NotificationInfo notification) {
_notifications.add(NotificationPaylod.fromNotification(notification));
}
Future<List<NotificationGroup>> getGroupAndCombineWithNotification(List<NotificationGroupDto> groupItems) { Future<List<NotificationGroup>> getGroupAndCombineWithNotification(List<NotificationGroupDto> groupItems) {
return _notificationService.getMySubscribedListAsync() return _notificationService.getMySubscribedListAsync()
.then((subscres) { .then((subscres) {

14
apps/flutter/platform/lib/services/favorite.menu.state.service.dart

@ -1,5 +1,6 @@
import 'package:core/services/environment.service.dart'; import 'package:core/services/environment.service.dart';
import 'package:core/services/service.base.dart'; import 'package:core/services/service.base.dart';
import 'package:core/services/session.service.dart';
import 'package:core/utils/index.dart'; import 'package:core/utils/index.dart';
import 'package:platforms/modes/state.dart'; import 'package:platforms/modes/state.dart';
import 'package:platforms/modes/menu.dto.dart'; import 'package:platforms/modes/menu.dto.dart';
@ -10,18 +11,29 @@ class FavoriteMenuStateService extends ServiceBase {
final InternalStore<FavoriteMenuState> _state = InternalStore<FavoriteMenuState>(state: FavoriteMenuState()); final InternalStore<FavoriteMenuState> _state = InternalStore<FavoriteMenuState>(state: FavoriteMenuState());
SessionService get _sessionService => resolve<SessionService>();
EnvironmentService get _environmentService => resolve<EnvironmentService>(); EnvironmentService get _environmentService => resolve<EnvironmentService>();
FavoriteMenuService get _favoriteMenuService => resolve<FavoriteMenuService>(); FavoriteMenuService get _favoriteMenuService => resolve<FavoriteMenuService>();
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
_initState();
}
void _initState() {
_sessionService.getToken$()
.listen((token) {
_state.patch((state) => state.menus = []);
if (token != null) {
refreshState(); refreshState();
} }
});
}
Future<void> refreshState() async { Future<void> refreshState() async {
var environment = _environmentService.getEnvironment(); var environment = _environmentService.getEnvironment();
var framework = environment.application.framework ?? 'flutter'; var framework = environment.application.framework ?? 'abp-flutter';
var result = await _favoriteMenuService.getMyFavoriteMenuList(framework); var result = await _favoriteMenuService.getMyFavoriteMenuList(framework);
_state.patch((state) => state.menus = result.items); _state.patch((state) => state.menus = result.items);
} }

14
apps/flutter/platform/lib/services/menu.state.service.dart

@ -1,5 +1,6 @@
import 'package:core/services/environment.service.dart'; import 'package:core/services/environment.service.dart';
import 'package:core/services/service.base.dart'; import 'package:core/services/service.base.dart';
import 'package:core/services/session.service.dart';
import 'package:core/utils/index.dart'; import 'package:core/utils/index.dart';
import 'package:platforms/modes/state.dart'; import 'package:platforms/modes/state.dart';
import 'package:platforms/modes/menu.dto.dart'; import 'package:platforms/modes/menu.dto.dart';
@ -11,17 +12,28 @@ class MenuStateService extends ServiceBase {
final InternalStore<MenuState> _state = InternalStore<MenuState>(state: MenuState()); final InternalStore<MenuState> _state = InternalStore<MenuState>(state: MenuState());
EnvironmentService get _environmentService => resolve<EnvironmentService>(); EnvironmentService get _environmentService => resolve<EnvironmentService>();
SessionService get _sessionService => resolve<SessionService>();
MenuService get _menuService => resolve<MenuService>(); MenuService get _menuService => resolve<MenuService>();
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
_initState();
}
void _initState() {
_sessionService.getToken$()
.listen((token) {
_state.patch((state) => state.menus = []);
if (token != null) {
refreshState(); refreshState();
} }
});
}
Future<void> refreshState() async { Future<void> refreshState() async {
var environment = _environmentService.getEnvironment(); var environment = _environmentService.getEnvironment();
var framework = environment.application.framework ?? 'flutter'; var framework = environment.application.framework ?? 'abp-flutter';
var result = await _menuService.getCurrentUserMenuList(framework); var result = await _menuService.getCurrentUserMenuList(framework);
_state.patch((state) => state.menus = result.items); _state.patch((state) => state.menus = result.items);
} }

Loading…
Cancel
Save