diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000..f620326 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.38.5" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 79c113f..b6323af 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0f7b500 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dart.flutterSdkPath": ".fvm/versions/3.38.5" +} \ No newline at end of file diff --git a/lib/app.dart b/lib/app.dart index 2ec6de6..8fa8daf 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -16,6 +16,7 @@ import 'feature/game/presentation/screen/game_screen.dart'; import 'feature/game/presentation/screen/private_entry_screen.dart'; import 'feature/game/presentation/screen/private_table_screen.dart'; import 'feature/game/presentation/screen/tier_list_screen.dart'; +import 'feature/legal/terms_screen.dart'; import 'feature/profile/presentation/bloc/profile_bloc.dart'; import 'feature/profile/presentation/bloc/profile_event.dart'; import 'feature/profile/presentation/screen/profile_screen.dart'; @@ -41,6 +42,7 @@ class HakemApp extends StatelessWidget { GoRoute(path: '/otp', builder: (_, __) => const OtpScreen()), GoRoute(path: '/setup', builder: (_, __) => const ProfileSetupScreen()), GoRoute(path: '/lobby', builder: (_, __) => const LobbyScreen()), + GoRoute(path: '/terms', builder: (_, __) => const TermsScreen()), GoRoute( path: '/profile', builder: (_, __) => BlocProvider( diff --git a/lib/feature/auth/presentation/screen/mobile_screen.dart b/lib/feature/auth/presentation/screen/mobile_screen.dart index c0208dd..b3d0f20 100644 --- a/lib/feature/auth/presentation/screen/mobile_screen.dart +++ b/lib/feature/auth/presentation/screen/mobile_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import '../../../../core/theme/app_theme.dart'; import '../../../../core/widgets/game_ui.dart'; import '../bloc/auth_bloc.dart'; import '../bloc/auth_event.dart'; @@ -97,6 +98,27 @@ class _MobileScreenState extends State { LoginOtpEvent(_controller.text.trim()), ), ), + const SizedBox(height: 8), + TextButton( + onPressed: () => context.push('/terms'), + child: const Text.rich( + TextSpan( + text: 'با ورود، ', + style: TextStyle( + color: Colors.white54, fontSize: 12), + children: [ + TextSpan( + text: 'شرایط و قوانین', + style: TextStyle( + color: AppColors.gold, + fontSize: 12, + fontWeight: FontWeight.bold), + ), + TextSpan(text: ' را می‌پذیرید'), + ], + ), + ), + ), ], ), ), diff --git a/lib/feature/legal/terms_screen.dart b/lib/feature/legal/terms_screen.dart new file mode 100644 index 0000000..575fda1 --- /dev/null +++ b/lib/feature/legal/terms_screen.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart'; + +import '../../core/theme/app_theme.dart'; +import '../../core/widgets/game_ui.dart'; + +/// صفحه‌ی «شرایط و قوانین» استفاده از حکم‌شو (برای انتشار در مایکت/کافه‌بازار). +class TermsScreen extends StatelessWidget { + const TermsScreen({super.key}); + + static const _sections = <(String, String)>[ + ( + '۱. پذیرش شرایط', + 'با نصب، ثبت‌نام یا استفاده از اپلیکیشن «حکم‌شو»، تأیید می‌کنید که این شرایط و ' + 'قوانین را خوانده و پذیرفته‌اید. اگر با بخشی از این قوانین موافق نیستید، ' + 'لطفاً از برنامه استفاده نکنید.' + ), + ( + '۲. حساب کاربری', + 'ورود به برنامه با شماره‌ی موبایل و کد یک‌بارمصرف انجام می‌شود. مسئولیت حفظِ ' + 'دسترسی به شماره و حسابِ کاربری بر عهده‌ی شماست. هر فعالیتی که از طریقِ حسابِ ' + 'شما انجام شود، به نامِ شما ثبت می‌گردد.' + ), + ( + '۳. سکه، بلیت و خریدِ درون‌برنامه‌ای', + 'سکه، بلیت و اشتراکِ VIP اعتبارِ مجازیِ درون‌برنامه‌ای هستند و ارزشِ نقدی ' + 'واقعی ندارند و قابلِ تبدیل به پول یا انتقال به کاربرِ دیگر نیستند. خرید از ' + 'طریقِ درگاهِ رسمیِ فروشگاه (مایکت/کافه‌بازار) انجام می‌شود. اقلامِ مصرف‌شده ' + 'قابلِ بازگشت نیستند مگر طبقِ قوانینِ همان فروشگاه.' + ), + ( + '۴. رفتارِ منصفانه', + 'استفاده از هرگونه ربات، تقلب، سوءاستفاده از باگ، یا دست‌کاریِ بازی ممنوع است. ' + 'در صورتِ تخلف، حسابِ کاربری بدونِ بازگشتِ سکه یا اشتراک مسدود می‌شود.' + ), + ( + '۵. رفتار با دیگران', + 'استفاده از پیام‌ها و شکلک‌های چت برای توهین، تهدید، یا انتشارِ محتوای نامناسب ' + 'مجاز نیست. احترام به دیگر بازیکنان الزامی است.' + ), + ( + '۶. حریمِ خصوصی', + 'برای ارائه‌ی خدمات، شماره‌ی موبایل و اطلاعاتِ بازیِ شما (امتیاز، آمار، تراکنشِ ' + 'سکه) نگه‌داری می‌شود. این اطلاعات برای سنجشِ عملکرد و پشتیبانی استفاده می‌شود ' + 'و بدونِ اجازه در اختیارِ اشخاصِ ثالثِ غیرمرتبط قرار نمی‌گیرد.' + ), + ( + '۷. تغییرات', + 'ممکن است این شرایط، امکانات، قیمت‌ها یا قوانینِ بازی در آینده به‌روزرسانی شوند. ' + 'ادامه‌ی استفاده از برنامه پس از تغییر، به‌منزله‌ی پذیرشِ نسخه‌ی جدید است.' + ), + ( + '۸. مسئولیت', + 'برنامه «همان‌طور که هست» ارائه می‌شود. در صورتِ اختلالِ فنی تلاش می‌کنیم مشکل را ' + 'برطرف کنیم، اما مسئولیتی در قبالِ ازدست‌رفتنِ سکه یا اشتراک ناشی از خطای شبکه، ' + 'دستگاه یا استفاده‌ی نادرست بر عهده‌ی توسعه‌دهنده نیست.' + ), + ( + '۹. ارتباط با ما', + 'برای پرسش یا گزارشِ مشکل می‌توانید از طریقِ صفحه‌ی برنامه در فروشگاه (مایکت/' + 'کافه‌بازار) با پشتیبانی در تماس باشید.' + ), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: GameBackground( + child: SafeArea( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(12), + child: Row(children: const [ + AppBackButton(), + Spacer(), + GlowText('شرایط و قوانین', size: 22), + Spacer(), + SizedBox(width: 48), + ]), + ), + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 24), + child: GamePanel( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'به حکم‌شو خوش آمدید. لطفاً پیش از استفاده، این شرایط را مطالعه کنید.', + style: TextStyle( + color: Colors.white70, + fontSize: 13, + height: 1.7), + ), + const SizedBox(height: 16), + for (final (title, body) in _sections) ...[ + Text( + title, + style: const TextStyle( + color: AppColors.gold, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 6), + Text( + body, + textAlign: TextAlign.justify, + style: const TextStyle( + color: Colors.white, + fontSize: 13.5, + height: 1.9, + ), + ), + const SizedBox(height: 16), + ], + const Divider(color: AppColors.goldFaint), + const SizedBox(height: 6), + const Text( + 'با ادامه‌ی استفاده از حکم‌شو، این شرایط و قوانین را می‌پذیرید.', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white54, fontSize: 12, height: 1.7), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/feature/profile/presentation/screen/profile_screen.dart b/lib/feature/profile/presentation/screen/profile_screen.dart index fd103fb..a390e8c 100644 --- a/lib/feature/profile/presentation/screen/profile_screen.dart +++ b/lib/feature/profile/presentation/screen/profile_screen.dart @@ -197,6 +197,18 @@ class ProfileScreen extends StatelessWidget { ), const SizedBox(height: 8), _statsSection(context, d), + const SizedBox(height: 16), + Align( + alignment: Alignment.center, + child: TextButton.icon( + onPressed: () => context.push('/terms'), + icon: const Icon(Icons.gavel, color: AppColors.gold, size: 18), + label: const Text( + 'شرایط و قوانین', + style: TextStyle(color: AppColors.gold, fontSize: 14), + ), + ), + ), ], ), );