diff --git a/lib/app.dart b/lib/app.dart index 69ac2cc6..bf39b183 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -18,8 +18,8 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { setTransparentNavigationBar(context); - primaryColor = Color(_setting.primaryColor.fetch()!); - final fullScreen = _setting.fullScreen.fetch()!; + primaryColor = Color(_setting.primaryColor.fetch()); + final fullScreen = _setting.fullScreen.fetch(); return ValueListenableBuilder( valueListenable: _setting.themeMode.listenable(), @@ -28,7 +28,7 @@ class MyApp extends StatelessWidget { // Issue #57 // if not [ok] -> [AMOLED] mode, use [ThemeMode.dark] final themeMode = isAMOLED ? ThemeMode.values[tMode] : ThemeMode.dark; - final locale = _setting.locale.fetch()?.toLocale; + final locale = _setting.locale.fetch().toLocale; final darkTheme = ThemeData( useMaterial3: true, brightness: Brightness.dark, diff --git a/lib/core/extension/order.dart b/lib/core/extension/order.dart index 474885c8..8ec05ffa 100644 --- a/lib/core/extension/order.dart +++ b/lib/core/extension/order.dart @@ -7,7 +7,7 @@ extension OrderX on Order { void move( int oldIndex, int newIndex, { - StoreProperty>? property, + StorePropertyBase>? property, _OnMove? onMove, }) { if (oldIndex == newIndex) return; @@ -35,7 +35,7 @@ extension OrderX on Order { List items, int o, int n, { - StoreProperty>? property, + StorePropertyBase>? property, _OnMove? onMove, }) { if (o == n) return; diff --git a/lib/core/persistant_store.dart b/lib/core/persistant_store.dart index 80efc489..0fe967ab 100644 --- a/lib/core/persistant_store.dart +++ b/lib/core/persistant_store.dart @@ -10,35 +10,72 @@ class PersistentStore { box = await Hive.openBox(boxName); return this; } - - StoreProperty property(String key, {T? defaultValue}) { - return StoreProperty(box, key, defaultValue); - } } -class StoreProperty { +abstract class StorePropertyBase { + ValueListenable listenable(); + T fetch(); + Future put(T value); + Future delete(); +} + +class StoreProperty implements StorePropertyBase { StoreProperty(this._box, this._key, this.defaultValue); final Box _box; final String _key; - T? defaultValue; + T defaultValue; + @override ValueListenable listenable() { return PropertyListenable(_box, _key, defaultValue); } - T? fetch() { - return _box.get(_key, defaultValue: defaultValue); - } - - dynamic fetchRaw() { - return _box.get(_key, defaultValue: defaultValue); + @override + T fetch() { + return _box.get(_key, defaultValue: defaultValue)!; } + @override Future put(T value) { return _box.put(_key, value); } + @override + Future delete() { + return _box.delete(_key); + } +} + +class StoreListProperty implements StorePropertyBase> { + StoreListProperty(this._box, this._key, this.defaultValue); + + final Box _box; + final String _key; + List defaultValue; + + @override + ValueListenable> listenable() { + return PropertyListenable>(_box, _key, defaultValue); + } + + @override + List fetch() { + final val = _box.get(_key, defaultValue: defaultValue)!; + + if (val is! List) { + throw Exception('StoreListProperty("$_key") is: ${val.runtimeType}'); + } + + return List.from(val); + } + + @override + Future put(List value) { + return _box.put(_key, value); + } + + @override Future delete() { return _box.delete(_key); } diff --git a/lib/core/utils/ui.dart b/lib/core/utils/ui.dart index 36c2ae43..ea9a1715 100644 --- a/lib/core/utils/ui.dart +++ b/lib/core/utils/ui.dart @@ -76,7 +76,7 @@ void showLoadingDialog(BuildContext context, {bool barrierDismiss = false}) { Widget buildSwitch( BuildContext context, - StoreProperty prop, { + StorePropertyBase prop, { void Function(bool)? func, }) { return ValueListenableBuilder( @@ -115,8 +115,8 @@ String tabTitleName(BuildContext context, AppTab tab) { } } -Future loadFontFile(String? localPath) async { - if (localPath == null) return; +Future loadFontFile(String localPath) async { + if (localPath.isEmpty) return; final name = getFileName(localPath); if (name == null) return; var fontLoader = FontLoader(name); diff --git a/lib/data/model/server/try_limiter.dart b/lib/data/model/server/try_limiter.dart index 6b477879..e6b3b1c9 100644 --- a/lib/data/model/server/try_limiter.dart +++ b/lib/data/model/server/try_limiter.dart @@ -5,7 +5,7 @@ class TryLimiter { final Map _triedTimes = {}; bool canTry(String id) { - final maxCount = locator().maxRetryCount.fetch()!; + final maxCount = locator().maxRetryCount.fetch(); if (maxCount <= 0) { return true; } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 5ab31335..55dd5f9d 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -49,7 +49,7 @@ class ServerProvider extends ChangeNotifier { _servers[spi.id] = genServer(spi); } final serverOrder_ = _settingStore.serverOrder.fetch(); - if (serverOrder_ != null) { + if (serverOrder_.isNotEmpty) { spis.reorder( order: serverOrder_, finder: (n, id) => n.id == id, @@ -112,7 +112,7 @@ class ServerProvider extends ChangeNotifier { } Future startAutoRefresh() async { - final duration = _settingStore.serverStatusUpdateInterval.fetch()!; + final duration = _settingStore.serverStatusUpdateInterval.fetch(); stopAutoRefresh(); if (duration == 0) return; _timer = Timer.periodic(Duration(seconds: duration), (_) async { diff --git a/lib/data/provider/snippet.dart b/lib/data/provider/snippet.dart index 921c407f..e050fe27 100644 --- a/lib/data/provider/snippet.dart +++ b/lib/data/provider/snippet.dart @@ -21,7 +21,7 @@ class SnippetProvider extends ChangeNotifier { void loadData() { _snippets = _store.fetch(); final order = _setting.snippetOrder.fetch(); - if (order != null) { + if (order.isNotEmpty) { final surplus = _snippets.reorder( order: order, finder: (n, name) => n.name == name, diff --git a/lib/data/provider/virtual_keyboard.dart b/lib/data/provider/virtual_keyboard.dart index 5f02efe4..b1a5127f 100644 --- a/lib/data/provider/virtual_keyboard.dart +++ b/lib/data/provider/virtual_keyboard.dart @@ -42,7 +42,7 @@ class VirtualKeyboard extends TerminalInputHandler with ChangeNotifier { ctrl: event.ctrl || ctrl, alt: event.alt || alt, ); - if (_setting.sshVirtualKeyAutoOff.fetch()!) { + if (_setting.sshVirtualKeyAutoOff.fetch()) { reset(e); } return defaultInputHandler.call(e); diff --git a/lib/data/res/color.dart b/lib/data/res/color.dart index c9b1aea0..046231c6 100644 --- a/lib/data/res/color.dart +++ b/lib/data/res/color.dart @@ -4,7 +4,7 @@ import 'package:toolbox/locator.dart'; import '../model/app/dynamic_color.dart'; -Color primaryColor = Color(locator().primaryColor.fetch()!); +Color primaryColor = Color(locator().primaryColor.fetch()); final contentColor = DynamicColor(Colors.black87, Colors.white70); final bgColor = DynamicColor(Colors.white, Colors.black); diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index 6653ce28..a11e1488 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/core/utils/platform.dart'; -import 'package:toolbox/data/model/ssh/virtual_key.dart'; import '../model/app/net_view.dart'; import '../res/default.dart'; @@ -9,112 +8,142 @@ import '../res/default.dart'; class SettingStore extends PersistentStore { Map toJson() => {for (var e in box.keys) e: box.get(e)}; - StoreProperty get primaryColor => property( - 'primaryColor', - defaultValue: 4287106639, - ); + late final primaryColor = StoreProperty( + box, + 'primaryColor', + 4287106639, + ); - StoreProperty get serverStatusUpdateInterval => property( - 'serverStatusUpdateInterval', - defaultValue: defaultUpdateInterval, - ); + late final serverStatusUpdateInterval = StoreProperty( + box, + 'serverStatusUpdateInterval', + defaultUpdateInterval, + ); // Lanch page idx - StoreProperty get launchPage => property( - 'launchPage', - defaultValue: defaultLaunchPageIdx, - ); + late final launchPage = StoreProperty( + box, + 'launchPage', + defaultLaunchPageIdx, + ); // Version of store db - StoreProperty get storeVersion => - property('storeVersion', defaultValue: 0); + late final storeVersion = StoreProperty(box, 'storeVersion', 0); - StoreProperty get termColorIdx => - property('termColorIdx', defaultValue: 0); + late final termColorIdx = StoreProperty(box, 'termColorIdx', 0); // Max retry count when connect to server - StoreProperty get maxRetryCount => - property('maxRetryCount', defaultValue: 2); + late final maxRetryCount = StoreProperty(box, 'maxRetryCount', 2); // Night mode: 0 -> auto, 1 -> light, 2 -> dark - StoreProperty get themeMode => property('themeMode', defaultValue: 0); + late final themeMode = StoreProperty(box, 'themeMode', 0); // Font file path - StoreProperty get fontPath => property('fontPath'); + late final fontPath = StoreProperty(box, 'fontPath', ''); // Backgroud running (Android) - StoreProperty get bgRun => property('bgRun', defaultValue: isAndroid); + late final bgRun = StoreProperty(box, 'bgRun', isAndroid); // Server order - StoreProperty> get serverOrder => - property('serverOrder', defaultValue: null); + late final serverOrder = StoreListProperty(box, 'serverOrder', []); - StoreProperty> get snippetOrder => property( - 'snippetOrder', - defaultValue: null, - ); + late final snippetOrder = StoreListProperty(box, 'snippetOrder', []); // Server details page cards order - StoreProperty> get detailCardOrder => - property('detailCardPrder', defaultValue: defaultDetailCardOrder); + late final detailCardOrder = + StoreListProperty(box, 'detailCardPrder', defaultDetailCardOrder); // SSH term font size - StoreProperty get termFontSize => - property('termFontSize', defaultValue: 13); + late final termFontSize = StoreProperty(box, 'termFontSize', 13.0); // Server detail disk ignore path - StoreProperty> get diskIgnorePath => - property('diskIgnorePath', defaultValue: defaultDiskIgnorePath); + late final diskIgnorePath = + StoreListProperty(box, 'diskIgnorePath', defaultDiskIgnorePath); // Locale - StoreProperty get locale => property('locale', defaultValue: null); + late final locale = StoreProperty(box, 'locale', ''); // SSH virtual key (ctrl | alt) auto turn off - StoreProperty get sshVirtualKeyAutoOff => - property('sshVirtualKeyAutoOff', defaultValue: true); + late final sshVirtualKeyAutoOff = + StoreProperty(box, 'sshVirtualKeyAutoOff', true); - StoreProperty get editorFontSize => - property('editorFontSize', defaultValue: 13); + late final editorFontSize = StoreProperty(box, 'editorFontSize', 13.0); // Editor theme - StoreProperty get editorTheme => - property('editorTheme', defaultValue: defaultEditorTheme); + late final editorTheme = StoreProperty( + box, + 'editorTheme', + defaultEditorTheme, + ); - StoreProperty get editorDarkTheme => - property('editorDarkTheme', defaultValue: defaultEditorDarkTheme); + late final editorDarkTheme = StoreProperty( + box, + 'editorDarkTheme', + defaultEditorDarkTheme, + ); - StoreProperty get fullScreen => - property('fullScreen', defaultValue: false); + late final fullScreen = StoreProperty( + box, + 'fullScreen', + false, + ); - StoreProperty get fullScreenJitter => - property('fullScreenJitter', defaultValue: true); + late final fullScreenJitter = StoreProperty( + box, + 'fullScreenJitter', + true, + ); - StoreProperty get fullScreenRotateQuarter => - property('fullScreenRotateQuarter', defaultValue: 1); + late final fullScreenRotateQuarter = StoreProperty( + box, + 'fullScreenRotateQuarter', + 1, + ); - StoreProperty get keyboardType => - property('keyboardType', defaultValue: TextInputType.text.index); + late final keyboardType = StoreProperty( + box, + 'keyboardType', + TextInputType.text.index, + ); - StoreProperty> get sshVirtKeys => - property('sshVirtKeys', defaultValue: defaultSSHVirtKeys); + late final sshVirtKeys = StoreListProperty( + box, + 'sshVirtKeys', + defaultSSHVirtKeys, + ); - StoreProperty get netViewType => - property('netViewType', defaultValue: NetViewType.speed); + late final netViewType = StoreProperty( + box, + 'netViewType', + NetViewType.speed, + ); // Only valid on iOS - StoreProperty get autoUpdateHomeWidget => - property('autoUpdateHomeWidget', defaultValue: isIOS); + late final autoUpdateHomeWidget = StoreProperty( + box, + 'autoUpdateHomeWidget', + isIOS, + ); - StoreProperty get autoCheckAppUpdate => - property('autoCheckAppUpdate', defaultValue: true); + late final autoCheckAppUpdate = StoreProperty( + box, + 'autoCheckAppUpdate', + true, + ); /// Display server tab function buttons on the bottom of each server card if [true] /// /// Otherwise, display them on the top of server detail page - StoreProperty get moveOutServerTabFuncBtns => - property('moveOutServerTabFuncBtns', defaultValue: true); + late final moveOutServerTabFuncBtns = StoreProperty( + box, + 'moveOutServerTabFuncBtns', + true, + ); /// Whether use `rm -rf` to delete directory on SFTP - StoreProperty get sftpRmrfDir => - property('sftpRmrfDir', defaultValue: true); + late final sftpRmrfDir = StoreProperty( + box, + 'sftpRmrfDir', + true, + ); } diff --git a/lib/main.dart b/lib/main.dart index 20ad5634..ce63b3ea 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -96,7 +96,7 @@ Future initApp() async { // Android only if (!isAndroid) return; // Only start service when [bgRun] is true. - if (locator().bgRun.fetch() ?? false) { + if (locator().bgRun.fetch()) { bgRunChannel.invokeMethod('startService'); } // SharedPreferences is only used on Android for saving home widgets settings. diff --git a/lib/view/page/full_screen.dart b/lib/view/page/full_screen.dart index b76c64c8..de0f8e87 100644 --- a/lib/view/page/full_screen.dart +++ b/lib/view/page/full_screen.dart @@ -45,7 +45,7 @@ class _FullScreenPageState extends State with AfterLayoutMixin { void initState() { super.initState(); switchStatusBar(hide: true); - _rotateQuarter = _setting.fullScreenRotateQuarter.fetch()!; + _rotateQuarter = _setting.fullScreenRotateQuarter.fetch(); _timer = Timer.periodic(const Duration(minutes: 1), (_) { if (mounted) { setState(() {}); @@ -362,7 +362,7 @@ class _FullScreenPageState extends State with AfterLayoutMixin { @override Future afterFirstLayout(BuildContext context) async { - if (_setting.autoCheckAppUpdate.fetch()!) { + if (_setting.autoCheckAppUpdate.fetch()) { doUpdate(context); } await GetIt.I.allReady(); diff --git a/lib/view/page/home.dart b/lib/view/page/home.dart index c6618861..775adc87 100644 --- a/lib/view/page/home.dart +++ b/lib/view/page/home.dart @@ -54,7 +54,7 @@ class _HomePageState extends State super.initState(); switchStatusBar(hide: false); WidgetsBinding.instance.addObserver(this); - _selectIndex.value = _setting.launchPage.fetch()!; + _selectIndex.value = _setting.launchPage.fetch(); // avoid index out of range if (_selectIndex.value >= AppTab.values.length || _selectIndex.value < 0) { _selectIndex.value = 0; @@ -90,7 +90,7 @@ class _HomePageState extends State break; case AppLifecycleState.paused: // Keep running in background on Android device - if (isAndroid && _setting.bgRun.fetch()!) { + if (isAndroid && _setting.bgRun.fetch()) { if (_app.moveBg) { bgRunChannel.invokeMethod('sendToBackground'); } @@ -366,7 +366,7 @@ class _HomePageState extends State @override Future afterFirstLayout(BuildContext context) async { - if (_setting.autoCheckAppUpdate.fetch()!) { + if (_setting.autoCheckAppUpdate.fetch()) { doUpdate(context); } updateHomeWidget(); @@ -379,7 +379,7 @@ class _HomePageState extends State } void updateHomeWidget() { - if (_setting.autoUpdateHomeWidget.fetch()!) { + if (_setting.autoUpdateHomeWidget.fetch()) { homeWidgetChannel.invokeMethod('update'); } } diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index f27a1af9..d55fc682 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -61,7 +61,7 @@ class _ServerDetailPageState extends State @override void initState() { super.initState(); - _cardsOrder.addAll(_setting.detailCardOrder.fetch()!); + _cardsOrder.addAll(_setting.detailCardOrder.fetch()); } @override @@ -80,7 +80,7 @@ class _ServerDetailPageState extends State } Widget _buildMainPage(Server si) { - final buildFuncs = !_setting.moveOutServerTabFuncBtns.fetch()!; + final buildFuncs = !_setting.moveOutServerTabFuncBtns.fetch(); return Scaffold( appBar: CustomAppBar( title: Text(si.spi.name, style: textSize18), @@ -299,7 +299,7 @@ class _ServerDetailPageState extends State Widget _buildDiskView(ServerStatus ss) { final disk = ss.disk; disk.removeWhere((e) { - for (final ingorePath in _setting.diskIgnorePath.fetch()!) { + for (final ingorePath in _setting.diskIgnorePath.fetch()) { if (e.path.startsWith(ingorePath)) return true; } return false; diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 36e6e281..0e3efa66 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -238,7 +238,7 @@ class _ServerPageState extends State ), ), height13, - if (_settingStore.moveOutServerTabFuncBtns.fetch()!) + if (_settingStore.moveOutServerTabFuncBtns.fetch()) SizedBox( height: 27, child: ServerFuncBtns(spi: spi, s: _s), @@ -446,7 +446,7 @@ class _ServerPageState extends State if (cs != ServerState.finished) { return 23.0; } - if (_settingStore.moveOutServerTabFuncBtns.fetch()!) { + if (_settingStore.moveOutServerTabFuncBtns.fetch()) { return 132; } return 107; diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart index 82e130c0..ce625bf8 100644 --- a/lib/view/page/setting/entry.dart +++ b/lib/view/page/setting/entry.dart @@ -77,7 +77,12 @@ class _SettingPageState extends State { void didChangeDependencies() { super.didChangeDependencies(); _s = S.of(context)!; - _localeCode.value = _setting.locale.fetch() ?? _s.localeName; + final localeSettingVal = _setting.locale.fetch(); + if (localeSettingVal.isEmpty) { + _localeCode.value = _s.localeName; + } else { + _localeCode.value = localeSettingVal; + } } @override @@ -85,18 +90,18 @@ class _SettingPageState extends State { super.initState(); _serverProvider = locator(); _setting = locator(); - _launchPageIdx.value = _setting.launchPage.fetch()!; - _nightMode.value = _setting.themeMode.fetch()!; - _updateInterval.value = _setting.serverStatusUpdateInterval.fetch()!; - _maxRetryCount.value = _setting.maxRetryCount.fetch()!; - _selectedColorValue.value = _setting.primaryColor.fetch()!; - _termFontSize.value = _setting.termFontSize.fetch()!; - _editorFontSize.value = _setting.editorFontSize.fetch()!; - _editorTheme.value = _setting.editorTheme.fetch()!; - _editorDarkTheme.value = _setting.editorDarkTheme.fetch()!; - _keyboardType.value = _setting.keyboardType.fetch()!; - _rotateQuarter.value = _setting.fullScreenRotateQuarter.fetch()!; - _netViewType.value = _setting.netViewType.fetch()!; + _launchPageIdx.value = _setting.launchPage.fetch(); + _nightMode.value = _setting.themeMode.fetch(); + _updateInterval.value = _setting.serverStatusUpdateInterval.fetch(); + _maxRetryCount.value = _setting.maxRetryCount.fetch(); + _selectedColorValue.value = _setting.primaryColor.fetch(); + _termFontSize.value = _setting.termFontSize.fetch(); + _editorFontSize.value = _setting.editorFontSize.fetch(); + _editorTheme.value = _setting.editorTheme.fetch(); + _editorDarkTheme.value = _setting.editorDarkTheme.fetch(); + _keyboardType.value = _setting.keyboardType.fetch(); + _rotateQuarter.value = _setting.fullScreenRotateQuarter.fetch(); + _netViewType.value = _setting.netViewType.fetch(); SharedPreferences.getInstance().then((value) => _sp = value); } @@ -563,7 +568,7 @@ class _SettingPageState extends State { } Widget _buildDiskIgnorePath() { - final paths = _setting.diskIgnorePath.fetch()!; + final paths = _setting.diskIgnorePath.fetch(); return ListTile( title: Text(_s.diskIgnorePath), trailing: Text(_s.edit, style: textSize15), @@ -987,7 +992,7 @@ class _SettingPageState extends State { void _showFontSizeDialog( ValueNotifier notifier, - StoreProperty property, + StorePropertyBase property, ) { final ctrller = TextEditingController(text: notifier.value.toString()); void onSave() { diff --git a/lib/view/page/setting/srv_detail_seq.dart b/lib/view/page/setting/srv_detail_seq.dart index 3b1a567c..f4ded95e 100644 --- a/lib/view/page/setting/srv_detail_seq.dart +++ b/lib/view/page/setting/srv_detail_seq.dart @@ -30,7 +30,7 @@ class _ServerDetailOrderPageState extends State { @override void initState() { super.initState(); - _cardsOrder.addAll(_store.detailCardOrder.fetch()!); + _cardsOrder.addAll(_store.detailCardOrder.fetch()); } @override diff --git a/lib/view/page/setting/virt_key.dart b/lib/view/page/setting/virt_key.dart index a26518c9..5ff9874d 100644 --- a/lib/view/page/setting/virt_key.dart +++ b/lib/view/page/setting/virt_key.dart @@ -39,7 +39,7 @@ class _SSHVirtKeySettingPageState extends State { } Widget _buildBody() { - final keys_ = _setting.sshVirtKeys.fetchRaw()!; + final keys_ = _setting.sshVirtKeys.fetch(); final keys = []; for (final key in keys_) { keys.add(key); diff --git a/lib/view/page/ssh_term.dart b/lib/view/page/ssh_term.dart index 58ce2c31..74936811 100644 --- a/lib/view/page/ssh_term.dart +++ b/lib/view/page/ssh_term.dart @@ -61,10 +61,10 @@ class _SSHPageState extends State { final fontFamilly = getFileName(_setting.fontPath.fetch()); final textStyle = TextStyle( fontFamily: fontFamilly, - fontSize: _setting.termFontSize.fetch()!, + fontSize: _setting.termFontSize.fetch(), ); _terminalStyle = TerminalStyle.fromTextStyle(textStyle); - _keyboardType = TextInputType.values[_setting.keyboardType.fetch()!]; + _keyboardType = TextInputType.values[_setting.keyboardType.fetch()]; _initTerminal(); _initVirtKeys(); } @@ -299,7 +299,7 @@ class _SSHPageState extends State { } void _initVirtKeys() { - final virtKeys = List.from(_setting.sshVirtKeys.fetchRaw()); + final virtKeys = List.from(_setting.sshVirtKeys.fetch()); for (int len = 0; len < virtKeys.length; len += 7) { if (len + 7 > virtKeys.length) { diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart index 2f174925..37fcde46 100644 --- a/lib/view/page/storage/sftp.dart +++ b/lib/view/page/storage/sftp.dart @@ -430,7 +430,7 @@ class _SftpPageState extends State with AfterLayoutMixin { void _delete(BuildContext context, SftpName file) { context.pop(); final isDir = file.attr.isDirectory; - final useRmrf = _setting.sftpRmrfDir.fetch()!; + final useRmrf = _setting.sftpRmrfDir.fetch(); final dirText = (isDir && !useRmrf) ? '\n${_s.sureDirEmpty}' : ''; final text = '${_s.sureDelete(file.filename)}$dirText'; final child = Text(text);