diff --git a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index b8988c8dd..90a26b2c8 100644 --- a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -76,6 +76,7 @@ class MainActivity : FlutterActivity() { "request_permission" -> { if(call.arguments is String){ requestPermission(context, call.arguments as String) + result.success(true) } else { result.success(false) } diff --git a/lib/models/file_model.dart b/lib/models/file_model.dart index 0af75ec33..e37149e3c 100644 --- a/lib/models/file_model.dart +++ b/lib/models/file_model.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/pages/file_manager_page.dart'; -import 'package:path/path.dart' as p; import 'package:flutter/material.dart'; import 'package:path/path.dart' as Path; @@ -11,14 +10,6 @@ import 'model.dart'; enum SortBy { Name, Type, Modified, Size } -// enum FileType { -// Dir = 0, -// DirLink = 2, -// DirDrive = 3, -// File = 4, -// FileLink = 5, -// } - class FileModel extends ChangeNotifier { var _isLocal = false; var _selectMode = false; @@ -55,15 +46,15 @@ class FileModel extends ChangeNotifier { String get currentHome => _isLocal ? _localOption.home : _remoteOption.home; String get currentShortPath { - if(currentDir.path.startsWith(currentHome)){ + if (currentDir.path.startsWith(currentHome)) { var path = currentDir.path.replaceFirst(currentHome, ""); - if(path.length ==0 ) return ""; - if(path[0] == "/" || path[0] == "\\") { + if (path.length == 0) return ""; + if (path[0] == "/" || path[0] == "\\") { // remove more '/' or '\' path = path.replaceFirst(path[0], ""); } return path; - }else{ + } else { return currentDir.path.replaceFirst(currentHome, ""); } } @@ -112,6 +103,18 @@ class FileModel extends ChangeNotifier { } receiveFileDir(Map evt) { + if (_remoteOption.home.isEmpty && evt['is_local'] == "false") { + // init remote home, the connection will automatic read remote home when established, + try { + final fd = FileDirectory.fromJson(jsonDecode(evt['value'])); + fd.format(_remoteOption.isWindows, sort: _sortStyle); + _remoteOption.home = fd.path; + debugPrint("init remote home:${fd.path}"); + _currentRemoteDir = fd; + notifyListeners(); + return; + } finally {} + } _fileFetcher.tryCompleteTask(evt['value'], evt['is_local']); } @@ -143,29 +146,30 @@ class FileModel extends ChangeNotifier { notifyListeners(); } - onReady() { - _localOption = DirectoryOption( - home: FFI.getByName("get_home_dir"), - showHidden: FFI.getByName("peer_option", "local_show_hidden") != ""); - _remoteOption = DirectoryOption( - home: FFI.ffiModel.pi.homeDir, - showHidden: FFI.getByName("peer_option", "remote_show_hidden") != "", - isWindows: FFI.ffiModel.pi.platform == "Windows"); + onReady() async { + _localOption.home = FFI.getByName("get_home_dir"); + _localOption.showHidden = + FFI.getByName("peer_option", "local_show_hidden").isNotEmpty; + + _remoteOption.showHidden = + FFI.getByName("peer_option", "remote_show_hidden").isNotEmpty; + _remoteOption.isWindows = FFI.ffiModel.pi.platform == "Windows"; debugPrint("remote platform: ${FFI.ffiModel.pi.platform}"); + await Future.delayed(Duration(milliseconds: 100)); + final local = FFI.getByName("peer_option", "local_dir"); final remote = FFI.getByName("peer_option", "remote_dir"); openDirectory(local.isEmpty ? _localOption.home : local, isLocal: true); openDirectory(remote.isEmpty ? _remoteOption.home : remote, isLocal: false); - Timer(Duration(seconds: 2), () { - if (_currentLocalDir.path.isEmpty) { - openDirectory(_localOption.home, isLocal: true); - } - if (_currentRemoteDir.path.isEmpty) { - openDirectory(_remoteOption.home, isLocal: false); - } - }); + await Future.delayed(Duration(seconds: 1)); + if (_currentLocalDir.path.isEmpty) { + openDirectory(_localOption.home, isLocal: true); + } + if (_currentRemoteDir.path.isEmpty) { + openDirectory(_remoteOption.home, isLocal: false); + } } onClose() { @@ -192,6 +196,8 @@ class FileModel extends ChangeNotifier { FFI.setByName('peer_option', jsonEncode(msg)); _currentLocalDir.clear(); _currentRemoteDir.clear(); + _localOption.clear(); + _remoteOption.clear(); } refresh() { @@ -223,7 +229,8 @@ class FileModel extends ChangeNotifier { } goToParentDirectory() { - openDirectory(currentDir.parent); + final parent = PathUtil.dirname(currentDir.path, currentIsWindows); + openDirectory(parent); } sendFiles(SelectedItems items) { @@ -278,7 +285,11 @@ class FileModel extends ChangeNotifier { fd.format(isWindows); EasyLoading.dismiss(); if (fd.entries.isEmpty) { - final confirm = await showRemoveDialog(translate("Are you sure you want to delete this empty directory?"), item.name, false); + final confirm = await showRemoveDialog( + translate( + "Are you sure you want to delete this empty directory?"), + item.name, + false); if (confirm == true) { sendRemoveEmptyDir(item.path, 0, items.isLocal!); } @@ -290,9 +301,10 @@ class FileModel extends ChangeNotifier { } for (var i = 0; i < entries.length; i++) { - final dirShow = item.isDirectory ? "${translate("Are you sure you want to delete the file of this directory?")}\n" : ""; - final count = - entries.length > 1 ? "${i + 1}/${entries.length}" : ""; + final dirShow = item.isDirectory + ? "${translate("Are you sure you want to delete the file of this directory?")}\n" + : ""; + final count = entries.length > 1 ? "${i + 1}/${entries.length}" : ""; content = dirShow + "$count \n${entries[i].path}"; final confirm = await showRemoveDialog(title, content, item.isDirectory); @@ -403,7 +415,7 @@ class FileModel extends ChangeNotifier { } cancelJob(int id) { - FFI.setByName("cancel_job",id.toString()); + FFI.setByName("cancel_job", id.toString()); } changeSortStyle(SortBy sort) { @@ -563,8 +575,6 @@ class FileDirectory { int id = 0; String path = ""; - String get parent => p.dirname(path); - FileDirectory(); FileDirectory.fromJson(Map json) { @@ -659,6 +669,11 @@ class PathUtil { final pathUtil = isWindows ? windowsContext : posixContext; return pathUtil.split(path); } + + static String dirname(String path, bool isWindows){ + final pathUtil = isWindows ? windowsContext : posixContext; + return pathUtil.dirname(path); + } } class DirectoryOption { @@ -668,6 +683,12 @@ class DirectoryOption { DirectoryOption( {this.home = "", this.showHidden = false, this.isWindows = false}); + + clear() { + home = ""; + showHidden = false; + isWindows = false; + } } // code from file_manager pkg after edit diff --git a/lib/models/model.dart b/lib/models/model.dart index ccffbbd0a..6a8da9c26 100644 --- a/lib/models/model.dart +++ b/lib/models/model.dart @@ -235,7 +235,6 @@ class FfiModel with ChangeNotifier { _pi.platform = evt['platform']; _pi.sasEnabled = evt['sas_enabled'] == "true"; _pi.currentDisplay = int.parse(evt['current_display']); - _pi.homeDir = evt['home_dir']; if (evt['is_file_transfer'] == "true") { FFI.fileModel.onReady(); @@ -878,7 +877,6 @@ class PeerInfo { String username = ""; String hostname = ""; String platform = ""; - String homeDir = ""; bool sasEnabled = false; int currentDisplay = 0; List displays = []; diff --git a/lib/pages/file_manager_page.dart b/lib/pages/file_manager_page.dart index 2c3e16881..dd0772f8f 100644 --- a/lib/pages/file_manager_page.dart +++ b/lib/pages/file_manager_page.dart @@ -4,6 +4,7 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_hbb/models/file_model.dart'; import 'package:provider/provider.dart'; import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; +import 'package:toggle_switch/toggle_switch.dart'; import '../common.dart'; import '../models/model.dart'; @@ -58,17 +59,124 @@ class _FileManagerPageState extends State { backgroundColor: MyTheme.grayBg, appBar: AppBar( leading: Row(children: [ - IconButton(icon: Icon(Icons.arrow_back), onPressed: goBack), IconButton(icon: Icon(Icons.close), onPressed: clientClose), ]), - leadingWidth: 200, centerTitle: true, - title: Text(translate(model.isLocal ? "Local" : "Remote")), + title: ToggleSwitch( + initialLabelIndex: model.isLocal ? 0 : 1, + activeBgColor: [MyTheme.idColor], + inactiveBgColor: MyTheme.grayBg, + inactiveFgColor: Colors.black54, + totalSwitches: 2, + minWidth: 100, + fontSize: 15, + iconSize: 18, + labels: [translate("Local"), translate("Remote")], + icons: [Icons.phone_android_sharp, Icons.screen_share], + onToggle: (index) { + final current = model.isLocal ? 0 : 1; + if (index != current) { + model.togglePage(); + } + }, + ), actions: [ - IconButton( - icon: Icon(Icons.change_circle), - onPressed: () => model.togglePage(), - ) + PopupMenuButton( + icon: Icon(Icons.more_vert), + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Row( + children: [ + Icon(Icons.refresh, color: Colors.black), + SizedBox(width: 5), + Text(translate("Refresh File")) + ], + ), + value: "refresh", + ), + PopupMenuItem( + child: Row( + children: [ + Icon(Icons.check, color: Colors.black), + SizedBox(width: 5), + Text(translate("Multi Select")) + ], + ), + value: "select", + ), + PopupMenuItem( + child: Row( + children: [ + Icon(Icons.folder_outlined, + color: Colors.black), + SizedBox(width: 5), + Text(translate("Create Folder")) + ], + ), + value: "folder", + ), + PopupMenuItem( + child: Row( + children: [ + Icon( + model.currentShowHidden + ? Icons.check_box_outlined + : Icons.check_box_outline_blank, + color: Colors.black), + SizedBox(width: 5), + Text(translate("Show Hidden Files")) + ], + ), + value: "hidden", + ) + ]; + }, + onSelected: (v) { + if (v == "refresh") { + model.refresh(); + } else if (v == "select") { + _selectedItems.clear(); + model.toggleSelectMode(); + } else if (v == "folder") { + final name = TextEditingController(); + DialogManager.show( + (setState, close) => CustomAlertDialog( + title: Text(translate("Create Folder")), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + decoration: InputDecoration( + labelText: translate( + "Please enter the folder name"), + ), + controller: name, + ), + ], + ), + actions: [ + TextButton( + style: flatButtonStyle, + onPressed: () => close(false), + child: Text(translate("Cancel"))), + ElevatedButton( + style: flatButtonStyle, + onPressed: () { + if (name.value.text.isNotEmpty) { + model.createDir(PathUtil.join( + model.currentDir.path, + name.value.text, + model.currentIsWindows)); + close(); + } + }, + child: Text(translate("OK"))) + ])); + } else if (v == "hidden") { + model.toggleShowHidden(); + } + }), ], ), body: body(), @@ -224,6 +332,10 @@ class _FileManagerPageState extends State { )), Row( children: [ + IconButton( + icon: Icon(Icons.arrow_upward), + onPressed: goBack, + ), PopupMenuButton( icon: Icon(Icons.sort), itemBuilder: (context) { @@ -236,98 +348,6 @@ class _FileManagerPageState extends State { .toList(); }, onSelected: model.changeSortStyle), - PopupMenuButton( - icon: Icon(Icons.more_vert), - itemBuilder: (context) { - return [ - PopupMenuItem( - child: Row( - children: [ - Icon(Icons.refresh), - SizedBox(width: 5), - Text(translate("Refresh File")) - ], - ), - value: "refresh", - ), - PopupMenuItem( - child: Row( - children: [ - Icon(Icons.check), - SizedBox(width: 5), - Text(translate("Multi Select")) - ], - ), - value: "select", - ), - PopupMenuItem( - child: Row( - children: [ - Icon(Icons.folder_outlined), - SizedBox(width: 5), - Text(translate("Create Folder")) - ], - ), - value: "folder", - ), - PopupMenuItem( - child: Row( - children: [ - Icon(model.currentShowHidden - ? Icons.check_box_outlined - : Icons.check_box_outline_blank), - SizedBox(width: 5), - Text(translate("Show Hidden Files")) - ], - ), - value: "hidden", - ) - ]; - }, - onSelected: (v) { - if (v == "refresh") { - model.refresh(); - } else if (v == "select") { - _selectedItems.clear(); - model.toggleSelectMode(); - } else if (v == "folder") { - final name = TextEditingController(); - DialogManager.show((setState, close) => CustomAlertDialog( - title: Text(translate("Create Folder")), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextFormField( - decoration: InputDecoration( - labelText: translate( - "Please enter the folder name"), - ), - controller: name, - ), - ], - ), - actions: [ - TextButton( - style: flatButtonStyle, - onPressed: () => close(false), - child: Text(translate("Cancel"))), - ElevatedButton( - style: flatButtonStyle, - onPressed: () { - if (name.value.text.isNotEmpty) { - model.createDir(PathUtil.join( - model.currentDir.path, - name.value.text, - model.currentIsWindows)); - close(); - } - }, - child: Text(translate("OK"))) - ])); - } else if (v == "hidden") { - model.toggleShowHidden(); - } - }), ], ) ], @@ -338,6 +358,13 @@ class _FileManagerPageState extends State { height: 100, child: Column( children: [ + Padding( + padding: EdgeInsets.fromLTRB(30,5,30,0), + child: Text( + model.currentDir.path, + style: TextStyle(color: MyTheme.darkGray), + ), + ), Padding( padding: EdgeInsets.all(2), child: Text(