설정 A 분야 11: 탐색기 도구 (ExplorerToolSettings) - 시스템 폴더 · 루트 · Wi-Fi 공유 · ZIP 수준, 키 6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>modular
parent
a35293271e
commit
828d978812
|
|
@ -15,6 +15,7 @@ import '../services/app_shell.dart' show appIconOf;
|
||||||
import '../core/remote_idle.dart';
|
import '../core/remote_idle.dart';
|
||||||
import 'settings/records.dart';
|
import 'settings/records.dart';
|
||||||
import 'settings/settings_group.dart';
|
import 'settings/settings_group.dart';
|
||||||
|
import 'settings/explorer_tool_settings.dart';
|
||||||
import 'settings/vault_settings.dart';
|
import 'settings/vault_settings.dart';
|
||||||
import 'settings/run_settings.dart';
|
import 'settings/run_settings.dart';
|
||||||
import 'settings/browser_settings.dart';
|
import 'settings/browser_settings.dart';
|
||||||
|
|
@ -29,6 +30,7 @@ import 'settings/explorer_settings.dart';
|
||||||
export 'settings/records.dart';
|
export 'settings/records.dart';
|
||||||
export 'settings/settings_group.dart';
|
export 'settings/settings_group.dart';
|
||||||
export 'settings/settings_store.dart';
|
export 'settings/settings_store.dart';
|
||||||
|
export 'settings/explorer_tool_settings.dart';
|
||||||
export 'settings/vault_settings.dart';
|
export 'settings/vault_settings.dart';
|
||||||
export 'settings/run_settings.dart';
|
export 'settings/run_settings.dart';
|
||||||
export 'settings/browser_settings.dart';
|
export 'settings/browser_settings.dart';
|
||||||
|
|
@ -159,11 +161,6 @@ class AppSettings {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// X-plore 비교 5-2 시스템 폴더 보기 (Shizuku, 읽기 전용, 사용자 결정 10/21 · 관리자 결정: 처음 끔 · 켤 때마다 경고)
|
|
||||||
bool shizukuEnabled = false;
|
|
||||||
|
|
||||||
/// X-plore 비교 5-2 루트 폴더 보기 (su, 읽기 전용, 관리자 결정 10/21: Shizuku 와 같은 틀 - 처음 끔 · 켤 때 · 처음 열 때 경고)
|
|
||||||
bool rootEnabled = false;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -171,17 +168,10 @@ class AppSettings {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// 89: Wi-Fi 공유 - 저절로 끄는 시간 (분, 0 = 끄지 않음). 처음 값 30분 (관리자 지시 10/17)
|
|
||||||
int wifiShareMinutes = 30;
|
|
||||||
|
|
||||||
/// 89 · 보안 검토 3: Wi-Fi 공유를 Tailscale (100.64/10, 내 tailnet 의 기기) 주소에서도 연다 (관리자 결정 10/18: 처음 켬)
|
|
||||||
bool wifiShareTailscale = true;
|
|
||||||
|
|
||||||
/// 89: Wi-Fi 공유로 마지막에 고른 폴더 (다시 켤 때 처음 고른 것)
|
|
||||||
String wifiShareFolder = '';
|
|
||||||
|
|
||||||
/// 86: ZIP 으로 묶기의 압축 정도 (1 빠르게 · 6 보통 (처음 값) · 9 작게) - 마지막에 고른 것을 기억
|
|
||||||
int zipLevel = 6;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -359,8 +349,11 @@ class AppSettings {
|
||||||
/// 암호 보관함
|
/// 암호 보관함
|
||||||
final vault = VaultSettings();
|
final vault = VaultSettings();
|
||||||
|
|
||||||
|
/// 탐색기 도구 - 시스템 폴더 (Shizuku) · 루트 · Wi-Fi 공유 · ZIP 묶기
|
||||||
|
final tools = ExplorerToolSettings();
|
||||||
|
|
||||||
/// 설정 분야들 (설정 A) - 저마다 자기 키를 읽고 쓴다. toJson · fromJson 은 이 목록을 돌며 합치기만 한다
|
/// 설정 분야들 (설정 A) - 저마다 자기 키를 읽고 쓴다. toJson · fromJson 은 이 목록을 돌며 합치기만 한다
|
||||||
List<SettingsGroup> get groups => [explorer, network, tor, copy, aiImage, reader, download, browser, run, vault];
|
List<SettingsGroup> get groups => [explorer, network, tor, copy, aiImage, reader, download, browser, run, vault, tools];
|
||||||
|
|
||||||
/// [plainSecrets]: 안전 저장소를 쓸 수 없을 때만 (예전 파일에 있던 비밀 값을 잃지 않게) 예전처럼 파일에 둔다
|
/// [plainSecrets]: 안전 저장소를 쓸 수 없을 때만 (예전 파일에 있던 비밀 값을 잃지 않게) 예전처럼 파일에 둔다
|
||||||
Map<String, Object?> toJson({bool plainSecrets = false}) {
|
Map<String, Object?> toJson({bool plainSecrets = false}) {
|
||||||
|
|
@ -398,12 +391,6 @@ class AppSettings {
|
||||||
'appIcon': appIcon,
|
'appIcon': appIcon,
|
||||||
'uiLanguagesAdded': uiLanguagesAdded,
|
'uiLanguagesAdded': uiLanguagesAdded,
|
||||||
'openFileWindow': openFileWindow,
|
'openFileWindow': openFileWindow,
|
||||||
'zipLevel': zipLevel,
|
|
||||||
'wifiShareMinutes': wifiShareMinutes,
|
|
||||||
'wifiShareTailscale': wifiShareTailscale,
|
|
||||||
'wifiShareFolder': wifiShareFolder,
|
|
||||||
'shizukuEnabled': shizukuEnabled,
|
|
||||||
'rootEnabled': rootEnabled,
|
|
||||||
'mkvExisting': mkvExisting,
|
'mkvExisting': mkvExisting,
|
||||||
'components': components,
|
'components': components,
|
||||||
'aiImageV1': true,
|
'aiImageV1': true,
|
||||||
|
|
@ -492,12 +479,6 @@ class AppSettings {
|
||||||
? j['screenOrientation'] as String
|
? j['screenOrientation'] as String
|
||||||
: 'auto'
|
: 'auto'
|
||||||
..openFileWindow = j['openFileWindow'] == 'new' ? 'new' : 'same'
|
..openFileWindow = j['openFileWindow'] == 'new' ? 'new' : 'same'
|
||||||
..shizukuEnabled = j['shizukuEnabled'] == true
|
|
||||||
..rootEnabled = j['rootEnabled'] == true
|
|
||||||
..zipLevel = const [1, 6, 9].contains(j['zipLevel']) ? j['zipLevel'] as int : 6
|
|
||||||
..wifiShareMinutes = const [0, 10, 30, 60, 120].contains(j['wifiShareMinutes']) ? j['wifiShareMinutes'] as int : 30
|
|
||||||
..wifiShareTailscale = j['wifiShareTailscale'] is bool ? j['wifiShareTailscale'] as bool : true
|
|
||||||
..wifiShareFolder = j['wifiShareFolder'] is String ? j['wifiShareFolder'] as String : ''
|
|
||||||
..mkvExisting = const ['rename', 'overwrite', 'skip'].contains(j['mkvExisting']) ? j['mkvExisting'] as String : 'ask'
|
..mkvExisting = const ['rename', 'overwrite', 'skip'].contains(j['mkvExisting']) ? j['mkvExisting'] as String : 'ask'
|
||||||
..components = j['components'] is List
|
..components = j['components'] is List
|
||||||
? [
|
? [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
import 'settings_group.dart';
|
||||||
|
|
||||||
|
/// 약속 (설정 A): 환경 설정 > 탐색기 도구 - 시스템 폴더 (Shizuku) · 루트 · Wi-Fi 공유 · ZIP 묶기 - 자기 키 (이름 · 처음 값 · 읽기 · 쓰기) 를 스스로 갖는다.
|
||||||
|
/// 설정 하나를 더할 때는 이 파일만 고친다. 저장 파일의 키 이름은 예전 그대로 (평평한 키)
|
||||||
|
class ExplorerToolSettings implements SettingsGroup {
|
||||||
|
/// X-plore 비교 5-2 시스템 폴더 보기 (Shizuku, 읽기 전용, 사용자 결정 10/21 · 관리자 결정: 처음 끔 · 켤 때마다 경고)
|
||||||
|
bool shizukuEnabled = false;
|
||||||
|
|
||||||
|
/// X-plore 비교 5-2 루트 폴더 보기 (su, 읽기 전용, 관리자 결정 10/21: Shizuku 와 같은 틀 - 처음 끔 · 켤 때 · 처음 열 때 경고)
|
||||||
|
bool rootEnabled = false;
|
||||||
|
|
||||||
|
/// 89: Wi-Fi 공유 - 저절로 끄는 시간 (분, 0 = 끄지 않음). 처음 값 30분 (관리자 지시 10/17)
|
||||||
|
int wifiShareMinutes = 30;
|
||||||
|
|
||||||
|
/// 89 · 보안 검토 3: Wi-Fi 공유를 Tailscale (100.64/10, 내 tailnet 의 기기) 주소에서도 연다 (관리자 결정 10/18: 처음 켬)
|
||||||
|
bool wifiShareTailscale = true;
|
||||||
|
|
||||||
|
/// 89: Wi-Fi 공유로 마지막에 고른 폴더 (다시 켤 때 처음 고른 것)
|
||||||
|
String wifiShareFolder = '';
|
||||||
|
|
||||||
|
/// 86: ZIP 으로 묶기의 압축 정도 (1 빠르게 · 6 보통 (처음 값) · 9 작게) - 마지막에 고른 것을 기억
|
||||||
|
int zipLevel = 6;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(Map<String, Object?> j, {required bool plainSecrets}) {
|
||||||
|
j['shizukuEnabled'] = shizukuEnabled;
|
||||||
|
j['rootEnabled'] = rootEnabled;
|
||||||
|
j['wifiShareMinutes'] = wifiShareMinutes;
|
||||||
|
j['wifiShareTailscale'] = wifiShareTailscale;
|
||||||
|
j['wifiShareFolder'] = wifiShareFolder;
|
||||||
|
j['zipLevel'] = zipLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void read(Map<String, dynamic> j) {
|
||||||
|
shizukuEnabled = j['shizukuEnabled'] == true;
|
||||||
|
rootEnabled = j['rootEnabled'] == true;
|
||||||
|
zipLevel = const [1, 6, 9].contains(j['zipLevel']) ? j['zipLevel'] as int : 6;
|
||||||
|
wifiShareMinutes = const [0, 10, 30, 60, 120].contains(j['wifiShareMinutes']) ? j['wifiShareMinutes'] as int : 30;
|
||||||
|
wifiShareTailscale = j['wifiShareTailscale'] is bool ? j['wifiShareTailscale'] as bool : true;
|
||||||
|
wifiShareFolder = j['wifiShareFolder'] is String ? j['wifiShareFolder'] as String : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -314,7 +314,7 @@ Future<String?> createZipFlow(BuildContext context, AppController c, List<String
|
||||||
}
|
}
|
||||||
final name = TextEditingController(
|
final name = TextEditingController(
|
||||||
text: sources.length == 1 ? p.basenameWithoutExtension(sources.first) : p.basename(dir.endsWith(p.separator) ? p.dirname(dir) : dir));
|
text: sources.length == 1 ? p.basenameWithoutExtension(sources.first) : p.basename(dir.endsWith(p.separator) ? p.dirname(dir) : dir));
|
||||||
var level = c.settings.zipLevel;
|
var level = c.settings.tools.zipLevel;
|
||||||
var where = dir;
|
var where = dir;
|
||||||
// zip_aes: 비밀번호 (비우면 보통 ZIP). 기억하지 않고, 기록에 남기지 않는다
|
// zip_aes: 비밀번호 (비우면 보통 ZIP). 기억하지 않고, 기록에 남기지 않는다
|
||||||
final pass = TextEditingController();
|
final pass = TextEditingController();
|
||||||
|
|
@ -412,7 +412,7 @@ Future<String?> createZipFlow(BuildContext context, AppController c, List<String
|
||||||
pass.dispose();
|
pass.dispose();
|
||||||
pass2.dispose();
|
pass2.dispose();
|
||||||
if (go != true || !context.mounted) return null;
|
if (go != true || !context.mounted) return null;
|
||||||
if (level != c.settings.zipLevel) await c.updateSettings((x) => x.zipLevel = level);
|
if (level != c.settings.tools.zipLevel) await c.updateSettings((x) => x.tools.zipLevel = level);
|
||||||
if (!context.mounted) return null;
|
if (!context.mounted) return null;
|
||||||
// zip_aes: 비밀번호 ZIP 은 동봉 7-Zip 으로 (흘려 가며 AES-256 - 큰 동영상도 메모리에 다 올리지 않게)
|
// zip_aes: 비밀번호 ZIP 은 동봉 7-Zip 으로 (흘려 가며 AES-256 - 큰 동영상도 메모리에 다 올리지 않게)
|
||||||
final exe = password.isEmpty ? null : await bundledSevenZip();
|
final exe = password.isEmpty ? null : await bundledSevenZip();
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ class ExplorerController extends ChangeNotifier {
|
||||||
for (final s in c.settings.smbServers) ('$smbScheme${s.id}/', s.label),
|
for (final s in c.settings.smbServers) ('$smbScheme${s.id}/', s.label),
|
||||||
// l: 평문 FTP 는 이름 앞에 ⚠
|
// l: 평문 FTP 는 이름 앞에 ⚠
|
||||||
for (final s in c.settings.ftpServers) ('$ftpScheme${s.id}/', s.tls ? s.label : '⚠ ${s.label}'),
|
for (final s in c.settings.ftpServers) ('$ftpScheme${s.id}/', s.tls ? s.label : '⚠ ${s.label}'),
|
||||||
if (c.settings.shizukuEnabled && shizukuSupported()) ('$shizukuScheme$shizukuServer/', tr('시스템 (읽기 전용)')),
|
if (c.settings.tools.shizukuEnabled && shizukuSupported()) ('$shizukuScheme$shizukuServer/', tr('시스템 (읽기 전용)')),
|
||||||
if (c.settings.rootEnabled && rootSupported()) (rootHome, tr('루트 (읽기 전용)')),
|
if (c.settings.tools.rootEnabled && rootSupported()) (rootHome, tr('루트 (읽기 전용)')),
|
||||||
];
|
];
|
||||||
|
|
||||||
String volumeOf(String path) => vol.volumeOf(path, local);
|
String volumeOf(String path) => vol.volumeOf(path, local);
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class _FilesSettingsSectionState extends State<FilesSettingsSection> {
|
||||||
title: Text(tr('시스템 폴더 보기 (Shizuku · 읽기 전용)')),
|
title: Text(tr('시스템 폴더 보기 (Shizuku · 읽기 전용)')),
|
||||||
subtitle: Text(tr('Shizuku 앱이 있으면 Android/data · obb 처럼 막힌 폴더를 읽기만 합니다. 탐색기 위 탭 [시스템 (읽기 전용)]')),
|
subtitle: Text(tr('Shizuku 앱이 있으면 Android/data · obb 처럼 막힌 폴더를 읽기만 합니다. 탐색기 위 탭 [시스템 (읽기 전용)]')),
|
||||||
trailing: Switch(
|
trailing: Switch(
|
||||||
value: s.shizukuEnabled,
|
value: s.tools.shizukuEnabled,
|
||||||
onChanged: (v) async {
|
onChanged: (v) async {
|
||||||
if (v &&
|
if (v &&
|
||||||
!await confirmReadOnlyView(context,
|
!await confirmReadOnlyView(context,
|
||||||
|
|
@ -104,7 +104,7 @@ class _FilesSettingsSectionState extends State<FilesSettingsSection> {
|
||||||
'대화 · 로그인 정보 같은 개인 데이터가 있을 수 있습니다.'))) {
|
'대화 · 로그인 정보 같은 개인 데이터가 있을 수 있습니다.'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await c.updateSettings((x) => x.shizukuEnabled = v);
|
await c.updateSettings((x) => x.tools.shizukuEnabled = v);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -114,7 +114,7 @@ class _FilesSettingsSectionState extends State<FilesSettingsSection> {
|
||||||
title: Text(tr('루트 폴더 보기 (su · 읽기 전용)')),
|
title: Text(tr('루트 폴더 보기 (su · 읽기 전용)')),
|
||||||
subtitle: Text(tr('루팅한 기기에서 su 로 시스템 · 다른 앱의 폴더를 읽기만 합니다. 탐색기 위 탭 [루트 (읽기 전용)]')),
|
subtitle: Text(tr('루팅한 기기에서 su 로 시스템 · 다른 앱의 폴더를 읽기만 합니다. 탐색기 위 탭 [루트 (읽기 전용)]')),
|
||||||
trailing: Switch(
|
trailing: Switch(
|
||||||
value: s.rootEnabled,
|
value: s.tools.rootEnabled,
|
||||||
onChanged: (v) async {
|
onChanged: (v) async {
|
||||||
if (v &&
|
if (v &&
|
||||||
!await confirmReadOnlyView(context,
|
!await confirmReadOnlyView(context,
|
||||||
|
|
@ -124,7 +124,7 @@ class _FilesSettingsSectionState extends State<FilesSettingsSection> {
|
||||||
'(대화 · 로그인 정보 · 비밀번호 등) 도 보일 수 있습니다.'))) {
|
'(대화 · 로그인 정보 · 비밀번호 등) 도 보일 수 있습니다.'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await c.updateSettings((x) => x.rootEnabled = v);
|
await c.updateSettings((x) => x.tools.rootEnabled = v);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,10 @@ class _WifiSharePageState extends State<WifiSharePage> {
|
||||||
_lastReason = null;
|
_lastReason = null;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
final mins = widget.c.settings.wifiShareMinutes;
|
final mins = widget.c.settings.tools.wifiShareMinutes;
|
||||||
final s = await WifiShare.start(widget.folder,
|
final s = await WifiShare.start(widget.folder,
|
||||||
autoOff: mins > 0 ? Duration(minutes: mins) : null, tailscale: widget.c.settings.wifiShareTailscale);
|
autoOff: mins > 0 ? Duration(minutes: mins) : null, tailscale: widget.c.settings.tools.wifiShareTailscale);
|
||||||
await widget.c.updateSettings((x) => x.wifiShareFolder = widget.folder);
|
await widget.c.updateSettings((x) => x.tools.wifiShareFolder = widget.folder);
|
||||||
_s?.removeListener(_changed);
|
_s?.removeListener(_changed);
|
||||||
_s = s..addListener(_changed);
|
_s = s..addListener(_changed);
|
||||||
// 작업 기록에는 켜고 끈 것만 (코드 · 주소 · 접속한 곳은 남기지 않는다)
|
// 작업 기록에는 켜고 끈 것만 (코드 · 주소 · 접속한 곳은 남기지 않는다)
|
||||||
|
|
@ -109,7 +109,7 @@ class _WifiSharePageState extends State<WifiSharePage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _offView() {
|
List<Widget> _offView() {
|
||||||
final mins = widget.c.settings.wifiShareMinutes;
|
final mins = widget.c.settings.tools.wifiShareMinutes;
|
||||||
return [
|
return [
|
||||||
Text(tr('공유할 폴더'), style: TextStyle(color: JjColors.textDim, fontSize: 12)),
|
Text(tr('공유할 폴더'), style: TextStyle(color: JjColors.textDim, fontSize: 12)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
|
|
@ -125,7 +125,7 @@ class _WifiSharePageState extends State<WifiSharePage> {
|
||||||
],
|
],
|
||||||
onChanged: (v) async {
|
onChanged: (v) async {
|
||||||
if (v == null) return;
|
if (v == null) return;
|
||||||
await widget.c.updateSettings((x) => x.wifiShareMinutes = v);
|
await widget.c.updateSettings((x) => x.tools.wifiShareMinutes = v);
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -135,9 +135,9 @@ class _WifiSharePageState extends State<WifiSharePage> {
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text(tr('Tailscale 에서도 열기')),
|
title: Text(tr('Tailscale 에서도 열기')),
|
||||||
subtitle: Text(tr('내 Tailscale 망 (tailnet) 의 기기도 이 주소로 볼 수 있습니다. 끄면 같은 Wi-Fi · 유선 망에서만')),
|
subtitle: Text(tr('내 Tailscale 망 (tailnet) 의 기기도 이 주소로 볼 수 있습니다. 끄면 같은 Wi-Fi · 유선 망에서만')),
|
||||||
value: widget.c.settings.wifiShareTailscale,
|
value: widget.c.settings.tools.wifiShareTailscale,
|
||||||
onChanged: (v) async {
|
onChanged: (v) async {
|
||||||
await widget.c.updateSettings((x) => x.wifiShareTailscale = v);
|
await widget.c.updateSettings((x) => x.tools.wifiShareTailscale = v);
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ void main() {
|
||||||
await tester.tap(find.widgetWithText(FilledButton, '묶기'));
|
await tester.tap(find.widgetWithText(FilledButton, '묶기'));
|
||||||
await wait(tester, () => finished);
|
await wait(tester, () => finished);
|
||||||
expect(made, p.join(tmp.path, 'photos.zip'));
|
expect(made, p.join(tmp.path, 'photos.zip'));
|
||||||
expect(c.settings.zipLevel, 9, reason: '고른 압축 정도를 기억');
|
expect(c.settings.tools.zipLevel, 9, reason: '고른 압축 정도를 기억');
|
||||||
expect(File(made!).lengthSync() > 0, isTrue);
|
expect(File(made!).lengthSync() > 0, isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,9 @@ void main() {
|
||||||
// 설정 "Tailscale 에서도 열기" 를 끄면 Tailscale 주소는 열지 않는다 (처음 값은 켬)
|
// 설정 "Tailscale 에서도 열기" 를 끄면 Tailscale 주소는 열지 않는다 (처음 값은 켬)
|
||||||
expect(WifiShare.shareInterface('Tailscale', '100.69.29.106', tailscale: false), isFalse);
|
expect(WifiShare.shareInterface('Tailscale', '100.69.29.106', tailscale: false), isFalse);
|
||||||
expect(WifiShare.shareInterface('Wi-Fi', '192.168.0.5', tailscale: false), isTrue);
|
expect(WifiShare.shareInterface('Wi-Fi', '192.168.0.5', tailscale: false), isTrue);
|
||||||
expect(AppSettings().wifiShareTailscale, isTrue);
|
expect(AppSettings().tools.wifiShareTailscale, isTrue);
|
||||||
expect(AppSettings.fromJson(const {'wifiShareTailscale': false}).wifiShareTailscale, isFalse);
|
expect(AppSettings.fromJson(const {'wifiShareTailscale': false}).tools.wifiShareTailscale, isFalse);
|
||||||
expect(AppSettings.fromJson(const {'wifiShareTailscale': 'x'}).wifiShareTailscale, isTrue, reason: '틀린 값은 처음 값');
|
expect(AppSettings.fromJson(const {'wifiShareTailscale': 'x'}).tools.wifiShareTailscale, isTrue, reason: '틀린 값은 처음 값');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('11: mDNS 로 찾은 주소는 사설망만', () {
|
test('11: mDNS 로 찾은 주소는 사설망만', () {
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ void main() {
|
||||||
AppController ctl({bool on = true}) {
|
AppController ctl({bool on = true}) {
|
||||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||||
c.settings
|
c.settings
|
||||||
..rootEnabled = on
|
..tools.rootEnabled = on
|
||||||
..explorer.paths = [tmp.path, tmp.path]
|
..explorer.paths = [tmp.path, tmp.path]
|
||||||
..explorer.layout = 'single';
|
..explorer.layout = 'single';
|
||||||
return c;
|
return c;
|
||||||
|
|
@ -221,9 +221,9 @@ void main() {
|
||||||
await t.pump();
|
await t.pump();
|
||||||
await t.tap(find.widgetWithText(FilledButton, '켜기'));
|
await t.tap(find.widgetWithText(FilledButton, '켜기'));
|
||||||
await settle();
|
await settle();
|
||||||
expect(c.settings.rootEnabled, isTrue);
|
expect(c.settings.tools.rootEnabled, isTrue);
|
||||||
await t.tap(sw.first);
|
await t.tap(sw.first);
|
||||||
await settle();
|
await settle();
|
||||||
expect(c.settings.rootEnabled, isFalse);
|
expect(c.settings.tools.rootEnabled, isFalse);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ void main() {
|
||||||
AppController ctl({bool on = true}) {
|
AppController ctl({bool on = true}) {
|
||||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||||
c.settings
|
c.settings
|
||||||
..shizukuEnabled = on
|
..tools.shizukuEnabled = on
|
||||||
..explorer.paths = [tmp.path, tmp.path]
|
..explorer.paths = [tmp.path, tmp.path]
|
||||||
..explorer.layout = 'single';
|
..explorer.layout = 'single';
|
||||||
return c;
|
return c;
|
||||||
|
|
@ -231,16 +231,16 @@ void main() {
|
||||||
expect(t.widget<FilledButton>(find.widgetWithText(FilledButton, '켜기')).onPressed, isNull, reason: '체크해야 켜짐');
|
expect(t.widget<FilledButton>(find.widgetWithText(FilledButton, '켜기')).onPressed, isNull, reason: '체크해야 켜짐');
|
||||||
await t.tap(find.text('취소'));
|
await t.tap(find.text('취소'));
|
||||||
await settle();
|
await settle();
|
||||||
expect(c.settings.shizukuEnabled, isFalse);
|
expect(c.settings.tools.shizukuEnabled, isFalse);
|
||||||
await t.tap(sw.first);
|
await t.tap(sw.first);
|
||||||
await settle();
|
await settle();
|
||||||
await t.tap(find.text('위 내용을 알고 켭니다'));
|
await t.tap(find.text('위 내용을 알고 켭니다'));
|
||||||
await t.pump();
|
await t.pump();
|
||||||
await t.tap(find.widgetWithText(FilledButton, '켜기'));
|
await t.tap(find.widgetWithText(FilledButton, '켜기'));
|
||||||
await settle();
|
await settle();
|
||||||
expect(c.settings.shizukuEnabled, isTrue);
|
expect(c.settings.tools.shizukuEnabled, isTrue);
|
||||||
await t.tap(sw.first);
|
await t.tap(sw.first);
|
||||||
await settle();
|
await settle();
|
||||||
expect(c.settings.shizukuEnabled, isFalse, reason: '끄기는 묻지 않음');
|
expect(c.settings.tools.shizukuEnabled, isFalse, reason: '끄기는 묻지 않음');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ void main() {
|
||||||
|
|
||||||
testWidgets('꺼짐 → [켜기] → 코드 · 남은 시간 → [끄기] → 꺼짐', (tester) async {
|
testWidgets('꺼짐 → [켜기] → 코드 · 남은 시간 → [끄기] → 꺼짐', (tester) async {
|
||||||
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
|
||||||
expect(c.settings.wifiShareMinutes, 30, reason: '처음 값 30분 (관리자 지시)');
|
expect(c.settings.tools.wifiShareMinutes, 30, reason: '처음 값 30분 (관리자 지시)');
|
||||||
// 폰 세로처럼 좁고 긴 화면 (아래 줄까지 다 그려지게)
|
// 폰 세로처럼 좁고 긴 화면 (아래 줄까지 다 그려지게)
|
||||||
tester.view.physicalSize = const Size(412, 1600);
|
tester.view.physicalSize = const Size(412, 1600);
|
||||||
tester.view.devicePixelRatio = 1;
|
tester.view.devicePixelRatio = 1;
|
||||||
|
|
@ -49,7 +49,7 @@ void main() {
|
||||||
expect(find.text(s.code), findsOneWidget);
|
expect(find.text(s.code), findsOneWidget);
|
||||||
expect(find.textContaining('분 뒤에 저절로 꺼집니다'), findsOneWidget);
|
expect(find.textContaining('분 뒤에 저절로 꺼집니다'), findsOneWidget);
|
||||||
expect(find.text('아직 접속한 기기가 없습니다'), findsOneWidget);
|
expect(find.text('아직 접속한 기기가 없습니다'), findsOneWidget);
|
||||||
expect(c.settings.wifiShareFolder, tmp.path);
|
expect(c.settings.tools.wifiShareFolder, tmp.path);
|
||||||
|
|
||||||
await tester.tap(find.text('끄기'));
|
await tester.tap(find.text('끄기'));
|
||||||
await tester.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 100)));
|
await tester.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 100)));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue