모르는 컴포넌트 (다른 판의 Tor 등) 는 설정 · 화면 순서에서 지우지 않음 (225)

- 데이터 (설정): 다른 판으로 오가면 Tor 컴포넌트 켜짐이 사라졌다 - 모르는 id 를 남기고 (40), 순서를 바꿀 때도 그 자리에 (AppComponent.reorder)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix_mkv
RyuJongJin 2026-10-12 00:38:57 +09:00
parent 3a9f09a6eb
commit aa7a1af27c
4 changed files with 42 additions and 3 deletions

View File

@ -48,6 +48,23 @@ class AppComponent {
/// 처음 설치 때 켜진 것
static List<String> get defaultInstalled => [for (final c in all) if (c.builtIn) c.id];
/// 225: 화면 순서를 [known] (이 판이 아는 화면, 새 순서) 로 바꾸되, [old] 안의 모르는 화면 (다른 판의 Tor 등) 은 그 자리에 남긴다
static List<String> reorder(List<String> old, List<String> known) {
final next = known.iterator;
final out = <String>[];
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<AppComponent> pages(List<String> installed, List<String> order) {
final ids = [

View File

@ -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

View File

@ -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: [

View File

@ -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;