커스텀창 - "체험하기"를 누르면 화면 전체 테마가 즉시 바뀌도록 수정

기존엔 미리보기가 큰 타일 하나만 바꾸고, 배경/카드 등 화면 전체는 실제
장착된 테마를 따로 불러와 보여줬다. 이제는 _resolvePreviewTemplate()
하나로 "지금 보여줄 테마"를 통일해서, 체험하기로 고른 템플릿이 배경색/
보유 캐시 바/카드 전부에 즉시 반영된다. "기본 모습"을 고르면 화면 전체가
원래 모습으로 돌아간다.

ShopTemplate에 code 필드를 추가해서 profileThemes 맵을 바로 찾아 쓸 수
있게 했다.
This commit is contained in:
2026-10-01 06:29:40 +00:00
parent 4e74667993
commit 726d2dc632
2 changed files with 18 additions and 20 deletions
@@ -9,6 +9,7 @@ import '../theme/profile_themes.dart';
class ShopTemplate { class ShopTemplate {
final int id; final int id;
final String code;
final String category; final String category;
final String name; final String name;
final int price; final int price;
@@ -19,6 +20,7 @@ class ShopTemplate {
ShopTemplate({ ShopTemplate({
required this.id, required this.id,
required this.code,
required this.category, required this.category,
required this.name, required this.name,
required this.price, required this.price,
@@ -31,6 +33,7 @@ class ShopTemplate {
factory ShopTemplate.fromJson(Map<String, dynamic> json) { factory ShopTemplate.fromJson(Map<String, dynamic> json) {
return ShopTemplate( return ShopTemplate(
id: json['id'] as int, id: json['id'] as int,
code: json['code'] as String,
category: json['category'] as String, category: json['category'] as String,
name: json['name'] as String, name: json['name'] as String,
price: json['price'] as int, price: json['price'] as int,
+15 -20
View File
@@ -32,15 +32,10 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
// null = 아직 직접 고르지 않음(장착된 테마를 그대로 보여줌), -1 = "기본 모습"을 명시적으로 미리보는 중. // null = 아직 직접 고르지 않음(장착된 테마를 그대로 보여줌), -1 = "기본 모습"을 명시적으로 미리보는 중.
int? _previewTemplateId; int? _previewTemplateId;
// 🎨 지금 실제로 장착 중인 테마 - 화면 배경/상점 타일 자체를 이걸로 물들인다.
// (미리보기는 큰 타일 하나만 바뀌는 것과 별개로, 이건 "진짜 내 테마"를 화면 전체에 반영)
ProfileTheme? _equippedTheme;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_controller.loadCatalog(widget.studentId); _controller.loadCatalog(widget.studentId);
_loadEquippedTheme();
} }
@override @override
@@ -49,16 +44,8 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
super.dispose(); super.dispose();
} }
Future<void> _loadEquippedTheme() async { /// 지금 큰 타일에 보여줄 템플릿을 고른다. 직접 미리보기를 누른 게 있으면 그걸,
final theme = await ProfileShopController.fetchEquippedTheme( /// 없으면 실제 장착 중인 템플릿을, 그마저도 없으면 null(기본 모습)을 돌려준다.
widget.studentId,
);
if (!mounted) return;
setState(() => _equippedTheme = theme);
}
/// 지금 큰 타일에 보여줄 테마를 고른다. 직접 미리보기를 누른 게 있으면 그걸,
/// 없으면 실제 장착 중인 테마를, 그마저도 없으면 null(기본 모습)을 돌려준다.
ShopTemplate? _resolvePreviewTemplate() { ShopTemplate? _resolvePreviewTemplate() {
if (_previewTemplateId == -1) return null; if (_previewTemplateId == -1) return null;
if (_previewTemplateId != null) { if (_previewTemplateId != null) {
@@ -72,6 +59,15 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
return null; return null;
} }
/// 🎨 지금 "체험하기/미리보기" 중인 테마로 화면 전체(배경/타일/버튼)를 물들인다.
/// 아무것도 직접 고르지 않았으면 실제 장착된 테마가 그대로 나오고, "기본 모습"을
/// 고르면 null이 되어 화면이 원래 모습으로 돌아간다 - 체험하기를 누르면 바로
/// 커스텀 화면 전체에 반영되는 효과를 _resolvePreviewTemplate() 하나로 처리한다.
ProfileTheme? get _displayTheme {
final preview = _resolvePreviewTemplate();
return preview == null ? null : profileThemes[preview.code];
}
Future<void> _handlePurchase(ShopTemplate template) async { Future<void> _handlePurchase(ShopTemplate template) async {
setState(() => _previewTemplateId = template.id); setState(() => _previewTemplateId = template.id);
final (success, message) = await _controller.purchase( final (success, message) = await _controller.purchase(
@@ -92,7 +88,6 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
widget.studentId, widget.studentId,
templateId, templateId,
); );
if (success) await _loadEquippedTheme();
if (!mounted) return; if (!mounted) return;
AppNotice.show( AppNotice.show(
context, context,
@@ -104,7 +99,7 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: _equippedTheme?.background ?? AppPalette.mist, backgroundColor: _displayTheme?.background ?? AppPalette.mist,
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
foregroundColor: AppPalette.ink, foregroundColor: AppPalette.ink,
@@ -148,7 +143,7 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _equippedTheme?.secondary ?? AppPalette.ink, color: _displayTheme?.secondary ?? AppPalette.ink,
borderRadius: BorderRadius.circular(18), borderRadius: BorderRadius.circular(18),
), ),
child: Row( child: Row(
@@ -246,7 +241,7 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
_DefaultTemplateTile( _DefaultTemplateTile(
equipped: !hasEquippedTemplate, equipped: !hasEquippedTemplate,
previewing: previewId == null, previewing: previewId == null,
theme: _equippedTheme, theme: _displayTheme,
onEquip: () => _handleEquip(null), onEquip: () => _handleEquip(null),
onPreview: () => setState(() => _previewTemplateId = -1), onPreview: () => setState(() => _previewTemplateId = -1),
), ),
@@ -255,7 +250,7 @@ class _ProfileCustomizeScreenState extends State<ProfileCustomizeScreen> {
template: template, template: template,
canAfford: _controller.cashBalance >= template.price, canAfford: _controller.cashBalance >= template.price,
previewing: previewId == template.id, previewing: previewId == template.id,
theme: _equippedTheme, theme: _displayTheme,
onPurchase: () => _handlePurchase(template), onPurchase: () => _handlePurchase(template),
onEquip: () => _handleEquip(template.id), onEquip: () => _handleEquip(template.id),
onPreview: () => setState(() => _previewTemplateId = template.id), onPreview: () => setState(() => _previewTemplateId = template.id),