2022-08-26 23:28:08 +08:00
import ' dart:core ' ;
import ' package:flutter/material.dart ' ;
import ' package:get/get.dart ' ;
2022-10-13 20:22:11 +09:00
import ' ../../common.dart ' ;
2022-08-29 18:48:12 +08:00
import ' ./material_mod_popup_menu.dart ' as mod_menu ;
2022-08-26 23:28:08 +08:00
// https://stackoverflow.com/questions/68318314/flutter-popup-menu-inside-popup-menu
2022-08-29 18:48:12 +08:00
class PopupMenuChildrenItem < T > extends mod_menu . PopupMenuEntry < T > {
2022-09-08 21:03:20 -07:00
const PopupMenuChildrenItem ( {
2022-08-26 23:28:08 +08:00
key ,
this . height = kMinInteractiveDimension ,
this . padding ,
2022-09-06 21:20:53 -07:00
this . enabled ,
2022-08-26 23:28:08 +08:00
this . textStyle ,
this . onTap ,
2022-08-29 18:48:12 +08:00
this . position = mod_menu . PopupMenuPosition . overSide ,
2022-08-26 23:28:08 +08:00
this . offset = Offset . zero ,
required this . itemBuilder ,
required this . child ,
} ) : super ( key: key ) ;
2022-08-29 18:48:12 +08:00
final mod_menu . PopupMenuPosition position ;
2022-08-26 23:28:08 +08:00
final Offset offset ;
final TextStyle ? textStyle ;
final EdgeInsets ? padding ;
2022-09-06 21:20:53 -07:00
final RxBool ? enabled ;
2022-08-26 23:28:08 +08:00
final void Function ( ) ? onTap ;
2022-08-29 18:48:12 +08:00
final List < mod_menu . PopupMenuEntry < T > > Function ( BuildContext ) itemBuilder ;
2022-08-26 23:28:08 +08:00
final Widget child ;
@ override
final double height ;
@ override
bool represents ( T ? value ) = > false ;
@ override
MyPopupMenuItemState < T , PopupMenuChildrenItem < T > > createState ( ) = >
MyPopupMenuItemState < T , PopupMenuChildrenItem < T > > ( ) ;
}
class MyPopupMenuItemState < T , W extends PopupMenuChildrenItem < T > >
extends State < W > {
2022-09-07 18:39:45 -07:00
RxBool enabled = true . obs ;
@ override
void initState ( ) {
super . initState ( ) ;
if ( widget . enabled ! = null ) {
enabled . value = widget . enabled ! . value ;
}
}
2022-08-26 23:28:08 +08:00
@ protected
void handleTap ( T value ) {
widget . onTap ? . call ( ) ;
Navigator . pop < T > ( context , value ) ;
}
@ override
Widget build ( BuildContext context ) {
final ThemeData theme = Theme . of ( context ) ;
final PopupMenuThemeData popupMenuTheme = PopupMenuTheme . of ( context ) ;
TextStyle style = widget . textStyle ? ?
popupMenuTheme . textStyle ? ?
theme . textTheme . subtitle1 ! ;
2022-09-07 18:39:45 -07:00
return Obx ( ( ) = > mod_menu . PopupMenuButton < T > (
enabled: enabled . value ,
position: widget . position ,
offset: widget . offset ,
onSelected: handleTap ,
itemBuilder: widget . itemBuilder ,
padding: EdgeInsets . zero ,
child: AnimatedDefaultTextStyle (
style: style ,
duration: kThemeChangeDuration ,
child: Container (
alignment: AlignmentDirectional . centerStart ,
2022-09-23 12:20:40 +08:00
constraints: BoxConstraints (
minHeight: widget . height , maxHeight: widget . height ) ,
2022-09-07 18:39:45 -07:00
padding:
widget . padding ? ? const EdgeInsets . symmetric ( horizontal: 16 ) ,
child: widget . child ,
) ,
2022-09-06 21:20:53 -07:00
) ,
2022-09-07 18:39:45 -07:00
) ) ;
2022-08-26 23:28:08 +08:00
}
}
class MenuConfig {
// adapt to the screen height
static const fontSize = 14.0 ;
static const midPadding = 10.0 ;
static const iconScale = 0.8 ;
static const iconWidth = 12.0 ;
static const iconHeight = 12.0 ;
2022-08-29 18:48:12 +08:00
final double height ;
final double dividerHeight ;
2022-10-18 23:56:36 +09:00
final double ? boxWidth ;
2022-08-26 23:28:08 +08:00
final Color commonColor ;
const MenuConfig (
{ required this . commonColor ,
2022-08-29 18:48:12 +08:00
this . height = kMinInteractiveDimension ,
2022-10-18 23:56:36 +09:00
this . dividerHeight = 16.0 ,
this . boxWidth } ) ;
2022-08-26 23:28:08 +08:00
}
2023-02-03 19:17:59 +08:00
typedef DismissCallback = Function ( ) ;
2022-08-26 23:28:08 +08:00
abstract class MenuEntryBase < T > {
2022-08-31 18:41:55 +08:00
bool dismissOnClicked ;
2023-02-03 19:17:59 +08:00
DismissCallback ? dismissCallback ;
2022-09-06 21:20:53 -07:00
RxBool ? enabled ;
2022-08-31 18:41:55 +08:00
2022-09-06 21:20:53 -07:00
MenuEntryBase ( {
this . dismissOnClicked = false ,
this . enabled ,
2023-02-03 19:17:59 +08:00
this . dismissCallback ,
2022-09-06 21:20:53 -07:00
} ) ;
2022-08-30 17:20:25 +08:00
List < mod_menu . PopupMenuEntry < T > > build ( BuildContext context , MenuConfig conf ) ;
2023-01-06 20:25:18 +08:00
enabledStyle ( BuildContext context ) = > TextStyle (
color: Theme . of ( context ) . textTheme . titleLarge ? . color ,
fontSize: MenuConfig . fontSize ,
fontWeight: FontWeight . normal ) ;
disabledStyle ( ) = > TextStyle (
color: Colors . grey ,
fontSize: MenuConfig . fontSize ,
fontWeight: FontWeight . normal ) ;
2022-08-26 23:28:08 +08:00
}
class MenuEntryDivider < T > extends MenuEntryBase < T > {
@ override
2022-08-30 17:20:25 +08:00
List < mod_menu . PopupMenuEntry < T > > build (
BuildContext context , MenuConfig conf ) {
return [
mod_menu . PopupMenuDivider (
height: conf . dividerHeight ,
)
] ;
2022-08-26 23:28:08 +08:00
}
}
2022-08-31 18:41:55 +08:00
class MenuEntryRadioOption {
String text ;
String value ;
bool dismissOnClicked ;
2022-09-06 21:20:53 -07:00
RxBool ? enabled ;
2023-02-03 19:17:59 +08:00
DismissCallback ? dismissCallback ;
2022-09-06 21:20:53 -07:00
MenuEntryRadioOption ( {
required this . text ,
required this . value ,
this . dismissOnClicked = false ,
this . enabled ,
2023-02-03 19:17:59 +08:00
this . dismissCallback ,
2022-09-06 21:20:53 -07:00
} ) ;
2022-08-31 18:41:55 +08:00
}
typedef RadioOptionsGetter = List < MenuEntryRadioOption > Function ( ) ;
2022-08-26 23:28:08 +08:00
typedef RadioCurOptionGetter = Future < String > Function ( ) ;
2022-08-31 18:41:55 +08:00
typedef RadioOptionSetter = Future < void > Function (
String oldValue , String newValue ) ;
2022-08-26 23:28:08 +08:00
2022-08-30 17:20:25 +08:00
class MenuEntryRadioUtils < T > { }
class MenuEntryRadios < T > extends MenuEntryBase < T > {
2022-08-26 23:28:08 +08:00
final String text ;
final RadioOptionsGetter optionsGetter ;
final RadioCurOptionGetter curOptionGetter ;
final RadioOptionSetter optionSetter ;
final RxString _curOption = " " . obs ;
2022-09-23 12:20:40 +08:00
final EdgeInsets ? padding ;
2022-08-26 23:28:08 +08:00
2022-09-06 21:20:53 -07:00
MenuEntryRadios ( {
required this . text ,
required this . optionsGetter ,
required this . curOptionGetter ,
required this . optionSetter ,
2022-09-23 12:20:40 +08:00
this . padding ,
2022-09-06 21:20:53 -07:00
dismissOnClicked = false ,
2023-02-03 19:17:59 +08:00
dismissCallback ,
2022-09-06 21:20:53 -07:00
RxBool ? enabled ,
2023-02-03 19:17:59 +08:00
} ) : super (
dismissOnClicked: dismissOnClicked ,
enabled: enabled ,
dismissCallback: dismissCallback ,
) {
2022-08-26 23:28:08 +08:00
( ) async {
_curOption . value = await curOptionGetter ( ) ;
} ( ) ;
}
2022-08-31 18:41:55 +08:00
List < MenuEntryRadioOption > get options = > optionsGetter ( ) ;
2022-08-26 23:28:08 +08:00
RxString get curOption = > _curOption ;
setOption ( String option ) async {
2022-08-31 18:41:55 +08:00
await optionSetter ( _curOption . value , option ) ;
if ( _curOption . value ! = option ) {
final opt = await curOptionGetter ( ) ;
if ( _curOption . value ! = opt ) {
_curOption . value = opt ;
}
2022-08-26 23:28:08 +08:00
}
}
2022-08-30 17:20:25 +08:00
mod_menu . PopupMenuEntry < T > _buildMenuItem (
2022-08-31 18:41:55 +08:00
BuildContext context , MenuConfig conf , MenuEntryRadioOption opt ) {
2023-01-06 20:25:18 +08:00
Widget getTextChild ( ) {
final enabledTextChild = Text (
opt . text ,
style: enabledStyle ( context ) ,
) ;
final disabledTextChild = Text (
opt . text ,
style: disabledStyle ( ) ,
) ;
if ( opt . enabled = = null ) {
return enabledTextChild ;
} else {
return Obx (
( ) = > opt . enabled ! . isTrue ? enabledTextChild : disabledTextChild ) ;
}
}
final child = Container (
padding: padding ,
alignment: AlignmentDirectional . centerStart ,
constraints:
BoxConstraints ( minHeight: conf . height , maxHeight: conf . height ) ,
child: Row (
children: [
getTextChild ( ) ,
Expanded (
child: Align (
alignment: Alignment . centerRight ,
child: Transform . scale (
scale: MenuConfig . iconScale ,
child: Obx ( ( ) = > opt . value = = curOption . value
? IconButton (
padding:
const EdgeInsets . fromLTRB ( 8.0 , 0.0 , 8.0 , 0.0 ) ,
hoverColor: Colors . transparent ,
focusColor: Colors . transparent ,
onPressed: ( ) { } ,
icon: Icon (
Icons . check ,
color: ( opt . enabled ? ? true . obs ) . isTrue
? conf . commonColor
: Colors . grey ,
) )
: const SizedBox . shrink ( ) ) ,
) ) ) ,
] ,
) ,
) ;
onPressed ( ) {
if ( opt . dismissOnClicked & & Navigator . canPop ( context ) ) {
Navigator . pop ( context ) ;
2023-02-03 19:17:59 +08:00
if ( opt . dismissCallback ! = null ) {
opt . dismissCallback ! ( ) ;
}
2023-01-06 20:25:18 +08:00
}
setOption ( opt . value ) ;
}
2022-08-29 18:48:12 +08:00
return mod_menu . PopupMenuItem (
2022-08-26 23:28:08 +08:00
padding: EdgeInsets . zero ,
2022-08-29 18:48:12 +08:00
height: conf . height ,
2022-10-18 23:56:36 +09:00
child: Container (
2023-01-06 20:25:18 +08:00
width: conf . boxWidth ,
child: opt . enabled = = null
? TextButton (
child: child ,
onPressed: onPressed ,
)
: Obx ( ( ) = > TextButton (
child: child ,
onPressed: opt . enabled ! . isTrue ? onPressed : null ,
) ) ,
) ,
2022-08-26 23:28:08 +08:00
) ;
}
@ override
2022-08-30 17:20:25 +08:00
List < mod_menu . PopupMenuEntry < T > > build (
BuildContext context , MenuConfig conf ) {
return options . map ( ( opt ) = > _buildMenuItem ( context , conf , opt ) ) . toList ( ) ;
}
}
class MenuEntrySubRadios < T > extends MenuEntryBase < T > {
final String text ;
final RadioOptionsGetter optionsGetter ;
final RadioCurOptionGetter curOptionGetter ;
final RadioOptionSetter optionSetter ;
final RxString _curOption = " " . obs ;
2022-09-23 12:20:40 +08:00
final EdgeInsets ? padding ;
2022-08-30 17:20:25 +08:00
2022-09-06 21:20:53 -07:00
MenuEntrySubRadios ( {
required this . text ,
required this . optionsGetter ,
required this . curOptionGetter ,
required this . optionSetter ,
2022-09-23 12:20:40 +08:00
this . padding ,
2022-09-06 21:20:53 -07:00
dismissOnClicked = false ,
RxBool ? enabled ,
} ) : super (
dismissOnClicked: dismissOnClicked ,
enabled: enabled ,
) {
2022-08-30 17:20:25 +08:00
( ) async {
_curOption . value = await curOptionGetter ( ) ;
} ( ) ;
}
2022-08-31 18:41:55 +08:00
List < MenuEntryRadioOption > get options = > optionsGetter ( ) ;
2022-08-30 17:20:25 +08:00
RxString get curOption = > _curOption ;
setOption ( String option ) async {
2022-08-31 18:41:55 +08:00
await optionSetter ( _curOption . value , option ) ;
if ( _curOption . value ! = option ) {
final opt = await curOptionGetter ( ) ;
if ( _curOption . value ! = opt ) {
_curOption . value = opt ;
}
2022-08-30 17:20:25 +08:00
}
}
mod_menu . PopupMenuEntry < T > _buildSecondMenu (
2022-08-31 18:41:55 +08:00
BuildContext context , MenuConfig conf , MenuEntryRadioOption opt ) {
2022-08-30 17:20:25 +08:00
return mod_menu . PopupMenuItem (
2022-08-26 23:28:08 +08:00
padding: EdgeInsets . zero ,
2022-08-29 18:48:12 +08:00
height: conf . height ,
2022-10-18 23:56:36 +09:00
child: Container (
width: conf . boxWidth ,
child: TextButton (
child: Container (
padding: padding ,
alignment: AlignmentDirectional . centerStart ,
constraints: BoxConstraints (
minHeight: conf . height , maxHeight: conf . height ) ,
child: Row (
children: [
Text (
opt . text ,
style: TextStyle (
color: Theme . of ( context ) . textTheme . titleLarge ? . color ,
fontSize: MenuConfig . fontSize ,
fontWeight: FontWeight . normal ) ,
) ,
Expanded (
child: Align (
alignment: Alignment . centerRight ,
child: Transform . scale (
scale: MenuConfig . iconScale ,
child: Obx ( ( ) = > opt . value = = curOption . value
? IconButton (
padding: EdgeInsets . zero ,
hoverColor: Colors . transparent ,
focusColor: Colors . transparent ,
onPressed: ( ) { } ,
icon: Icon (
Icons . check ,
color: conf . commonColor ,
) )
: const SizedBox . shrink ( ) ) ) ,
) ) ,
] ,
2022-08-30 17:20:25 +08:00
) ,
2022-10-18 23:56:36 +09:00
) ,
onPressed: ( ) {
if ( opt . dismissOnClicked & & Navigator . canPop ( context ) ) {
Navigator . pop ( context ) ;
2023-02-03 19:17:59 +08:00
if ( opt . dismissCallback ! = null ) {
opt . dismissCallback ! ( ) ;
}
2022-10-18 23:56:36 +09:00
}
setOption ( opt . value ) ;
} ,
) ) ,
2022-08-26 23:28:08 +08:00
) ;
}
2022-08-30 17:20:25 +08:00
@ override
List < mod_menu . PopupMenuEntry < T > > build (
BuildContext context , MenuConfig conf ) {
return [
PopupMenuChildrenItem (
2022-09-06 21:20:53 -07:00
enabled: super . enabled ,
2022-09-23 12:20:40 +08:00
padding: padding ,
2022-08-30 17:20:25 +08:00
height: conf . height ,
itemBuilder: ( BuildContext context ) = >
options . map ( ( opt ) = > _buildSecondMenu ( context , conf , opt ) ) . toList ( ) ,
child: Row ( children: [
const SizedBox ( width: MenuConfig . midPadding ) ,
Text (
text ,
2022-09-04 16:26:08 +08:00
style: TextStyle (
2022-09-23 16:31:50 +08:00
color: Theme . of ( context ) . textTheme . titleLarge ? . color ,
2022-08-30 17:20:25 +08:00
fontSize: MenuConfig . fontSize ,
fontWeight: FontWeight . normal ) ,
) ,
Expanded (
child: Align (
alignment: Alignment . centerRight ,
child: Icon (
Icons . keyboard_arrow_right ,
color: conf . commonColor ,
) ,
) )
] ) ,
)
] ;
}
2022-08-26 23:28:08 +08:00
}
2022-09-23 12:20:40 +08:00
enum SwitchType {
sswitch ,
scheckbox ,
}
2022-08-26 23:28:08 +08:00
typedef SwitchGetter = Future < bool > Function ( ) ;
typedef SwitchSetter = Future < void > Function ( bool ) ;
abstract class MenuEntrySwitchBase < T > extends MenuEntryBase < T > {
2022-09-23 12:20:40 +08:00
final SwitchType switchType ;
2022-08-26 23:28:08 +08:00
final String text ;
2022-09-23 12:20:40 +08:00
final EdgeInsets ? padding ;
2022-09-07 18:39:45 -07:00
Rx < TextStyle > ? textStyle ;
2022-08-26 23:28:08 +08:00
2022-09-06 21:20:53 -07:00
MenuEntrySwitchBase ( {
2022-09-23 12:20:40 +08:00
required this . switchType ,
2022-09-06 21:20:53 -07:00
required this . text ,
required dismissOnClicked ,
this . textStyle ,
2022-09-23 12:20:40 +08:00
this . padding ,
2022-09-06 21:20:53 -07:00
RxBool ? enabled ,
2023-02-03 19:17:59 +08:00
dismissCallback ,
} ) : super (
dismissOnClicked: dismissOnClicked ,
enabled: enabled ,
dismissCallback: dismissCallback ,
) ;
2022-08-26 23:28:08 +08:00
RxBool get curOption ;
2022-09-23 12:20:40 +08:00
Future < void > setOption ( bool ? option ) ;
2022-08-26 23:28:08 +08:00
@ override
2022-08-30 17:20:25 +08:00
List < mod_menu . PopupMenuEntry < T > > build (
BuildContext context , MenuConfig conf ) {
2022-09-23 16:31:50 +08:00
textStyle ? ? = TextStyle (
color: Theme . of ( context ) . textTheme . titleLarge ? . color ,
2022-09-07 18:39:45 -07:00
fontSize: MenuConfig . fontSize ,
fontWeight: FontWeight . normal )
. obs ;
2022-08-30 17:20:25 +08:00
return [
mod_menu . PopupMenuItem (
padding: EdgeInsets . zero ,
height: conf . height ,
2022-10-18 23:56:36 +09:00
child: Container (
width: conf . boxWidth ,
child: TextButton (
child: Container (
padding: padding ,
alignment: AlignmentDirectional . centerStart ,
height: conf . height ,
child: Row ( children: [
Obx ( ( ) = > Text (
text ,
style: textStyle ! . value ,
) ) ,
Expanded (
child: Align (
alignment: Alignment . centerRight ,
child: Transform . scale (
scale: MenuConfig . iconScale ,
child: Obx ( ( ) {
if ( switchType = = SwitchType . sswitch ) {
return Switch (
value: curOption . value ,
onChanged: ( v ) {
if ( super . dismissOnClicked & &
Navigator . canPop ( context ) ) {
Navigator . pop ( context ) ;
2023-02-03 19:17:59 +08:00
if ( super . dismissCallback ! = null ) {
super . dismissCallback ! ( ) ;
}
2022-10-18 23:56:36 +09:00
}
setOption ( v ) ;
} ,
) ;
} else {
return Checkbox (
value: curOption . value ,
onChanged: ( v ) {
if ( super . dismissOnClicked & &
Navigator . canPop ( context ) ) {
Navigator . pop ( context ) ;
2023-02-03 19:17:59 +08:00
if ( super . dismissCallback ! = null ) {
super . dismissCallback ! ( ) ;
}
2022-10-18 23:56:36 +09:00
}
setOption ( v ) ;
} ,
) ;
}
} ) ) ,
) )
] ) ) ,
onPressed: ( ) {
if ( super . dismissOnClicked & & Navigator . canPop ( context ) ) {
Navigator . pop ( context ) ;
2023-02-03 19:17:59 +08:00
if ( super . dismissCallback ! = null ) {
super . dismissCallback ! ( ) ;
}
2022-10-18 23:56:36 +09:00
}
setOption ( ! curOption . value ) ;
} ,
) ) ,
2022-08-30 17:20:25 +08:00
)
] ;
2022-08-26 23:28:08 +08:00
}
}
class MenuEntrySwitch < T > extends MenuEntrySwitchBase < T > {
final SwitchGetter getter ;
final SwitchSetter setter ;
final RxBool _curOption = false . obs ;
2022-09-06 21:20:53 -07:00
MenuEntrySwitch ( {
2022-09-23 12:20:40 +08:00
required SwitchType switchType ,
2022-09-06 21:20:53 -07:00
required String text ,
required this . getter ,
required this . setter ,
Rx < TextStyle > ? textStyle ,
2022-09-23 12:20:40 +08:00
EdgeInsets ? padding ,
2022-09-06 21:20:53 -07:00
dismissOnClicked = false ,
RxBool ? enabled ,
2023-02-03 19:17:59 +08:00
dismissCallback ,
2022-09-06 21:20:53 -07:00
} ) : super (
2022-09-23 12:20:40 +08:00
switchType: switchType ,
2022-09-06 21:20:53 -07:00
text: text ,
textStyle: textStyle ,
2022-09-23 12:20:40 +08:00
padding: padding ,
2022-09-06 21:20:53 -07:00
dismissOnClicked: dismissOnClicked ,
enabled: enabled ,
2023-02-03 19:17:59 +08:00
dismissCallback: dismissCallback ,
2022-09-06 21:20:53 -07:00
) {
2022-08-26 23:28:08 +08:00
( ) async {
_curOption . value = await getter ( ) ;
} ( ) ;
}
@ override
RxBool get curOption = > _curOption ;
@ override
2022-09-23 12:20:40 +08:00
setOption ( bool ? option ) async {
if ( option ! = null ) {
await setter ( option ) ;
final opt = await getter ( ) ;
if ( _curOption . value ! = opt ) {
_curOption . value = opt ;
}
2022-08-26 23:28:08 +08:00
}
}
}
typedef Switch2Getter = RxBool Function ( ) ;
typedef Switch2Setter = Future < void > Function ( bool ) ;
class MenuEntrySwitch2 < T > extends MenuEntrySwitchBase < T > {
final Switch2Getter getter ;
final SwitchSetter setter ;
2022-09-06 21:20:53 -07:00
MenuEntrySwitch2 ( {
2022-09-23 12:20:40 +08:00
required SwitchType switchType ,
2022-09-06 21:20:53 -07:00
required String text ,
required this . getter ,
required this . setter ,
Rx < TextStyle > ? textStyle ,
2022-09-23 12:20:40 +08:00
EdgeInsets ? padding ,
2022-09-06 21:20:53 -07:00
dismissOnClicked = false ,
RxBool ? enabled ,
2023-02-03 19:17:59 +08:00
dismissCallback ,
2022-09-06 21:20:53 -07:00
} ) : super (
2023-02-03 19:17:59 +08:00
switchType: switchType ,
text: text ,
textStyle: textStyle ,
padding: padding ,
dismissOnClicked: dismissOnClicked ,
dismissCallback: dismissCallback ,
) ;
2022-08-26 23:28:08 +08:00
@ override
RxBool get curOption = > getter ( ) ;
@ override
2022-09-23 12:20:40 +08:00
setOption ( bool ? option ) async {
if ( option ! = null ) {
await setter ( option ) ;
}
2022-08-26 23:28:08 +08:00
}
}
class MenuEntrySubMenu < T > extends MenuEntryBase < T > {
final String text ;
final List < MenuEntryBase < T > > entries ;
2022-09-23 12:20:40 +08:00
final EdgeInsets ? padding ;
2022-08-26 23:28:08 +08:00
2022-09-06 21:20:53 -07:00
MenuEntrySubMenu ( {
required this . text ,
required this . entries ,
2022-09-23 12:20:40 +08:00
this . padding ,
2022-09-06 21:20:53 -07:00
RxBool ? enabled ,
} ) : super ( enabled: enabled ) ;
2022-08-26 23:28:08 +08:00
@ override
2022-08-30 17:20:25 +08:00
List < mod_menu . PopupMenuEntry < T > > build (
BuildContext context , MenuConfig conf ) {
2022-09-07 18:39:45 -07:00
super . enabled ? ? = true . obs ;
2022-08-30 17:20:25 +08:00
return [
PopupMenuChildrenItem (
2022-09-06 21:20:53 -07:00
enabled: super . enabled ,
2022-08-30 17:20:25 +08:00
height: conf . height ,
2022-09-23 12:20:40 +08:00
padding: padding ,
2022-08-30 17:20:25 +08:00
position: mod_menu . PopupMenuPosition . overSide ,
itemBuilder: ( BuildContext context ) = > entries
. map ( ( entry ) = > entry . build ( context , conf ) )
. expand ( ( i ) = > i )
. toList ( ) ,
child: Row ( children: [
const SizedBox ( width: MenuConfig . midPadding ) ,
2022-09-06 21:20:53 -07:00
Obx ( ( ) = > Text (
text ,
2023-01-06 20:25:18 +08:00
style: super . enabled ! . value
? enabledStyle ( context )
: disabledStyle ( ) ,
2022-09-06 21:20:53 -07:00
) ) ,
2022-08-30 17:20:25 +08:00
Expanded (
child: Align (
alignment: Alignment . centerRight ,
2022-09-06 21:20:53 -07:00
child: Obx ( ( ) = > Icon (
Icons . keyboard_arrow_right ,
2022-09-07 18:39:45 -07:00
color: super . enabled ! . value ? conf . commonColor : Colors . grey ,
2022-09-06 21:20:53 -07:00
) ) ,
2022-08-30 17:20:25 +08:00
) )
] ) ,
)
] ;
2022-08-26 23:28:08 +08:00
}
}
class MenuEntryButton < T > extends MenuEntryBase < T > {
final Widget Function ( TextStyle ? style ) childBuilder ;
Function ( ) proc ;
2022-09-23 12:20:40 +08:00
final EdgeInsets ? padding ;
2022-08-26 23:28:08 +08:00
2022-09-06 21:20:53 -07:00
MenuEntryButton ( {
required this . childBuilder ,
required this . proc ,
2022-09-23 12:20:40 +08:00
this . padding ,
2022-09-06 21:20:53 -07:00
dismissOnClicked = false ,
RxBool ? enabled ,
2023-02-03 19:17:59 +08:00
dismissCallback ,
2022-09-06 21:20:53 -07:00
} ) : super (
dismissOnClicked: dismissOnClicked ,
enabled: enabled ,
2023-02-03 19:17:59 +08:00
dismissCallback: dismissCallback ,
2022-09-06 21:20:53 -07:00
) ;
Widget _buildChild ( BuildContext context , MenuConfig conf ) {
2022-09-07 18:39:45 -07:00
super . enabled ? ? = true . obs ;
2022-10-18 23:56:36 +09:00
return Obx ( ( ) = > Container (
width: conf . boxWidth ,
child: TextButton (
2022-09-07 18:39:45 -07:00
onPressed: super . enabled ! . value
? ( ) {
if ( super . dismissOnClicked & & Navigator . canPop ( context ) ) {
Navigator . pop ( context ) ;
2023-02-03 19:17:59 +08:00
if ( super . dismissCallback ! = null ) {
super . dismissCallback ! ( ) ;
}
2022-09-07 18:39:45 -07:00
}
proc ( ) ;
2022-09-06 21:20:53 -07:00
}
2022-09-07 18:39:45 -07:00
: null ,
child: Container (
2022-09-23 12:20:40 +08:00
padding: padding ,
2022-09-07 18:39:45 -07:00
alignment: AlignmentDirectional . centerStart ,
2022-09-23 12:20:40 +08:00
constraints:
BoxConstraints ( minHeight: conf . height , maxHeight: conf . height ) ,
2022-09-07 18:39:45 -07:00
child: childBuilder (
2023-01-06 20:25:18 +08:00
super . enabled ! . value ? enabledStyle ( context ) : disabledStyle ( ) ) ,
2022-09-07 18:39:45 -07:00
) ,
2022-10-18 23:56:36 +09:00
) ) ) ;
2022-09-06 21:20:53 -07:00
}
2022-08-26 23:28:08 +08:00
@ override
2022-08-30 17:20:25 +08:00
List < mod_menu . PopupMenuEntry < T > > build (
BuildContext context , MenuConfig conf ) {
return [
mod_menu . PopupMenuItem (
padding: EdgeInsets . zero ,
height: conf . height ,
2022-09-06 21:20:53 -07:00
child: _buildChild ( context , conf ) ,
2022-08-30 17:20:25 +08:00
)
] ;
2022-08-26 23:28:08 +08:00
}
}
2022-10-13 20:22:11 +09:00
class CustomPopupMenuTheme {
static const Color commonColor = MyTheme . accent ;
// kMinInteractiveDimension
static const double height = 20.0 ;
static const double dividerHeight = 3.0 ;
}