integrate file search bar into path location
This commit is contained in:
parent
5b1a12c6a7
commit
baf437e6f0
@ -14,7 +14,17 @@ import '../../common.dart';
|
|||||||
import '../../models/model.dart';
|
import '../../models/model.dart';
|
||||||
import '../../models/platform_model.dart';
|
import '../../models/platform_model.dart';
|
||||||
|
|
||||||
enum LocationStatus { bread, textField }
|
/// status of location bar
|
||||||
|
enum LocationStatus {
|
||||||
|
/// normal bread crumb bar
|
||||||
|
bread,
|
||||||
|
|
||||||
|
/// show path text field
|
||||||
|
pathLocation,
|
||||||
|
|
||||||
|
/// show file search bar text field
|
||||||
|
fileSearchBar
|
||||||
|
}
|
||||||
|
|
||||||
class FileManagerPage extends StatefulWidget {
|
class FileManagerPage extends StatefulWidget {
|
||||||
const FileManagerPage({Key? key, required this.id}) : super(key: key);
|
const FileManagerPage({Key? key, required this.id}) : super(key: key);
|
||||||
@ -40,7 +50,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
final _breadCrumbScrollerLocal = ScrollController();
|
final _breadCrumbScrollerLocal = ScrollController();
|
||||||
final _breadCrumbScrollerRemote = ScrollController();
|
final _breadCrumbScrollerRemote = ScrollController();
|
||||||
|
|
||||||
final _dropMaskVisible = false.obs;
|
final _dropMaskVisible = false.obs; // TODO impl drop mask
|
||||||
|
|
||||||
ScrollController getBreadCrumbScrollController(bool isLocal) {
|
ScrollController getBreadCrumbScrollController(bool isLocal) {
|
||||||
return isLocal ? _breadCrumbScrollerLocal : _breadCrumbScrollerRemote;
|
return isLocal ? _breadCrumbScrollerLocal : _breadCrumbScrollerRemote;
|
||||||
@ -84,6 +94,8 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
Get.delete<FFI>(tag: 'ft_${widget.id}');
|
Get.delete<FFI>(tag: 'ft_${widget.id}');
|
||||||
_locationNodeLocal.removeListener(onLocalLocationFocusChanged);
|
_locationNodeLocal.removeListener(onLocalLocationFocusChanged);
|
||||||
_locationNodeRemote.removeListener(onRemoteLocationFocusChanged);
|
_locationNodeRemote.removeListener(onRemoteLocationFocusChanged);
|
||||||
|
_locationNodeLocal.dispose();
|
||||||
|
_locationNodeRemote.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,14 +108,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: _ffi.fileModel,
|
value: _ffi.fileModel,
|
||||||
child: Consumer<FileModel>(builder: (context, model, child) {
|
child: Consumer<FileModel>(builder: (context, model, child) {
|
||||||
return WillPopScope(
|
return Scaffold(
|
||||||
onWillPop: () async {
|
|
||||||
if (model.selectMode) {
|
|
||||||
model.toggleSelectMode();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor: Theme.of(context).backgroundColor,
|
backgroundColor: Theme.of(context).backgroundColor,
|
||||||
body: Row(
|
body: Row(
|
||||||
children: [
|
children: [
|
||||||
@ -112,7 +117,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
Flexible(flex: 2, child: statusList())
|
Flexible(flex: 2, child: statusList())
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
));
|
);
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
@ -406,8 +411,6 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
final locationStatus =
|
final locationStatus =
|
||||||
isLocal ? _locationStatusLocal : _locationStatusRemote;
|
isLocal ? _locationStatusLocal : _locationStatusRemote;
|
||||||
final locationFocus = isLocal ? _locationNodeLocal : _locationNodeRemote;
|
final locationFocus = isLocal ? _locationNodeLocal : _locationNodeRemote;
|
||||||
final searchTextObs = isLocal ? _searchTextLocal : _searchTextRemote;
|
|
||||||
final searchController = TextEditingController(text: searchTextObs.value);
|
|
||||||
return Container(
|
return Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -473,73 +476,62 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
locationStatus.value =
|
locationStatus.value =
|
||||||
locationStatus.value == LocationStatus.bread
|
locationStatus.value == LocationStatus.bread
|
||||||
? LocationStatus.textField
|
? LocationStatus.pathLocation
|
||||||
: LocationStatus.bread;
|
: LocationStatus.bread;
|
||||||
Future.delayed(Duration.zero, () {
|
Future.delayed(Duration.zero, () {
|
||||||
if (locationStatus.value == LocationStatus.textField) {
|
if (locationStatus.value == LocationStatus.pathLocation) {
|
||||||
locationFocus.requestFocus();
|
locationFocus.requestFocus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Obx(() => Container(
|
||||||
decoration:
|
decoration: BoxDecoration(
|
||||||
BoxDecoration(border: Border.all(color: Colors.black12)),
|
border: Border.all(
|
||||||
|
color: locationStatus.value == LocationStatus.bread
|
||||||
|
? Colors.black12
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary
|
||||||
|
.withOpacity(0.5))),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(() =>
|
child: locationStatus.value == LocationStatus.bread
|
||||||
locationStatus.value == LocationStatus.bread
|
|
||||||
? buildBread(isLocal)
|
? buildBread(isLocal)
|
||||||
: buildPathLocation(isLocal))),
|
: buildPathLocation(isLocal)),
|
||||||
DropdownButton<String>(
|
|
||||||
isDense: true,
|
|
||||||
underline: Offstage(),
|
|
||||||
items: [
|
|
||||||
// TODO: favourite
|
|
||||||
DropdownMenuItem(
|
|
||||||
child: Text('/'),
|
|
||||||
value: '/',
|
|
||||||
)
|
|
||||||
],
|
|
||||||
onChanged: (path) {
|
|
||||||
if (path is String && path.isNotEmpty) {
|
|
||||||
openDirectory(path, isLocal: isLocal);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
],
|
],
|
||||||
|
))),
|
||||||
)),
|
)),
|
||||||
)),
|
Obx(() {
|
||||||
PopupMenuButton(
|
switch (locationStatus.value) {
|
||||||
tooltip: "",
|
case LocationStatus.bread:
|
||||||
itemBuilder: (context) => [
|
return IconButton(
|
||||||
PopupMenuItem(
|
|
||||||
enabled: false,
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(minWidth: 200),
|
|
||||||
child: TextField(
|
|
||||||
textAlignVertical: TextAlignVertical.center,
|
|
||||||
controller: searchController,
|
|
||||||
autofocus: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: Icon(Icons.search),
|
|
||||||
suffix: IconButton(
|
|
||||||
icon: Icon(Icons.clear),
|
|
||||||
splashRadius: 20,
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
searchController.clear();
|
locationStatus.value = LocationStatus.fileSearchBar;
|
||||||
searchTextObs.value = "";
|
final focusNode =
|
||||||
Get.back();
|
isLocal ? _locationNodeLocal : _locationNodeRemote;
|
||||||
|
Future.delayed(
|
||||||
|
Duration.zero, () => focusNode.requestFocus());
|
||||||
},
|
},
|
||||||
),
|
|
||||||
),
|
|
||||||
onChanged: (searchText) =>
|
|
||||||
onSearchText(searchText, isLocal),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
splashRadius: 20,
|
splashRadius: 20,
|
||||||
icon: const Icon(Icons.search),
|
icon: Icon(Icons.search));
|
||||||
),
|
case LocationStatus.pathLocation:
|
||||||
|
return IconButton(
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
onPressed: null,
|
||||||
|
splashRadius: 20,
|
||||||
|
icon: Icon(Icons.close));
|
||||||
|
case LocationStatus.fileSearchBar:
|
||||||
|
return IconButton(
|
||||||
|
color: Theme.of(context).disabledColor,
|
||||||
|
onPressed: () {
|
||||||
|
onSearchText("", isLocal);
|
||||||
|
locationStatus.value = LocationStatus.bread;
|
||||||
|
},
|
||||||
|
splashRadius: 1,
|
||||||
|
icon: Icon(Icons.close));
|
||||||
|
}
|
||||||
|
}),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
model.refresh(isLocal: isLocal);
|
model.refresh(isLocal: isLocal);
|
||||||
@ -649,9 +641,11 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
// ignore
|
// ignore
|
||||||
} else {
|
} else {
|
||||||
// lost focus, change to bread
|
// lost focus, change to bread
|
||||||
|
if (_locationStatusLocal.value != LocationStatus.fileSearchBar) {
|
||||||
_locationStatusLocal.value = LocationStatus.bread;
|
_locationStatusLocal.value = LocationStatus.bread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void onRemoteLocationFocusChanged() {
|
void onRemoteLocationFocusChanged() {
|
||||||
debugPrint("focus changed on remote");
|
debugPrint("focus changed on remote");
|
||||||
@ -659,9 +653,11 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
// ignore
|
// ignore
|
||||||
} else {
|
} else {
|
||||||
// lost focus, change to bread
|
// lost focus, change to bread
|
||||||
|
if (_locationStatusRemote.value != LocationStatus.fileSearchBar) {
|
||||||
_locationStatusRemote.value = LocationStatus.bread;
|
_locationStatusRemote.value = LocationStatus.bread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildBread(bool isLocal) {
|
Widget buildBread(bool isLocal) {
|
||||||
final items = getPathBreadCrumbItems(isLocal, (list) {
|
final items = getPathBreadCrumbItems(isLocal, (list) {
|
||||||
@ -671,14 +667,33 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
}
|
}
|
||||||
openDirectory(path, isLocal: isLocal);
|
openDirectory(path, isLocal: isLocal);
|
||||||
});
|
});
|
||||||
|
breadCrumbScrollToEnd(isLocal);
|
||||||
return items.isEmpty
|
return items.isEmpty
|
||||||
? Offstage()
|
? Offstage()
|
||||||
: BreadCrumb(
|
: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||||
|
Expanded(
|
||||||
|
child: BreadCrumb(
|
||||||
items: items,
|
items: items,
|
||||||
divider: Text("/").paddingSymmetric(horizontal: 4.0),
|
divider: Text("/").paddingSymmetric(horizontal: 4.0),
|
||||||
overflow: ScrollableOverflow(
|
overflow: ScrollableOverflow(
|
||||||
controller: getBreadCrumbScrollController(isLocal)),
|
controller: getBreadCrumbScrollController(isLocal)),
|
||||||
);
|
)),
|
||||||
|
DropdownButton<String>(
|
||||||
|
isDense: true,
|
||||||
|
underline: Offstage(),
|
||||||
|
items: [
|
||||||
|
// TODO: favourite
|
||||||
|
DropdownMenuItem(
|
||||||
|
child: Text('/'),
|
||||||
|
value: '/',
|
||||||
|
)
|
||||||
|
],
|
||||||
|
onChanged: (path) {
|
||||||
|
if (path is String && path.isNotEmpty) {
|
||||||
|
openDirectory(path, isLocal: isLocal);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BreadCrumbItem> getPathBreadCrumbItems(
|
List<BreadCrumbItem> getPathBreadCrumbItems(
|
||||||
@ -705,19 +720,37 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildPathLocation(bool isLocal) {
|
Widget buildPathLocation(bool isLocal) {
|
||||||
return TextField(
|
final searchTextObs = isLocal ? _searchTextLocal : _searchTextRemote;
|
||||||
focusNode: isLocal ? _locationNodeLocal : _locationNodeRemote,
|
final locationStatus =
|
||||||
|
isLocal ? _locationStatusLocal : _locationStatusRemote;
|
||||||
|
final focusNode = isLocal ? _locationNodeLocal : _locationNodeRemote;
|
||||||
|
return Row(children: [
|
||||||
|
Icon(
|
||||||
|
locationStatus.value == LocationStatus.pathLocation
|
||||||
|
? Icons.folder
|
||||||
|
: Icons.search,
|
||||||
|
color: Theme.of(context).hintColor,
|
||||||
|
).paddingSymmetric(horizontal: 2),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
focusNode: focusNode,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
isDense: true,
|
isDense: true,
|
||||||
prefix: Padding(padding: EdgeInsets.only(left: 4.0)),
|
prefix: Padding(padding: EdgeInsets.only(left: 4.0))),
|
||||||
),
|
controller: locationStatus.value == LocationStatus.pathLocation
|
||||||
controller:
|
? TextEditingController(text: model.getCurrentDir(isLocal).path)
|
||||||
TextEditingController(text: model.getCurrentDir(isLocal).path),
|
: TextEditingController(text: searchTextObs.value)
|
||||||
|
..selection =
|
||||||
|
TextSelection.collapsed(offset: searchTextObs.value.length),
|
||||||
onSubmitted: (path) {
|
onSubmitted: (path) {
|
||||||
openDirectory(path, isLocal: isLocal);
|
openDirectory(path, isLocal: isLocal);
|
||||||
},
|
},
|
||||||
);
|
onChanged: locationStatus.value == LocationStatus.fileSearchBar
|
||||||
|
? (searchText) => onSearchText(searchText, isLocal)
|
||||||
|
: null,
|
||||||
|
))
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchText(String searchText, bool isLocal) {
|
onSearchText(String searchText, bool isLocal) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user