From aa7a1af27ca703dc59bff34b67d24c2178c5c5d5 Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:38:57 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=A5=B4=EB=8A=94=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20(=EB=8B=A4=EB=A5=B8=20=ED=8C=90?= =?UTF-8?q?=EC=9D=98=20Tor=20=EB=93=B1)=20=EB=8A=94=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=C2=B7=20=ED=99=94=EB=A9=B4=20=EC=88=9C=EC=84=9C=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A7=80=EC=9A=B0=EC=A7=80=20=EC=95=8A=EC=9D=8C=20?= =?UTF-8?q?(225)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 데이터 (설정): 다른 판으로 오가면 Tor 컴포넌트 켜짐이 사라졌다 - 모르는 id 를 남기고 (40), 순서를 바꿀 때도 그 자리에 (AppComponent.reorder) Co-Authored-By: Claude Opus 5.5 --- lib/app/components.dart | 17 +++++++++++++++++ lib/app/settings.dart | 6 ++++-- lib/ui/component_settings.dart | 4 +++- test/components_test.dart | 18 ++++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/app/components.dart b/lib/app/components.dart index 7d3c683..2299eeb 100644 --- a/lib/app/components.dart +++ b/lib/app/components.dart @@ -48,6 +48,23 @@ class AppComponent { /// 처음 설치 때 켜진 것 static List get defaultInstalled => [for (final c in all) if (c.builtIn) c.id]; + /// 225: 화면 순서를 [known] (이 판이 아는 화면, 새 순서) 로 바꾸되, [old] 안의 모르는 화면 (다른 판의 Tor 등) 은 그 자리에 남긴다 + static List reorder(List old, List known) { + final next = known.iterator; + final out = []; + for (final x in old) { + if (byId(x) == null) { + out.add(x); + } else if (next.moveNext()) { + out.add(next.current); + } + } + while (next.moveNext()) { + out.add(next.current); + } + return out; + } + /// 설치된 화면들을 [order] 순서로 (순서에 없는 것은 기본 순서대로 뒤에) static List pages(List installed, List order) { final ids = [ diff --git a/lib/app/settings.dart b/lib/app/settings.dart index cddf534..079b064 100644 --- a/lib/app/settings.dart +++ b/lib/app/settings.dart @@ -879,13 +879,15 @@ class AppSettings { ..rsyncPaths = [for (final x in (j['rsyncPaths'] as List?) ?? const []) '$x'] ..components = j['components'] is List ? [ - for (final x in j['components'] as List) if (AppComponent.byId('$x') != null) '$x', + // 225: 이 판이 모르는 것 (다른 판 · 새 판의 컴포넌트 - Tor 등) 도 지우지 않고 남긴다 (40: 모르는 설정은 남김). + // 화면 · 기능은 아는 것만 쓴다 (AppComponent.pages · contains) + for (final x in j['components'] as List) '$x', // 123: 새 화면 "AI 그림" 은 예전 설정에도 한 번 켜서 넣는다 (끄기: 환경 설정 > 컴포넌트) if (j['aiImageV1'] != true && !(j['components'] as List).contains('aiimage')) 'aiimage', ] : AppComponent.defaultInstalled ..navOrder = j['navOrder'] is List - ? [for (final x in j['navOrder'] as List) if (AppComponent.defaultOrder.contains('$x')) '$x'] + ? [for (final x in j['navOrder'] as List) '$x'] // 225: 모르는 화면도 자리째 남긴다 : AppComponent.defaultOrder ..swipeNav = j['swipeNav'] as bool? ?? true ..imageExts = j['imageExts'] is List diff --git a/lib/ui/component_settings.dart b/lib/ui/component_settings.dart index e2f2e3e..b191b77 100644 --- a/lib/ui/component_settings.dart +++ b/lib/ui/component_settings.dart @@ -176,7 +176,9 @@ class ComponentSettings extends StatelessWidget { void move(int from, int to) { final ids = [for (final p in pages) p.id]; ids.insert(to, ids.removeAt(from)); - c.updateSettings((v) => v.navOrder = [...ids, ...AppComponent.defaultOrder.where((x) => !ids.contains(x))]); + // 225: 이 판이 모르는 화면 (다른 판의 Tor 등) 은 지우지 않고 그 자리에 + c.updateSettings((v) => + v.navOrder = AppComponent.reorder(v.navOrder, [...ids, ...AppComponent.defaultOrder.where((x) => !ids.contains(x))])); } return Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ diff --git a/test/components_test.dart b/test/components_test.dart index eba6650..a461b17 100644 --- a/test/components_test.dart +++ b/test/components_test.dart @@ -34,6 +34,24 @@ void main() { expect(AppSettings.fromJson({}).components, AppComponent.defaultInstalled); }); + test('225: 이 판이 모르는 컴포넌트 (다른 판의 Tor 등) 는 설정에서 지우지 않는다 · 순서를 바꿔도 그 자리에', () { + final s = AppSettings.fromJson({ + 'components': ['mkv', 'tor', 'explorer'], + 'navOrder': ['mkv', 'tor', 'explorer', 'browser'], + 'aiImageV1': true, + }); + expect(s.components, ['mkv', 'tor', 'explorer'], reason: '모르는 tor 도 남김'); + expect(s.navOrder, ['mkv', 'tor', 'explorer', 'browser']); + // 화면은 아는 것만 + expect([for (final p in AppComponent.pages(s.components, s.navOrder)) p.id], ['mkv', 'explorer']); + final back = AppSettings.fromJson(s.toJson()); + expect([back.components, back.navOrder], [s.components, s.navOrder], reason: '저장해도 남음'); + // 순서 바꾸기 (explorer 를 맨 앞으로): tor 는 둘째 자리 그대로 + expect(AppComponent.reorder(s.navOrder, ['explorer', 'mkv', 'browser']), ['explorer', 'tor', 'mkv', 'browser']); + // 예전 순서에 없던 아는 화면은 뒤에 + expect(AppComponent.reorder(['tor', 'mkv'], ['mkv', 'explorer']), ['tor', 'mkv', 'explorer']); + }); + testWidgets('위쪽 이동 버튼: 설치한 화면만 · 설정을 바꾸면 바로 · 하나뿐이면 그것만', (tester) async { tester.view.physicalSize = const Size(1500, 900); tester.view.devicePixelRatio = 1;