opt: address book action more desktop style

This commit is contained in:
csf 2022-10-08 19:28:20 +09:00
parent 6a92212216
commit 14d390e23f
4 changed files with 90 additions and 68 deletions

View File

@ -1,6 +1,10 @@
import 'package:contextmenu/contextmenu.dart'; import 'package:contextmenu/contextmenu.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common/widgets/peer_card.dart';
import 'package:flutter_hbb/common/widgets/peers_view.dart'; import 'package:flutter_hbb/common/widgets/peers_view.dart';
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
import '../../consts.dart';
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../common.dart'; import '../../common.dart';
@ -102,6 +106,7 @@ class _AddressBookState extends State<AddressBook> {
} }
Widget _buildAddressBook(BuildContext context) { Widget _buildAddressBook(BuildContext context) {
var pos = RelativeRect.fill;
return Row( return Row(
children: [ children: [
Card( Card(
@ -120,27 +125,15 @@ class _AddressBookState extends State<AddressBook> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// TODO same style as peer
Text(translate('Tags')), Text(translate('Tags')),
InkWell( GestureDetector(
child: PopupMenuButton( onTapDown: (e) {
itemBuilder: (context) => [ final x = e.globalPosition.dx;
PopupMenuItem( final y = e.globalPosition.dy;
value: 'add-id', pos = RelativeRect.fromLTRB(x, y, x, y);
child: Text(translate("Add ID")), },
), onTap: () => _showMenu(pos),
PopupMenuItem( child: ActionMore()),
value: 'add-tag',
child: Text(translate("Add Tag")),
),
PopupMenuItem(
value: 'unset-all-tag',
child: Text(translate("Unselect all tags")),
),
],
onSelected: handleAbOp,
child: const Icon(Icons.more_vert_outlined)),
)
], ],
), ),
Expanded( Expanded(
@ -184,15 +177,39 @@ class _AddressBookState extends State<AddressBook> {
); );
} }
/// tag operation void _showMenu(RelativeRect pos) {
void handleAbOp(String value) { MenuEntryButton<String> getEntry(String title, VoidCallback proc) {
if (value == 'add-id') { return MenuEntryButton<String>(
abAddId(); childBuilder: (TextStyle? style) => Text(
} else if (value == 'add-tag') { title,
abAddTag(); style: style,
} else if (value == 'unset-all-tag') { ),
gFFI.abModel.unsetSelectedTags(); proc: proc,
padding: kDesktopMenuPadding,
dismissOnClicked: true,
);
} }
final items = [
getEntry(translate("Add ID"), abAddId),
getEntry(translate("Add Tag"), abAddTag),
getEntry(translate("Unselect all tags"), gFFI.abModel.unsetSelectedTags),
];
mod_menu.showMenu(
context: context,
position: pos,
items: items
.map((e) => e.build(
context,
MenuConfig(
commonColor: CustomPopupMenuTheme.commonColor,
height: CustomPopupMenuTheme.height,
dividerHeight: CustomPopupMenuTheme.dividerHeight)))
.expand((i) => i)
.toList(),
elevation: 8,
);
} }
void abAddId() async { void abAddId() async {

View File

@ -12,7 +12,7 @@ import '../../models/platform_model.dart';
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
import '../../desktop/widgets/popup_menu.dart'; import '../../desktop/widgets/popup_menu.dart';
class _PopupMenuTheme { class CustomPopupMenuTheme {
static const Color commonColor = MyTheme.accent; static const Color commonColor = MyTheme.accent;
// kMinInteractiveDimension // kMinInteractiveDimension
static const double height = 20.0; static const double height = 20.0;
@ -46,9 +46,8 @@ class _PeerCard extends StatefulWidget {
class _PeerCardState extends State<_PeerCard> class _PeerCardState extends State<_PeerCard>
with AutomaticKeepAliveClientMixin { with AutomaticKeepAliveClientMixin {
var _menuPos = RelativeRect.fill; var _menuPos = RelativeRect.fill;
final double _cardRadis = 16; final double _cardRadius = 16;
final double _borderWidth = 2; final double _borderWidth = 2;
final RxBool _iconMoreHover = false.obs;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -122,23 +121,23 @@ class _PeerCardState extends State<_PeerCard>
var deco = Rx<BoxDecoration?>(BoxDecoration( var deco = Rx<BoxDecoration?>(BoxDecoration(
border: Border.all(color: Colors.transparent, width: _borderWidth), border: Border.all(color: Colors.transparent, width: _borderWidth),
borderRadius: peerCardUiType.value == PeerUiType.grid borderRadius: peerCardUiType.value == PeerUiType.grid
? BorderRadius.circular(_cardRadis) ? BorderRadius.circular(_cardRadius)
: null)); : null));
return MouseRegion( return MouseRegion(
onEnter: (evt) { onEnter: (evt) {
deco.value = BoxDecoration( deco.value = BoxDecoration(
border: Border.all( border: Border.all(
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.primary,
width: _borderWidth), width: _borderWidth),
borderRadius: peerCardUiType.value == PeerUiType.grid borderRadius: peerCardUiType.value == PeerUiType.grid
? BorderRadius.circular(_cardRadis) ? BorderRadius.circular(_cardRadius)
: null); : null);
}, },
onExit: (evt) { onExit: (evt) {
deco.value = BoxDecoration( deco.value = BoxDecoration(
border: Border.all(color: Colors.transparent, width: _borderWidth), border: Border.all(color: Colors.transparent, width: _borderWidth),
borderRadius: peerCardUiType.value == PeerUiType.grid borderRadius: peerCardUiType.value == PeerUiType.grid
? BorderRadius.circular(_cardRadis) ? BorderRadius.circular(_cardRadius)
: null); : null);
}, },
child: GestureDetector( child: GestureDetector(
@ -221,7 +220,7 @@ class _PeerCardState extends State<_PeerCard>
() => Container( () => Container(
foregroundDecoration: deco.value, foregroundDecoration: deco.value,
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(_cardRadis - _borderWidth), borderRadius: BorderRadius.circular(_cardRadius - _borderWidth),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -299,27 +298,7 @@ class _PeerCardState extends State<_PeerCard>
_menuPos = RelativeRect.fromLTRB(x, y, x, y); _menuPos = RelativeRect.fromLTRB(x, y, x, y);
}, },
onPointerUp: (_) => _showPeerMenu(peer.id), onPointerUp: (_) => _showPeerMenu(peer.id),
child: MouseRegion( child: ActionMore());
onEnter: (_) => _iconMoreHover.value = true,
onExit: (_) => _iconMoreHover.value = false,
child: CircleAvatar(
radius: 14,
backgroundColor: _iconMoreHover.value
? Theme.of(context).scaffoldBackgroundColor
: Theme.of(context).backgroundColor,
// ? Theme.of(context).scaffoldBackgroundColor!
// : Theme.of(context).backgroundColor!,
child: Icon(Icons.more_vert,
size: 18,
color: _iconMoreHover.value
? Theme.of(context).textTheme.titleLarge?.color
: Theme.of(context)
.textTheme
.titleLarge
?.color
?.withOpacity(0.5)))));
// ? MyTheme.color(context).text
// : MyTheme.color(context).lightText))));
/// Show the peer menu and handle user's choice. /// Show the peer menu and handle user's choice.
/// User might remove the peer or send a file to the peer. /// User might remove the peer or send a file to the peer.
@ -358,9 +337,9 @@ abstract class BasePeerCard extends StatelessWidget {
.map((e) => e.build( .map((e) => e.build(
context, context,
const MenuConfig( const MenuConfig(
commonColor: _PopupMenuTheme.commonColor, commonColor: CustomPopupMenuTheme.commonColor,
height: _PopupMenuTheme.height, height: CustomPopupMenuTheme.height,
dividerHeight: _PopupMenuTheme.dividerHeight))) dividerHeight: CustomPopupMenuTheme.dividerHeight)))
.expand((i) => i) .expand((i) => i)
.toList(); .toList();
@ -426,7 +405,7 @@ abstract class BasePeerCard extends StatelessWidget {
return MenuEntryButton<String>( return MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Container( childBuilder: (TextStyle? style) => Container(
alignment: AlignmentDirectional.center, alignment: AlignmentDirectional.center,
height: _PopupMenuTheme.height, height: CustomPopupMenuTheme.height,
child: Row( child: Row(
children: [ children: [
Text( Text(
@ -875,7 +854,7 @@ void _rdpDialog(String id) async {
text: await bind.mainGetPeerOption(id: id, key: 'rdp_port')); text: await bind.mainGetPeerOption(id: id, key: 'rdp_port'));
final userController = TextEditingController( final userController = TextEditingController(
text: await bind.mainGetPeerOption(id: id, key: 'rdp_username')); text: await bind.mainGetPeerOption(id: id, key: 'rdp_username'));
final passwordContorller = TextEditingController( final passwordController = TextEditingController(
text: await bind.mainGetPeerOption(id: id, key: 'rdp_password')); text: await bind.mainGetPeerOption(id: id, key: 'rdp_password'));
RxBool secure = true.obs; RxBool secure = true.obs;
@ -886,7 +865,7 @@ void _rdpDialog(String id) async {
await bind.mainSetPeerOption( await bind.mainSetPeerOption(
id: id, key: 'rdp_username', value: userController.text); id: id, key: 'rdp_username', value: userController.text);
await bind.mainSetPeerOption( await bind.mainSetPeerOption(
id: id, key: 'rdp_password', value: passwordContorller.text); id: id, key: 'rdp_password', value: passwordController.text);
close(); close();
} }
@ -970,7 +949,7 @@ void _rdpDialog(String id) async {
icon: Icon(secure.value icon: Icon(secure.value
? Icons.visibility_off ? Icons.visibility_off
: Icons.visibility))), : Icons.visibility))),
controller: passwordContorller, controller: passwordController,
)), )),
), ),
], ],
@ -997,3 +976,28 @@ Widget getOnline(double rightPadding, bool online) {
child: CircleAvatar( child: CircleAvatar(
radius: 3, backgroundColor: online ? Colors.green : kColorWarn))); radius: 3, backgroundColor: online ? Colors.green : kColorWarn)));
} }
class ActionMore extends StatelessWidget {
final RxBool _iconMoreHover = false.obs;
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (_) => _iconMoreHover.value = true,
onExit: (_) => _iconMoreHover.value = false,
child: Obx(() => CircleAvatar(
radius: 14,
backgroundColor: _iconMoreHover.value
? Theme.of(context).scaffoldBackgroundColor
: Theme.of(context).backgroundColor,
child: Icon(Icons.more_vert,
size: 18,
color: _iconMoreHover.value
? Theme.of(context).textTheme.titleLarge?.color
: Theme.of(context)
.textTheme
.titleLarge
?.color
?.withOpacity(0.5)))));
}
}

View File

@ -32,6 +32,7 @@ const kDefaultMouseWheelThrottleDuration = Duration(milliseconds: 50);
const kFullScreenEdgeSize = 0.0; const kFullScreenEdgeSize = 0.0;
var kWindowEdgeSize = Platform.isWindows ? 1.0 : 5.0; var kWindowEdgeSize = Platform.isWindows ? 1.0 : 5.0;
const kWindowBorderWidth = 1.0; const kWindowBorderWidth = 1.0;
const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0);
const kInvalidValueStr = "InvalidValueStr"; const kInvalidValueStr = "InvalidValueStr";

View File

@ -86,16 +86,16 @@ class _ConnectionPageState extends State<ConnectionPage>
], ],
children: [ children: [
RecentPeersView( RecentPeersView(
menuPadding: EdgeInsets.only(left: 12.0, right: 3.0), menuPadding: kDesktopMenuPadding,
), ),
FavoritePeersView( FavoritePeersView(
menuPadding: EdgeInsets.only(left: 12.0, right: 3.0), menuPadding: kDesktopMenuPadding,
), ),
DiscoveredPeersView( DiscoveredPeersView(
menuPadding: EdgeInsets.only(left: 12.0, right: 3.0), menuPadding: kDesktopMenuPadding,
), ),
const AddressBook( const AddressBook(
menuPadding: EdgeInsets.only(left: 12.0, right: 3.0), menuPadding: kDesktopMenuPadding,
), ),
], ],
).paddingOnly(right: 12.0), ).paddingOnly(right: 12.0),