1
0
forked from baron/baron-sso

locale_store 리팩토링

This commit is contained in:
Lectom C Han
2026-02-20 08:16:56 +09:00
parent 2811ecf268
commit 4c9f71147c
12 changed files with 592 additions and 229 deletions

View File

@@ -1,11 +1,59 @@
import 'package:flutter/foundation.dart';
import 'locale_storage_backend.dart';
import 'locale_storage_stub.dart'
if (dart.library.js_interop) 'locale_storage_web.dart';
abstract class LocaleStorage {
static bool _forceMemory = false;
static bool _forceSession = false;
static void _syncTestMode() {
if (_forceMemory) {
localeStorage.setTestMode(LocaleStorageTestMode.memoryOnly);
return;
}
if (_forceSession) {
localeStorage.setTestMode(LocaleStorageTestMode.sessionOnly);
return;
}
localeStorage.setTestMode(LocaleStorageTestMode.normal);
}
static String? read() => localeStorage.read();
static void write(String locale) => localeStorage.write(locale);
static void forceMemoryStorageForTests(bool value) =>
localeStorage.forceMemoryStorageForTests(value);
static void forceSessionStorageForTests(bool value) =>
localeStorage.forceSessionStorageForTests(value);
@visibleForTesting
static void setTestModeForTests(LocaleStorageTestMode mode) {
_forceMemory = mode == LocaleStorageTestMode.memoryOnly;
_forceSession = mode == LocaleStorageTestMode.sessionOnly;
_syncTestMode();
}
@visibleForTesting
static void clearForTests() {
localeStorage.clearForTests();
_forceMemory = false;
_forceSession = false;
}
@visibleForTesting
static void seedLegacyForTests(String locale) {
localeStorage.seedLegacyForTests(locale);
}
@visibleForTesting
static LocaleStorageDebugState debugStateForTests() {
return localeStorage.debugStateForTests();
}
static void forceMemoryStorageForTests(bool value) {
_forceMemory = value;
_syncTestMode();
}
static void forceSessionStorageForTests(bool value) {
_forceSession = value;
_syncTestMode();
}
}

View File

@@ -0,0 +1,38 @@
import 'package:flutter/foundation.dart';
enum LocaleStorageTestMode { normal, sessionOnly, memoryOnly }
@immutable
class LocaleStorageDebugState {
const LocaleStorageDebugState({
required this.mode,
this.localCurrent,
this.localLegacy,
this.sessionCurrent,
this.sessionLegacy,
this.memoryCurrent,
this.memoryLegacy,
});
final LocaleStorageTestMode mode;
final String? localCurrent;
final String? localLegacy;
final String? sessionCurrent;
final String? sessionLegacy;
final String? memoryCurrent;
final String? memoryLegacy;
}
abstract interface class LocaleStorageBackend {
String? read();
void write(String locale);
void setTestMode(LocaleStorageTestMode mode);
void clearForTests();
void seedLegacyForTests(String locale);
LocaleStorageDebugState debugStateForTests();
}

View File

@@ -0,0 +1,13 @@
class LocaleStoragePolicy {
static const currentKey = 'locale';
static const legacyKey = 'baron_locale';
static bool hasValue(String? value) => value != null && value.isNotEmpty;
static bool shouldMigrateLegacy({
required String? current,
required String? legacy,
}) {
return !hasValue(current) && hasValue(legacy);
}
}

View File

