file transfer search bar pop_menu show Windows drives

This commit is contained in:
csf 2022-10-18 23:56:36 +09:00
parent e23fa8c806
commit 0c976a6644
6 changed files with 251 additions and 168 deletions

View File

@ -107,7 +107,7 @@ class DraggableChatWindow extends StatelessWidget {
icon: IconFont.close, icon: IconFont.close,
onTap: chatModel.hideChatWindowOverlay, onTap: chatModel.hideChatWindowOverlay,
isClose: true, isClose: true,
size: 32, boxSize: 32,
)) ))
], ],
), ),

View File

@ -6,6 +6,7 @@ import 'package:desktop_drop/desktop_drop.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; import 'package:flutter_breadcrumb/flutter_breadcrumb.dart';
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/models/file_model.dart'; import 'package:flutter_hbb/models/file_model.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -455,7 +456,7 @@ class _FileManagerPageState extends State<FileManagerPage>
icon: const Icon(Icons.restart_alt_rounded)), icon: const Icon(Icons.restart_alt_rounded)),
), ),
IconButton( IconButton(
icon: const Icon(Icons.delete), icon: const Icon(Icons.delete_forever_outlined),
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
model.jobTable.removeAt(index); model.jobTable.removeAt(index);
@ -742,32 +743,98 @@ class _FileManagerPageState extends State<FileManagerPage>
openDirectory(path, isLocal: isLocal); openDirectory(path, isLocal: isLocal);
}); });
breadCrumbScrollToEnd(isLocal); breadCrumbScrollToEnd(isLocal);
final locationBarKey = GlobalKey(debugLabel: "locationBarKey");
return items.isEmpty return items.isEmpty
? Offstage() ? Offstage()
: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ : Row(
Expanded( key: locationBarKey,
child: BreadCrumb( mainAxisAlignment: MainAxisAlignment.spaceBetween,
items: items, children: [
divider: Text("/").paddingSymmetric(horizontal: 4.0), Expanded(
overflow: ScrollableOverflow( child: BreadCrumb(
controller: getBreadCrumbScrollController(isLocal)), items: items,
)), divider: Text("/",
DropdownButton<String>( style: TextStyle(color: Theme.of(context).hintColor))
isDense: true, .paddingSymmetric(horizontal: 2.0),
underline: Offstage(), overflow: ScrollableOverflow(
items: [ controller: getBreadCrumbScrollController(isLocal)),
// TODO: favourite )),
DropdownMenuItem( ActionIcon(
child: Text('/'), message: "",
value: '/', icon: Icons.arrow_drop_down,
) onTap: () async {
], final renderBox = locationBarKey.currentContext
onChanged: (path) { ?.findRenderObject() as RenderBox;
if (path is String && path.isNotEmpty) { locationBarKey.currentContext?.size;
openDirectory(path, isLocal: isLocal);
} final size = renderBox.size;
}) final offset = renderBox.localToGlobal(Offset.zero);
]);
final x = offset.dx;
final y = offset.dy + size.height + 1;
final peerPlatform = (await bind.sessionGetPlatform(
id: _ffi.id, isRemote: !isLocal))
.toLowerCase();
final List<MenuEntryBase> menuItems;
if (peerPlatform == "windows") {
menuItems = [];
final loadingTag =
_ffi.dialogManager.showLoading("Waiting");
try {
final fd =
await model.fetchDirectory("/", isLocal, false);
for (var entry in fd.entries) {
menuItems.add(MenuEntryButton(
childBuilder: (TextStyle? style) => Text(
entry.name,
style: style,
),
proc: () {
openDirectory(entry.name, isLocal: isLocal);
Get.back();
}));
menuItems.add(MenuEntryDivider());
}
} finally {
_ffi.dialogManager.dismissByTag(loadingTag);
}
} else {
menuItems = [
MenuEntryButton(
childBuilder: (TextStyle? style) => Text(
'/',
style: style,
),
proc: () {
openDirectory('/', isLocal: isLocal);
Get.back();
}),
MenuEntryDivider()
];
}
mod_menu.showMenu(
context: context,
position: RelativeRect.fromLTRB(x, y, x, y),
elevation: 4,
items: menuItems
.map((e) => e.build(
context,
MenuConfig(
commonColor:
CustomPopupMenuTheme.commonColor,
height: CustomPopupMenuTheme.height,
dividerHeight:
CustomPopupMenuTheme.dividerHeight,
boxWidth: size.width)))
.expand((i) => i)
.toList());
},
iconSize: 20,
)
]);
} }
List<BreadCrumbItem> getPathBreadCrumbItems( List<BreadCrumbItem> getPathBreadCrumbItems(

View File

@ -99,12 +99,14 @@ class MenuConfig {
final double height; final double height;
final double dividerHeight; final double dividerHeight;
final double? boxWidth;
final Color commonColor; final Color commonColor;
const MenuConfig( const MenuConfig(
{required this.commonColor, {required this.commonColor,
this.height = kMinInteractiveDimension, this.height = kMinInteractiveDimension,
this.dividerHeight = 16.0}); this.dividerHeight = 16.0,
this.boxWidth});
} }
abstract class MenuEntryBase<T> { abstract class MenuEntryBase<T> {
@ -190,49 +192,51 @@ class MenuEntryRadios<T> extends MenuEntryBase<T> {
return mod_menu.PopupMenuItem( return mod_menu.PopupMenuItem(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
height: conf.height, height: conf.height,
child: TextButton( child: Container(
child: Container( width: conf.boxWidth,
padding: padding, child: TextButton(
alignment: AlignmentDirectional.centerStart, child: Container(
constraints: padding: padding,
BoxConstraints(minHeight: conf.height, maxHeight: conf.height), alignment: AlignmentDirectional.centerStart,
child: Row( constraints: BoxConstraints(
children: [ minHeight: conf.height, maxHeight: conf.height),
Text( child: Row(
opt.text, children: [
style: TextStyle( Text(
color: Theme.of(context).textTheme.titleLarge?.color, opt.text,
fontSize: MenuConfig.fontSize, style: TextStyle(
fontWeight: FontWeight.normal), 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: const EdgeInsets.fromLTRB(
8.0, 0.0, 8.0, 0.0),
hoverColor: Colors.transparent,
focusColor: Colors.transparent,
onPressed: () {},
icon: Icon(
Icons.check,
color: conf.commonColor,
))
: const SizedBox.shrink()),
))),
],
), ),
Expanded( ),
child: Align( onPressed: () {
alignment: Alignment.centerRight, if (opt.dismissOnClicked && Navigator.canPop(context)) {
child: Transform.scale( Navigator.pop(context);
scale: MenuConfig.iconScale, }
child: Obx(() => opt.value == curOption.value setOption(opt.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: conf.commonColor,
))
: const SizedBox.shrink()),
))),
],
),
),
onPressed: () {
if (opt.dismissOnClicked && Navigator.canPop(context)) {
Navigator.pop(context);
}
setOption(opt.value);
},
),
); );
} }
@ -285,48 +289,50 @@ class MenuEntrySubRadios<T> extends MenuEntryBase<T> {
return mod_menu.PopupMenuItem( return mod_menu.PopupMenuItem(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
height: conf.height, height: conf.height,
child: TextButton( child: Container(
child: Container( width: conf.boxWidth,
padding: padding, child: TextButton(
alignment: AlignmentDirectional.centerStart, child: Container(
constraints: padding: padding,
BoxConstraints(minHeight: conf.height, maxHeight: conf.height), alignment: AlignmentDirectional.centerStart,
child: Row( constraints: BoxConstraints(
children: [ minHeight: conf.height, maxHeight: conf.height),
Text( child: Row(
opt.text, children: [
style: TextStyle( Text(
color: Theme.of(context).textTheme.titleLarge?.color, opt.text,
fontSize: MenuConfig.fontSize, style: TextStyle(
fontWeight: FontWeight.normal), 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())),
)),
],
), ),
Expanded( ),
child: Align( onPressed: () {
alignment: Alignment.centerRight, if (opt.dismissOnClicked && Navigator.canPop(context)) {
child: Transform.scale( Navigator.pop(context);
scale: MenuConfig.iconScale, }
child: Obx(() => opt.value == curOption.value setOption(opt.value);
? IconButton( },
padding: EdgeInsets.zero, )),
hoverColor: Colors.transparent,
focusColor: Colors.transparent,
onPressed: () {},
icon: Icon(
Icons.check,
color: conf.commonColor,
))
: const SizedBox.shrink())),
)),
],
),
),
onPressed: () {
if (opt.dismissOnClicked && Navigator.canPop(context)) {
Navigator.pop(context);
}
setOption(opt.value);
},
),
); );
} }
@ -401,55 +407,57 @@ abstract class MenuEntrySwitchBase<T> extends MenuEntryBase<T> {
mod_menu.PopupMenuItem( mod_menu.PopupMenuItem(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
height: conf.height, height: conf.height,
child: TextButton( child: Container(
child: Container( width: conf.boxWidth,
padding: padding, child: TextButton(
alignment: AlignmentDirectional.centerStart, child: Container(
height: conf.height, padding: padding,
child: Row(children: [ alignment: AlignmentDirectional.centerStart,
Obx(() => Text( height: conf.height,
text, child: Row(children: [
style: textStyle!.value, Obx(() => Text(
)), text,
Expanded( style: textStyle!.value,
child: Align( )),
alignment: Alignment.centerRight, Expanded(
child: Transform.scale( child: Align(
scale: MenuConfig.iconScale, alignment: Alignment.centerRight,
child: Obx(() { child: Transform.scale(
if (switchType == SwitchType.sswitch) { scale: MenuConfig.iconScale,
return Switch( child: Obx(() {
value: curOption.value, if (switchType == SwitchType.sswitch) {
onChanged: (v) { return Switch(
if (super.dismissOnClicked && value: curOption.value,
Navigator.canPop(context)) { onChanged: (v) {
Navigator.pop(context); if (super.dismissOnClicked &&
} Navigator.canPop(context)) {
setOption(v); Navigator.pop(context);
}, }
); setOption(v);
} else { },
return Checkbox( );
value: curOption.value, } else {
onChanged: (v) { return Checkbox(
if (super.dismissOnClicked && value: curOption.value,
Navigator.canPop(context)) { onChanged: (v) {
Navigator.pop(context); if (super.dismissOnClicked &&
} Navigator.canPop(context)) {
setOption(v); Navigator.pop(context);
}, }
); setOption(v);
} },
})), );
)) }
])), })),
onPressed: () { ))
if (super.dismissOnClicked && Navigator.canPop(context)) { ])),
Navigator.pop(context); onPressed: () {
} if (super.dismissOnClicked && Navigator.canPop(context)) {
setOption(!curOption.value); Navigator.pop(context);
}, }
), setOption(!curOption.value);
},
)),
) )
]; ];
} }
@ -606,7 +614,9 @@ class MenuEntryButton<T> extends MenuEntryBase<T> {
fontSize: MenuConfig.fontSize, fontSize: MenuConfig.fontSize,
fontWeight: FontWeight.normal); fontWeight: FontWeight.normal);
super.enabled ??= true.obs; super.enabled ??= true.obs;
return Obx(() => TextButton( return Obx(() => Container(
width: conf.boxWidth,
child: TextButton(
onPressed: super.enabled!.value onPressed: super.enabled!.value
? () { ? () {
if (super.dismissOnClicked && Navigator.canPop(context)) { if (super.dismissOnClicked && Navigator.canPop(context)) {
@ -623,7 +633,7 @@ class MenuEntryButton<T> extends MenuEntryBase<T> {
child: childBuilder( child: childBuilder(
super.enabled!.value ? enabledStyle : disabledStyle), super.enabled!.value ? enabledStyle : disabledStyle),
), ),
)); )));
} }
@override @override

View File

@ -811,14 +811,16 @@ class ActionIcon extends StatelessWidget {
final IconData icon; final IconData icon;
final Function() onTap; final Function() onTap;
final bool isClose; final bool isClose;
final double? size; final double iconSize;
final double boxSize;
const ActionIcon( const ActionIcon(
{Key? key, {Key? key,
required this.message, required this.message,
required this.icon, required this.icon,
required this.onTap, required this.onTap,
required this.isClose, this.isClose = false,
this.size}) this.iconSize = _kActionIconSize,
this.boxSize = _kTabBarHeight - 1})
: super(key: key); : super(key: key);
@override @override
@ -834,14 +836,14 @@ class ActionIcon extends StatelessWidget {
onHover: (value) => hover.value = value, onHover: (value) => hover.value = value,
onTap: onTap, onTap: onTap,
child: SizedBox( child: SizedBox(
height: size ?? (_kTabBarHeight - 1), height: boxSize,
width: size ?? (_kTabBarHeight - 1), width: boxSize,
child: Icon( child: Icon(
icon, icon,
color: hover.value && isClose color: hover.value && isClose
? Colors.white ? Colors.white
: MyTheme.tabbar(context).unSelectedIconColor, : MyTheme.tabbar(context).unSelectedIconColor,
size: _kActionIconSize, size: iconSize,
), ),
), ),
), ),

View File

@ -221,7 +221,7 @@ void runConnectionManagerScreen() async {
windowManager.setOpacity(1) windowManager.setOpacity(1)
]); ]);
// ensure // ensure
windowManager.setAlignment(Alignment.topRight); windowManager.setAlignment(Alignment.topRight);
}); });
} }

View File

@ -402,6 +402,10 @@ class FileModel extends ChangeNotifier {
} }
} }
Future<FileDirectory> fetchDirectory(path, isLocal, showHidden) async {
return await _fileFetcher.fetchDirectory(path, isLocal, showHidden);
}
void pushHistory(bool isLocal) { void pushHistory(bool isLocal) {
final history = isLocal ? localHistory : remoteHistory; final history = isLocal ? localHistory : remoteHistory;
final currPath = isLocal ? currentLocalDir.path : currentRemoteDir.path; final currPath = isLocal ? currentLocalDir.path : currentRemoteDir.path;