committed by
GitHub
43 changed files with 732 additions and 68 deletions
@ -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), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
class MenuState { |
||||
|
|
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export './not_found/index.dart'; |
||||
@ -0,0 +1 @@ |
|||||
|
export '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, |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
} |
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
export 'search.dart'; |
||||
|
export 'menu_drawer.dart'; |
||||
|
export 'my_favorite.dart'; |
||||
|
export 'notification_bar.dart'; |
||||
|
export 'quick_navigation.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, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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]); |
||||
|
}, |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -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'; |
||||
@ -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'; |
||||
} |
} |
||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
Loading…
Reference in new issue