@@ -1,19 +1,59 @@
class LocaleStorageImpl {
String? _locale;
import 'locale_storage_backend.dart';
import 'locale_storage_policy.dart';
String? read() => _locale;
class LocaleStorageImpl implements LocaleStorageBackend {
final Map<String, String> _memory = {};
LocaleStorageTestMode _mode = LocaleStorageTestMode.normal;
@override
String? read() {
final current = _memory[LocaleStoragePolicy.currentKey];
if (LocaleStoragePolicy.hasValue(current)) {
return current;
}
final legacy = _memory[LocaleStoragePolicy.legacyKey];
if (LocaleStoragePolicy.shouldMigrateLegacy(
current: current,
legacy: legacy,
)) {
_memory[LocaleStoragePolicy.currentKey] = legacy!;
_memory.remove(LocaleStoragePolicy.legacyKey);
return legacy;
}
return null;
}
@override
void write(String locale) {
_locale = locale;
_memory[LocaleStoragePolicy.currentKey] = locale;
}
void forceMemoryStorageForTests(bool value) {
// Stub
@override
void setTestMode(LocaleStorageTestMode mode) {
_mode = mode;
}
void forceSessionStorageForTests(bool value) {
// Stub
@override
void clearForTests() {
_memory.clear();
_mode = LocaleStorageTestMode.normal;
}
@override
void seedLegacyForTests(String locale) {
_memory[LocaleStoragePolicy.legacyKey] = locale;
}
@override
LocaleStorageDebugState debugStateForTests() {
return LocaleStorageDebugState(
mode: _mode,
memoryCurrent: _memory[LocaleStoragePolicy.currentKey],
memoryLegacy: _memory[LocaleStoragePolicy.legacyKey],
);
}
}
final localeStorage = LocaleStorageImpl();
final LocaleStorageBackend localeStorage = LocaleStorageImpl();

View File

@@ -1,120 +1,200 @@
// ignore_for_file: avoid_web_libraries_in_flutter
import 'package:web/web.dart' as web;
import 'package:flutter/foundation.dart';
class LocaleStorageImpl {
static const _key = 'locale';
static const _legacyKey = 'baron_locale';
import 'locale_storage_backend.dart';
import 'locale_storage_policy.dart';
enum _StorageTarget { local, session, memory }
class LocaleStorageImpl implements LocaleStorageBackend {
static final Map<String, String> _memory = {};
static bool _forceMemory = false;
static bool _forceSession = false;
static LocaleStorageTestMode _mode = LocaleStorageTestMode.normal;
@visibleForTesting
void forceMemoryStorageForTests(bool value) {
_forceMemory = value;
if (!value) {
_memory.clear();
List<_StorageTarget> _fallbackTargets() {
switch (_mode) {
case LocaleStorageTestMode.normal:
return [
_StorageTarget.local,
_StorageTarget.session,
_StorageTarget.memory,
];
case LocaleStorageTestMode.sessionOnly:
return [_StorageTarget.session, _StorageTarget.memory];
case LocaleStorageTestMode.memoryOnly:
return [_StorageTarget.memory];
}
}
@visibleForTesting
void forceSessionStorageForTests(bool value) {
_forceSession = value;
String? _safeReadLocal(String key) {
try {
return web.window.localStorage.getItem(key);
} catch (_) {
return null;
}
}
String? _read(String key) {
if (!_forceMemory && !_forceSession) {
try {
return web.window.localStorage.getItem(key);
} catch (_) {
// localStorage 접근이 차단된 경우 sessionStorage로 fallback.
try {
return web.window.sessionStorage.getItem(key);
} catch (_) {
// sessionStorage도 차단된 경우 메모리 fallback 사용.
}
}
String? _safeReadSession(String key) {
try {
return web.window.sessionStorage.getItem(key);
} catch (_) {
return null;
}
if (!_forceMemory) {
try {
return web.window.sessionStorage.getItem(key);
} catch (_) {
// sessionStorage도 차단된 경우 메모리 fallback 사용.
}
}
return _memory[key];
}
void _write(String key, String value) {
if (!_forceMemory && !_forceSession) {
try {
web.window.localStorage.setItem(key, value);
return;
} catch (_) {
// localStorage 접근이 차단된 경우 sessionStorage로 fallback.
try {
web.window.sessionStorage.setItem(key, value);
return;
} catch (_) {
// sessionStorage도 차단된 경우 메모리 fallback 사용.
}
}
bool _safeWriteLocal(String key, String value) {
try {
web.window.localStorage.setItem(key, value);
return true;
} catch (_) {
return false;
}
if (!_forceMemory) {
try {
web.window.sessionStorage.setItem(key, value);
return;
} catch (_) {
// sessionStorage도 차단된 경우 메모리 fallback 사용.
}
}
_memory[key] = value;
}
void _remove(String key) {
if (!_forceMemory && !_forceSession) {
try {
web.window.localStorage.removeItem(key);
return;
} catch (_) {
// localStorage 접근이 차단된 경우 sessionStorage로 fallback.
try {
web.window.sessionStorage.removeItem(key);
return;
} catch (_) {
// sessionStorage도 차단된 경우 메모리 fallback 사용.
}
bool _safeWriteSession(String key, String value) {
try {
web.window.sessionStorage.setItem(key, value);
return true;
} catch (_) {
return false;
}
}
bool _safeRemoveLocal(String key) {
try {
web.window.localStorage.removeItem(key);
return true;
} catch (_) {
return false;
}
}
bool _safeRemoveSession(String key) {
try {
web.window.sessionStorage.removeItem(key);
return true;
} catch (_) {
return false;
}
}
void _safeClearLocal() {
try {
web.window.localStorage.clear();
} catch (_) {
// 스토리지 접근이 차단된 경우는 테스트 정리에서 무시합니다.
}
}
void _safeClearSession() {
try {
web.window.sessionStorage.clear();
} catch (_) {
// 스토리지 접근이 차단된 경우는 테스트 정리에서 무시합니다.
}
}
String? _readFromTarget(_StorageTarget target, String key) {
switch (target) {
case _StorageTarget.local:
return _safeReadLocal(key);
case _StorageTarget.session:
return _safeReadSession(key);
case _StorageTarget.memory:
return _memory[key];
}
}
bool _writeToTarget(_StorageTarget target, String key, String value) {
switch (target) {
case _StorageTarget.local:
return _safeWriteLocal(key, value);
case _StorageTarget.session:
return _safeWriteSession(key, value);
case _StorageTarget.memory:
_memory[key] = value;
return true;
}
}
String? _readByKey(String key) {
for (final target in _fallbackTargets()) {
final value = _readFromTarget(target, key);
if (value != null) {
return value;
}
}
if (!_forceMemory) {
try {
web.window.sessionStorage.removeItem(key);
return null;
}
void _writeByKey(String key, String value) {
for (final target in _fallbackTargets()) {
if (_writeToTarget(target, key, value)) {
return;
} catch (_) {
// sessionStorage도 차단된 경우 메모리 fallback 사용.
}
}
}
void _removeEverywhere(String key) {
_safeRemoveLocal(key);
_safeRemoveSession(key);
_memory.remove(key);
}
@override
String? read() {
final current = _read(_key);
if (current != null && current.isNotEmpty) {
final current = _readByKey(LocaleStoragePolicy.currentKey);
if (LocaleStoragePolicy.hasValue(current)) {
return current;
}
final legacy = _read(_legacyKey);
if (legacy != null && legacy.isNotEmpty) {
_write(_key, legacy);
_remove(_legacyKey);
final legacy = _readByKey(LocaleStoragePolicy.legacyKey);
if (LocaleStoragePolicy.shouldMigrateLegacy(
current: current,
legacy: legacy,
)) {
_writeByKey(LocaleStoragePolicy.currentKey, legacy!);
_removeEverywhere(LocaleStoragePolicy.legacyKey);
return legacy;
}
return null;
}
@override
void write(String locale) {
_write(_key, locale);
_writeByKey(LocaleStoragePolicy.currentKey, locale);
}
@override
void setTestMode(LocaleStorageTestMode mode) {
_mode = mode;
}
@override
void clearForTests() {
_safeClearLocal();
_safeClearSession();
_memory.clear();
_mode = LocaleStorageTestMode.normal;
}
@override
void seedLegacyForTests(String locale) {
_writeByKey(LocaleStoragePolicy.legacyKey, locale);
}
@override
LocaleStorageDebugState debugStateForTests() {
return LocaleStorageDebugState(
mode: _mode,
localCurrent: _safeReadLocal(LocaleStoragePolicy.currentKey),
localLegacy: _safeReadLocal(LocaleStoragePolicy.legacyKey),
sessionCurrent: _safeReadSession(LocaleStoragePolicy.currentKey),
sessionLegacy: _safeReadSession(LocaleStoragePolicy.legacyKey),
memoryCurrent: _memory[LocaleStoragePolicy.currentKey],
memoryLegacy: _memory[LocaleStoragePolicy.legacyKey],
);
}
}
final localeStorage = LocaleStorageImpl();
final LocaleStorageBackend localeStorage = LocaleStorageImpl();