fix: frames

This commit is contained in:
2026-07-08 13:48:29 +03:30
parent df2ae2a215
commit 6b9b9a0f3a
8 changed files with 461 additions and 216 deletions
+34 -19
View File
@@ -1,24 +1,39 @@
import 'package:flutter/material.dart';
import 'app_theme.dart';
/// کشِ رنگِ قاب‌ها که از سرور می‌آید (id → گرادیان). با هر بار خواندنِ کاتالوگِ
/// قاب‌ها پر می‌شود؛ هیچ رنگی سمتِ کلاینت hardcode نیست (تا کش پر نشود، null).
class FrameStyles {
FrameStyles._();
static final FrameStyles I = FrameStyles._();
/// گرادیانِ هر قابِ آواتار (کازمتیک). شناسه‌ها با کاتالوگِ سرور جور است.
/// null یعنی «بدون قابِ اختصاصی» ⇒ از قابِ رتبه استفاده شود.
List<Color>? frameGradient(String id) {
switch (id) {
case 'gold':
return const [Color(0xFFF3D27A), AppColors.goldDark];
case 'fire':
return const [Color(0xFFFF9A3C), Color(0xFFB81D2A)];
case 'emerald':
return const [Color(0xFF7BEAA5), Color(0xFF1B7A4A)];
case 'ocean':
return const [Color(0xFF8FD3F0), Color(0xFF1E5FA8)];
case 'rose':
return const [Color(0xFFF7A8C4), Color(0xFFA83060)];
case 'royal':
return const [Color(0xFFCE9BEA), Color(0xFF6A2FA0)];
default: // none / '' / ناشناخته
return null;
final Map<String, List<Color>> _cache = {};
/// کشِ رنگ‌ها را از کاتالوگِ سرور پر می‌کند. هر آیتم باید id و دو رنگِ hex بدهد.
void setFromCatalog(Iterable<({String id, String c1, String c2})> frames) {
for (final f in frames) {
final g = _parse(f.c1, f.c2);
if (g != null) _cache[f.id] = g;
}
}
List<Color>? gradient(String id) {
if (id.isEmpty || id == 'none') return null;
return _cache[id];
}
static List<Color>? _parse(String c1, String c2) {
final a = _hex(c1), b = _hex(c2);
if (a == null || b == null) return null;
return [a, b];
}
static Color? _hex(String s) {
s = s.trim().replaceAll('#', '');
if (s.length != 6) return null;
final v = int.tryParse(s, radix: 16);
return v == null ? null : Color(0xFF000000 | v);
}
}
/// گرادیانِ قابِ آواتار (از کشِ سرور). null ⇒ قابِ رتبه.
List<Color>? frameGradient(String id) => FrameStyles.I.gradient(id);
+51
View File
@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'app_theme.dart';
/// کشِ رنگ و برچسبِ رتبه‌ها که از سرور می‌آید (tier → گرادیان/برچسب). با هر بار
/// خواندنِ کاتالوگِ قاب‌ها پر می‌شود؛ تا آن لحظه از fallbackِ خنثی استفاده می‌شود.
class RankStyles {
RankStyles._();
static final RankStyles I = RankStyles._();
final Map<String, List<Color>> _grad = {};
final Map<String, String> _label = {};
/// کش را از کاتالوگِ سرور پر می‌کند. هر آیتم id/label/c1/c2 دارد.
void setFromCatalog(
Iterable<({String id, String label, String c1, String c2})> tiers,
) {
for (final t in tiers) {
final g = _parse(t.c1, t.c2);
if (g != null) _grad[t.id] = g;
if (t.label.isNotEmpty) _label[t.id] = t.label;
}
}
/// گرادیانِ رتبه (از سرور، وگرنه fallbackِ خنثیِ طلایی).
List<Color> gradient(String tier) => _grad[tier] ?? _fallbackGrad;
/// برچسبِ فارسیِ رتبه (از سرور، وگرنه خودِ شناسه).
String label(String tier) => _label[tier] ?? tier;
static const _fallbackGrad = [AppColors.gold, AppColors.goldDark];
static List<Color>? _parse(String c1, String c2) {
final a = _hex(c1), b = _hex(c2);
if (a == null || b == null) return null;
return [a, b];
}
static Color? _hex(String s) {
s = s.trim().replaceAll('#', '');
if (s.length != 6) return null;
final v = int.tryParse(s, radix: 16);
return v == null ? null : Color(0xFF000000 | v);
}
}
/// گرادیانِ رنگیِ رتبه (از کشِ سرور).
List<Color> rankGradient(String tier) => RankStyles.I.gradient(tier);
/// برچسبِ فارسیِ رتبه (از کشِ سرور).
String rankLabel(String tier) => RankStyles.I.label(tier);
+4 -13
View File
@@ -1,27 +1,18 @@
import 'package:flutter/material.dart';
import '../theme/app_theme.dart';
import '../theme/ranks.dart';
/// نشانِ رتبه (برنز/نقره/طلا/الماس/پادشاه) با رنگ و برچسبِ فارسی.
/// نشانِ رتبه (برنز/نقره/طلا/الماس/پادشاه) با رنگ و برچسبِ فارسی از سرور.
class RankBadge extends StatelessWidget {
final String tier; // bronze..king
final int? points; // در صورت نمایش امتیاز
final double size;
const RankBadge({super.key, required this.tier, this.points, this.size = 16});
static const _tiers = {
'bronze': ('برنز', [Color(0xFFCD7F32), Color(0xFF8C5A2B)]),
'silver': ('نقره', [Color(0xFFBFC6CC), Color(0xFF8A949B)]),
'gold': ('طلا', [Color(0xFFFFD54F), AppColors.goldDark]),
'diamond': ('الماس', [Color(0xFF5BE0E6), Color(0xFF1E8A99)]),
'king': ('پادشاه', [Color(0xFFB388FF), Color(0xFF6A1B9A)]),
};
@override
Widget build(BuildContext context) {
final t = _tiers[tier] ?? _tiers['bronze']!;
final label = t.$1;
final colors = t.$2;
final label = rankLabel(tier);
final colors = rankGradient(tier);
return Container(
padding: EdgeInsets.symmetric(horizontal: size * 0.6, vertical: size * 0.25),
decoration: BoxDecoration(