diff --git a/frontend/.env.example b/frontend/.env.example
new file mode 100644
index 00000000..9cad7b21
--- /dev/null
+++ b/frontend/.env.example
@@ -0,0 +1 @@
+REVENUE_CAT_API_KEY=
\ No newline at end of file
diff --git a/frontend/.gitignore b/frontend/.gitignore
index 57be19c0..c3e8e704 100644
--- a/frontend/.gitignore
+++ b/frontend/.gitignore
@@ -1,3 +1,5 @@
+*.env
+
# Miscellaneous
*.class
*.log
diff --git a/frontend/ios/Podfile.lock b/frontend/ios/Podfile.lock
index 334a3470..21a85848 100644
--- a/frontend/ios/Podfile.lock
+++ b/frontend/ios/Podfile.lock
@@ -1,21 +1,38 @@
PODS:
- Flutter (1.0.0)
+ - purchases_flutter (5.8.2):
+ - Flutter
+ - PurchasesHybridCommon (= 6.3.2)
+ - PurchasesHybridCommon (6.3.2):
+ - RevenueCat (= 4.26.1)
+ - RevenueCat (4.26.1)
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
DEPENDENCIES:
- Flutter (from `Flutter`)
+ - purchases_flutter (from `.symlinks/plugins/purchases_flutter/ios`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
+SPEC REPOS:
+ trunk:
+ - PurchasesHybridCommon
+ - RevenueCat
+
EXTERNAL SOURCES:
Flutter:
:path: Flutter
+ purchases_flutter:
+ :path: ".symlinks/plugins/purchases_flutter/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/darwin"
SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ purchases_flutter: 32697fa7b2aceb2af2dde25826c5f8b74021fcd1
+ PurchasesHybridCommon: 98af59169dd9c418eac0725c43f02db92a643b79
+ RevenueCat: 4e8899a69fd57180ef166237d1eb670023be05de
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
diff --git a/frontend/ios/Runner.xcodeproj/project.pbxproj b/frontend/ios/Runner.xcodeproj/project.pbxproj
index 50fd984c..177178cc 100644
--- a/frontend/ios/Runner.xcodeproj/project.pbxproj
+++ b/frontend/ios/Runner.xcodeproj/project.pbxproj
@@ -473,8 +473,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 4;
- DEVELOPMENT_TEAM = JVX7U43WRX;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = HC3NQ49D3T;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ChessKnock;
@@ -484,7 +484,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = band.effective.chessknock;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.effective.chessknock;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@@ -664,8 +664,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 4;
- DEVELOPMENT_TEAM = JVX7U43WRX;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = HC3NQ49D3T;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ChessKnock;
@@ -675,7 +675,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = band.effective.chessknock;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.effective.chessknock;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@@ -695,8 +695,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 4;
- DEVELOPMENT_TEAM = JVX7U43WRX;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = HC3NQ49D3T;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ChessKnock;
@@ -706,7 +706,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = band.effective.chessknock;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.effective.chessknock;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
diff --git a/frontend/ios/Runner/Info.plist b/frontend/ios/Runner/Info.plist
index a8191529..ae61fda2 100644
--- a/frontend/ios/Runner/Info.plist
+++ b/frontend/ios/Runner/Info.plist
@@ -24,6 +24,8 @@
????
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+ ITSAppUsesNonExemptEncryption
+
LSRequiresIPhoneOS
UIApplicationSupportsIndirectInputEvents
@@ -38,7 +40,5 @@
UIInterfaceOrientationPortrait
- ITSAppUsesNonExemptEncryption
-
diff --git a/frontend/l10n.yaml b/frontend/l10n.yaml
index f3781cab..ca687774 100644
--- a/frontend/l10n.yaml
+++ b/frontend/l10n.yaml
@@ -1,3 +1,4 @@
arb-dir: lib/l10n
template-arb-file: en.arb
output-localization-file: app_localizations.dart
+nullable-getter: false
diff --git a/frontend/lib/common/shared_functions.dart b/frontend/lib/common/shared_functions.dart
index e5169940..1f7b6b25 100644
--- a/frontend/lib/common/shared_functions.dart
+++ b/frontend/lib/common/shared_functions.dart
@@ -1,8 +1,22 @@
import 'package:flutter/material.dart';
+import 'package:frontend/constants/text_styles.dart';
sealed class SharedFunctions {
static bool isTablet(BuildContext context) {
final shortestSide = MediaQuery.of(context).size.shortestSide;
return shortestSide >= 640;
}
+
+ static void showSnackBar(BuildContext context, String text) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ backgroundColor: Colors.black,
+ content: Text(
+ text,
+ style: TextStyles.caption2,
+ ),
+ duration: const Duration(seconds: 2),
+ ),
+ );
+ }
}
diff --git a/frontend/lib/constants/assets.dart b/frontend/lib/constants/assets.dart
new file mode 100644
index 00000000..5bcb5701
--- /dev/null
+++ b/frontend/lib/constants/assets.dart
@@ -0,0 +1,28 @@
+sealed class Assets {
+ static const handbook = "assets/images/icons/handbook.svg";
+ static const loading = "assets/images/icons/loading.svg";
+ static const board = "assets/images/board.svg";
+ static const advantage = 'assets/images/icons/advantage.svg';
+ static const backArrowIcon = "assets/images/icons/back_arrow_icon.svg";
+ static const pointLight = "assets/images/icons/point_light.svg";
+ static const darkSwitch = "assets/images/icons/dark_switch.svg";
+ static const lightSwitch = "assets/images/icons/light_switch.svg";
+ static const proSparkles = 'assets/images/icons/pro_sparkles.svg';
+ static const sun = 'assets/images/icons/sun.svg';
+ static const moon = 'assets/images/icons/moon.svg';
+ static const explosion = 'assets/images/icons/explosion.svg';
+ static const lamp = 'assets/images/icons/lamp.svg';
+ static const book = 'assets/images/icons/book.svg';
+ static const chessPiece = 'assets/images/icons/chess_piece.svg';
+ static const leftBigArrowIcon = "assets/images/icons/left_big_arrow_icon.svg";
+ static const rightBigArrowIcon =
+ "assets/images/icons/right_big_arrow_icon.svg";
+ static const questionIcon = "assets/images/icons/question_icon.svg";
+}
+
+sealed class AssetsPieces {
+ static const bishop = 'assets/images/pieces/bishop.svg';
+ static const rook = 'assets/images/pieces/rook.svg';
+ static const knight = 'assets/images/pieces/knight.svg';
+ static const queen = 'assets/images/pieces/queen.svg';
+}
diff --git a/frontend/lib/constants/constants.dart b/frontend/lib/constants/constants.dart
index 15640624..be66b301 100644
--- a/frontend/lib/constants/constants.dart
+++ b/frontend/lib/constants/constants.dart
@@ -1,4 +1,3 @@
export "colors.dart";
export "text_styles.dart";
-export "string_constants.dart";
export 'gradient_consts.dart';
diff --git a/frontend/lib/constants/string_constants.dart b/frontend/lib/constants/string_constants.dart
deleted file mode 100644
index a6e24c66..00000000
--- a/frontend/lib/constants/string_constants.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-sealed class StringConstants {
- static String proVersionAvailability =
- 'Эта функция доступна \nтолько в Pro версии';
- static String partyHistory = 'История ваших партий';
- static String becomePro = 'Стать Pro';
- static String downgradeFromPro = 'Отменить статус Pro';
-}
diff --git a/frontend/lib/data_sources/in_app_purchase_data_source.dart b/frontend/lib/data_sources/in_app_purchase_data_source.dart
new file mode 100644
index 00000000..3798ed38
--- /dev/null
+++ b/frontend/lib/data_sources/in_app_purchase_data_source.dart
@@ -0,0 +1,5 @@
+abstract interface class IInAppPurchaseDataSource {
+ Future buyProduct(String productId);
+ Future checkStatus(String productId);
+ Future restorePurchases();
+}
diff --git a/frontend/lib/data_sources/revenuecat_data_source.dart b/frontend/lib/data_sources/revenuecat_data_source.dart
new file mode 100644
index 00000000..d3ee34ff
--- /dev/null
+++ b/frontend/lib/data_sources/revenuecat_data_source.dart
@@ -0,0 +1,23 @@
+import 'package:frontend/data_sources/in_app_purchase_data_source.dart';
+import 'package:purchases_flutter/purchases_flutter.dart';
+
+class RevenueCatDataSource implements IInAppPurchaseDataSource {
+ @override
+ Future buyProduct(String productId) async {
+ final product = (await Purchases.getProducts([productId])).first;
+ final customerInfo = await Purchases.purchaseStoreProduct(product);
+ final isPro = customerInfo.entitlements.active[productId] != null;
+ return isPro;
+ }
+
+ @override
+ Future checkStatus(String productId) async {
+ final customerInfo = await Purchases.getCustomerInfo();
+ return customerInfo.entitlements.active.containsKey(productId);
+ }
+
+ @override
+ Future restorePurchases() async {
+ Purchases.restorePurchases();
+ }
+}
diff --git a/frontend/lib/l10n/en.arb b/frontend/lib/l10n/en.arb
index 317a3194..6b32384e 100644
--- a/frontend/lib/l10n/en.arb
+++ b/frontend/lib/l10n/en.arb
@@ -103,5 +103,10 @@
"moveBackModal": "Ability to return\nthe game board one move back",
"threatsModal": "Display of danger\nof your piece being captured",
"hintsModal": "Display of hints\nfor possible moves",
- "description": "Description"
-}
+ "description": "Description",
+ "price": "1.99 $",
+ "purchaseError": "Could not buy the product. Try again later",
+ "restorePurchases": "Restore Purchases",
+ "restorePurchasesError": "Could not restore purchases. Try again later",
+ "restorePurchasesCompleted" : "Restore purchases completed. Check your current status"
+}
\ No newline at end of file
diff --git a/frontend/lib/l10n/ru.arb b/frontend/lib/l10n/ru.arb
index dd3b5fd6..5bc46e54 100644
--- a/frontend/lib/l10n/ru.arb
+++ b/frontend/lib/l10n/ru.arb
@@ -103,5 +103,10 @@
"moveBackModal": "Возможность вернуть\nигровое поле на ход назад",
"threatsModal": "Отображение опасности\nвзятия вашей фигуры",
"hintsModal": "Отображение подсказок\nвозможных ходов",
- "description": "Описание"
-}
+ "description": "Описание",
+ "price": "199 ₽",
+ "purchaseError": "Ошибка покупки товара. Попробуйте позже",
+ "restorePurchases": "Восстановить покупки",
+ "restorePurchasesError": "Ошибка восстановления покупок. Попробуйте позже",
+ "restorePurchasesCompleted" : "Восстановление покупок прошло успешно. Проверьте ваш текущий статус"
+}
\ No newline at end of file
diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart
index 36ee863b..19229c8f 100644
--- a/frontend/lib/main.dart
+++ b/frontend/lib/main.dart
@@ -1,13 +1,30 @@
+import "dart:io";
+
+import "package:flutter_dotenv/flutter_dotenv.dart";
+import "package:frontend/data_sources/revenuecat_data_source.dart";
import "package:frontend/exports.dart";
import "package:flutter/material.dart";
import "package:flutter/services.dart";
+import "package:frontend/repositories/in_app_purchase_repository.dart";
import "package:provider/provider.dart";
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import "package:purchases_flutter/purchases_flutter.dart";
-void main() {
+void main() async {
+ await dotenv.load(fileName: ".env");
+ WidgetsFlutterBinding.ensureInitialized();
+ if (Platform.isIOS) {
+ await configureRevenueCat();
+ }
runApp(const MyApp());
}
+Future configureRevenueCat() async {
+ Purchases.setLogLevel(LogLevel.debug);
+ final apiKey = dotenv.env['REVENUE_CAT_API_KEY'];
+ Purchases.configure(PurchasesConfiguration(apiKey!));
+}
+
class MyApp extends StatelessWidget {
const MyApp({super.key});
@@ -23,7 +40,12 @@ class MyApp extends StatelessWidget {
create: (context) => ThemeProvider(),
),
ChangeNotifierProvider(
- create: (context) => ProVersionProvider(),
+ create: (context) => ProVersionProvider(
+ repository: InAppPurchaseRepository(
+ //TODO: choose data source based off of a platform
+ dataSource: RevenueCatDataSource(),
+ ),
+ ),
)
],
child: Builder(builder: (context) {
diff --git a/frontend/lib/providers/pro_version_errors.dart b/frontend/lib/providers/pro_version_errors.dart
new file mode 100644
index 00000000..eabb16a6
--- /dev/null
+++ b/frontend/lib/providers/pro_version_errors.dart
@@ -0,0 +1 @@
+enum ProVersionError { purchaseError, restoreError }
diff --git a/frontend/lib/providers/pro_version_provider.dart b/frontend/lib/providers/pro_version_provider.dart
index 173e0912..4acb3754 100644
--- a/frontend/lib/providers/pro_version_provider.dart
+++ b/frontend/lib/providers/pro_version_provider.dart
@@ -1,20 +1,69 @@
import 'package:flutter/material.dart';
+import 'package:frontend/providers/pro_version_errors.dart';
+import 'package:frontend/providers/pro_version_states.dart';
+import 'package:frontend/repositories/in_app_purchase_repository.dart';
class ProVersionProvider extends ChangeNotifier {
- bool _isProStatus = false;
+ //The key of a product should be the same as an entitlement name attached to it
+ static const _proVersionKey = 'chessknock_pro_version';
- void _setProStatus(bool status) {
- _isProStatus = status;
- notifyListeners();
+ late ProVersionState _state;
+
+ final InAppPurchaseRepository _repository;
+
+ ProVersionProvider({required InAppPurchaseRepository repository})
+ : _repository = repository {
+ _state = const InitialProVersionState();
+ _init();
}
- void upgradeToPro() {
- _setProStatus(true);
+ void _init() async {
+ final isPro = await _repository.checkStatus(_proVersionKey);
+ _setState(InitialProVersionState(isProStatus: isPro));
+ }
+
+ Future upgradeToPro() async {
+ try {
+ await _repository.buyProduct(_proVersionKey);
+ final isPro = await _repository.checkStatus(_proVersionKey);
+ if (isPro) _setState(const SuccessfulPurchaseState());
+ } catch (_) {
+ _setState(ErrorProVersionState(
+ error: ProVersionError.purchaseError,
+ isProStatus: state.isProStatus,
+ ));
+ }
}
void downgradeFromPro() {
- _setProStatus(false);
+ _setState(const InitialProVersionState());
+ }
+
+ Future restorePurchases() async {
+ try {
+ await _repository.restorePurchases();
+ final isPro = await _repository.checkStatus(_proVersionKey);
+ _setState(SuccessfulRestorePurchasesState(isProStatus: isPro));
+ } catch (_) {
+ _setState(ErrorProVersionState(
+ error: ProVersionError.restoreError,
+ isProStatus: state.isProStatus,
+ ));
+ }
+ }
+
+ void _setState(ProVersionState state) {
+ _state = state;
+ notifyListeners();
}
- bool get isPro => _isProStatus;
+ ProVersionState get state => _state;
+
+ bool get isPro => state.isProStatus;
+ ProVersionError? get error {
+ if (state is ErrorProVersionState) {
+ return (state as ErrorProVersionState).error;
+ }
+ return null;
+ }
}
diff --git a/frontend/lib/providers/pro_version_states.dart b/frontend/lib/providers/pro_version_states.dart
new file mode 100644
index 00000000..d3802f00
--- /dev/null
+++ b/frontend/lib/providers/pro_version_states.dart
@@ -0,0 +1,27 @@
+import 'package:frontend/providers/pro_version_errors.dart';
+
+sealed class ProVersionState {
+ final bool isProStatus;
+
+ const ProVersionState({
+ required this.isProStatus,
+ });
+}
+
+class InitialProVersionState extends ProVersionState {
+ const InitialProVersionState({super.isProStatus = false});
+}
+
+class ErrorProVersionState extends ProVersionState {
+ ErrorProVersionState({required this.error, required super.isProStatus});
+
+ final ProVersionError error;
+}
+
+class SuccessfulRestorePurchasesState extends ProVersionState {
+ SuccessfulRestorePurchasesState({required super.isProStatus});
+}
+
+class SuccessfulPurchaseState extends ProVersionState {
+ const SuccessfulPurchaseState({super.isProStatus = true});
+}
diff --git a/frontend/lib/repositories/in_app_purchase_repository.dart b/frontend/lib/repositories/in_app_purchase_repository.dart
new file mode 100644
index 00000000..b6f56052
--- /dev/null
+++ b/frontend/lib/repositories/in_app_purchase_repository.dart
@@ -0,0 +1,21 @@
+import 'package:frontend/data_sources/in_app_purchase_data_source.dart';
+
+class InAppPurchaseRepository {
+ final IInAppPurchaseDataSource _dataSource;
+
+ InAppPurchaseRepository({
+ required IInAppPurchaseDataSource dataSource,
+ }) : _dataSource = dataSource;
+
+ Future buyProduct(String productId) {
+ return _dataSource.buyProduct(productId);
+ }
+
+ Future checkStatus(String productId) {
+ return _dataSource.checkStatus(productId);
+ }
+
+ Future restorePurchases() async {
+ _dataSource.restorePurchases();
+ }
+}
diff --git a/frontend/lib/views/components/button_to_guide.dart b/frontend/lib/views/components/button_to_guide.dart
index 312b2eb0..82698f1a 100644
--- a/frontend/lib/views/components/button_to_guide.dart
+++ b/frontend/lib/views/components/button_to_guide.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:flutter_svg/svg.dart";
+import "package:frontend/constants/assets.dart";
class ButtonToGuide extends StatelessWidget {
const ButtonToGuide(
@@ -29,7 +30,7 @@ class ButtonToGuide extends StatelessWidget {
constraints: const BoxConstraints(),
color: backGroundColor,
icon: SvgPicture.asset(
- "assets/images/icons/handbook.svg",
+ Assets.handbook,
),
),
);
diff --git a/frontend/lib/views/components/components.dart b/frontend/lib/views/components/components.dart
index 05e17aee..05258009 100644
--- a/frontend/lib/views/components/components.dart
+++ b/frontend/lib/views/components/components.dart
@@ -4,3 +4,4 @@ export "custom_icon_button.dart";
export "loading_widget.dart";
export "custom_tab_bar.dart";
export 'pro_functions_tooltip.dart';
+export 'custom_button.dart';
diff --git a/frontend/lib/views/components/custom_button.dart b/frontend/lib/views/components/custom_button.dart
new file mode 100644
index 00000000..2819d2e8
--- /dev/null
+++ b/frontend/lib/views/components/custom_button.dart
@@ -0,0 +1,31 @@
+import 'package:flutter/material.dart';
+import 'package:frontend/constants/gradient_consts.dart';
+
+class CustomButton extends StatelessWidget {
+ const CustomButton({
+ super.key,
+ required this.onTap,
+ required this.child,
+ this.borderRadius = 16,
+ this.gradient = GradientConsts.orange,
+ });
+
+ final VoidCallback onTap;
+ final Widget child;
+ final double borderRadius;
+ final Gradient gradient;
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: onTap,
+ child: DecoratedBox(
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(borderRadius),
+ gradient: gradient,
+ ),
+ child: Center(child: child),
+ ),
+ );
+ }
+}
diff --git a/frontend/lib/views/components/loading_widget.dart b/frontend/lib/views/components/loading_widget.dart
index cba71bd8..4ea04663 100644
--- a/frontend/lib/views/components/loading_widget.dart
+++ b/frontend/lib/views/components/loading_widget.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:flutter_svg/flutter_svg.dart";
+import "package:frontend/constants/assets.dart";
import "package:frontend/exports.dart";
class LoadingWidget extends StatelessWidget {
@@ -16,7 +17,7 @@ class LoadingWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
- "assets/images/icons/loading.svg",
+ Assets.loading,
colorFilter: ColorFilter.mode(scheme.primary, BlendMode.srcIn),
),
const SizedBox(
diff --git a/frontend/lib/views/components/pro_functions_tooltip.dart b/frontend/lib/views/components/pro_functions_tooltip.dart
index 64fa7d95..04d5c7da 100644
--- a/frontend/lib/views/components/pro_functions_tooltip.dart
+++ b/frontend/lib/views/components/pro_functions_tooltip.dart
@@ -67,7 +67,7 @@ class _ProFunctionsTooltipState extends State {
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Text(
- AppLocalizations.of(context)!.proFeatureDescription,
+ AppLocalizations.of(context).proFeatureDescription,
style: TextStyles.caption1.copyWith(
color: ColorsConst.neutralColor100,
height: 1.3,
diff --git a/frontend/lib/views/game_view/components/back_arrow_button.dart b/frontend/lib/views/game_view/components/back_arrow_button.dart
index d494cf67..81bb9104 100644
--- a/frontend/lib/views/game_view/components/back_arrow_button.dart
+++ b/frontend/lib/views/game_view/components/back_arrow_button.dart
@@ -11,7 +11,7 @@ class BackArrowButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return SizedBox(
height: MediaQuery.sizeOf(context).height * 0.04,
child: Stack(
diff --git a/frontend/lib/views/game_view/components/game_info_and_controls.dart b/frontend/lib/views/game_view/components/game_info_and_controls.dart
index 1745f2c4..a419c6ca 100644
--- a/frontend/lib/views/game_view/components/game_info_and_controls.dart
+++ b/frontend/lib/views/game_view/components/game_info_and_controls.dart
@@ -29,7 +29,8 @@ class GameInfoAndControls extends StatelessWidget {
gameModel,
)
: ProFunctionsTooltip(
- modalHeader: ModalStrings.moveBackModalText(AppLocalizations.of(context)!),
+ modalHeader: ModalStrings.moveBackModalText(
+ AppLocalizations.of(context)),
isPro: isPro,
child: UndoRedoButtons(
gameModel,
diff --git a/frontend/lib/views/game_view/components/game_info_and_controls/game_status.dart b/frontend/lib/views/game_view/components/game_info_and_controls/game_status.dart
index b21d76e4..9d8ec907 100644
--- a/frontend/lib/views/game_view/components/game_info_and_controls/game_status.dart
+++ b/frontend/lib/views/game_view/components/game_info_and_controls/game_status.dart
@@ -9,7 +9,7 @@ class GameStatus extends StatelessWidget {
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Consumer(
builder: (context, gameModel, child) => Row(
mainAxisAlignment: MainAxisAlignment.center,
diff --git a/frontend/lib/views/game_view/components/game_info_and_controls/restart_exit_buttons.dart b/frontend/lib/views/game_view/components/game_info_and_controls/restart_exit_buttons.dart
index 076b00a9..00768997 100644
--- a/frontend/lib/views/game_view/components/game_info_and_controls/restart_exit_buttons.dart
+++ b/frontend/lib/views/game_view/components/game_info_and_controls/restart_exit_buttons.dart
@@ -13,7 +13,7 @@ class RestartExitButtons extends StatelessWidget {
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Row(
children: [
Expanded(
diff --git a/frontend/lib/views/game_view/components/name_with_advantage_widget.dart b/frontend/lib/views/game_view/components/name_with_advantage_widget.dart
index 1bdc8a61..583fb037 100644
--- a/frontend/lib/views/game_view/components/name_with_advantage_widget.dart
+++ b/frontend/lib/views/game_view/components/name_with_advantage_widget.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:frontend/constants/assets.dart';
import '../../../exports.dart';
// ignore: must_be_immutable
@@ -12,7 +13,7 @@ class NameWithAdvantageForPlayer extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
@@ -33,7 +34,7 @@ class NameWithAdvantageForPlayer extends StatelessWidget {
gameModel.advantageForPlayer(player)) ...[
Row(
children: [
- SvgPicture.asset('assets/images/icons/advantage.svg'),
+ SvgPicture.asset(Assets.advantage),
Text(
"+${gameModel.advantageForPlayer(oppositePlayer(player)) - gameModel.advantageForPlayer(player)}",
textAlign: TextAlign.center,
diff --git a/frontend/lib/views/game_view/components/piece_choose_window.dart b/frontend/lib/views/game_view/components/piece_choose_window.dart
index 60127165..10f2bbf1 100644
--- a/frontend/lib/views/game_view/components/piece_choose_window.dart
+++ b/frontend/lib/views/game_view/components/piece_choose_window.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:frontend/constants/assets.dart';
import '../../../exports.dart';
class PieceChooseWindow extends StatelessWidget {
@@ -10,7 +11,7 @@ class PieceChooseWindow extends StatelessWidget {
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Container(
width: 245,
height: 275,
@@ -42,7 +43,7 @@ class PieceChooseWindow extends StatelessWidget {
children: [
IconButton(
icon: SvgPicture.asset(
- 'assets/images/pieces/bishop.svg',
+ AssetsPieces.bishop,
width: 55,
height: 55,
colorFilter:
@@ -55,7 +56,7 @@ class PieceChooseWindow extends StatelessWidget {
),
IconButton(
icon: SvgPicture.asset(
- 'assets/images/pieces/rook.svg',
+ AssetsPieces.rook,
width: 55,
height: 55,
colorFilter:
@@ -74,7 +75,7 @@ class PieceChooseWindow extends StatelessWidget {
children: [
IconButton(
icon: SvgPicture.asset(
- 'assets/images/pieces/knight.svg',
+ AssetsPieces.knight,
width: 55,
height: 55,
colorFilter:
@@ -87,7 +88,7 @@ class PieceChooseWindow extends StatelessWidget {
),
IconButton(
icon: SvgPicture.asset(
- 'assets/images/pieces/queen.svg',
+ AssetsPieces.queen,
width: 55,
height: 55,
colorFilter:
diff --git a/frontend/lib/views/game_view/components/shared_functions.dart b/frontend/lib/views/game_view/components/shared_functions.dart
index af675ae9..45529d10 100644
--- a/frontend/lib/views/game_view/components/shared_functions.dart
+++ b/frontend/lib/views/game_view/components/shared_functions.dart
@@ -3,28 +3,30 @@ import 'package:sqflite/sqflite.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../../exports.dart';
-String getResultForHistory(GameModel gameModel, AppLocalizations l10n) {
+enum GameResult { draw, blackVictory, whiteVictory }
+
+String getResultForHistory(GameModel gameModel) {
if (gameModel.gameOver) {
if (gameModel.stalemate || gameModel.draw) {
- return l10n.draw;
+ return GameResult.draw.name;
} else {
if (gameModel.turn == Player.player1) {
- return l10n.blackVictory;
+ return GameResult.blackVictory.name;
} else {
- return l10n.whiteVictory;
+ return GameResult.whiteVictory.name;
}
}
} else {
- return l10n.draw;
+ return GameResult.draw.name;
}
}
List getPartyData(GameModel gameModel, AppLocalizations l10n) {
- String enemy = gameModel.playerCount == 1 ? l10n.computer : l10n.friend;
+ String enemy = l10n.friend;
String formattedDate = DateFormat("dd.MM.yyyy").format(DateTime.now());
String formattedTime = DateFormat.Hm().format(DateTime.now());
String durationGame = _formatDuration(gameModel.durationOfGame);
- String result = getResultForHistory(gameModel, l10n);
+ String result = getResultForHistory(gameModel);
String color = gameModel.playerSide == Player.player1
? l10n.whitePieces
: l10n.blackPieces;
diff --git a/frontend/lib/views/game_view/constants/game_page_const.dart b/frontend/lib/views/game_view/constants/game_page_const.dart
index 823f70a7..f783f8d1 100644
--- a/frontend/lib/views/game_view/constants/game_page_const.dart
+++ b/frontend/lib/views/game_view/constants/game_page_const.dart
@@ -7,21 +7,4 @@ class GamePageConst {
static const startPos =
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
static List listOfColumns = ["h", "g", "f", "e", "d", "c", "b", "a"];
- static const gameStatusEnemyMove = "Ход противника ";
- static const gameStatusOurMove = "Ваш ход";
- static const gameStatusWhiteMove = "Ход белых";
- static const gameStatusBlackMove = "Ход чёрных";
- static const gameStatusStalemate = "Пат (Ничья)";
- static const gameStatusDraw = "Ничья";
- static const gameStatusBlackWin = "Выиграли чёрные";
- static const gameStatusWhiteWin = "Выиграли белые";
- static const gameEndText = "В главное меню";
- static const continueGameText = "Продолжить игру";
- static const gameRestartText = "Новая игра";
- static const gameGiveUpText = "Сдаться";
- static const gameBackModalHeader = "Сдаться?";
- static const gameResultWin = "Победа";
- static const gameResultLose = "Поражение";
- static const gameResultWinBlack = "Победа чёрных";
- static const gameResultWinWhite = "Победа белых";
}
diff --git a/frontend/lib/views/game_view/game_page_view.dart b/frontend/lib/views/game_view/game_page_view.dart
index 8c58ca64..baea9230 100644
--- a/frontend/lib/views/game_view/game_page_view.dart
+++ b/frontend/lib/views/game_view/game_page_view.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:flutter_svg/flutter_svg.dart";
+import "package:frontend/constants/assets.dart";
import "package:go_router/go_router.dart";
import "package:provider/provider.dart";
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -35,7 +36,7 @@ class _GameViewState extends State {
final scheme = Theme.of(context).colorScheme;
final deviceWidth = MediaQuery.of(context).size.width;
final deviceHeight = MediaQuery.of(context).size.height;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return isLoading
? const LoadingWidget()
: Scaffold(
@@ -80,7 +81,7 @@ class _GameViewState extends State {
Align(
alignment: Alignment.topCenter,
child: SvgPicture.asset(
- "assets/images/board.svg",
+ Assets.board,
width: deviceWidth,
height: deviceWidth *
LogicConsts.boardRatio,
diff --git a/frontend/lib/views/guide_view/components/guide_chose_piece_button.dart b/frontend/lib/views/guide_view/components/guide_chose_piece_button.dart
index 5fe5212c..526e0378 100644
--- a/frontend/lib/views/guide_view/components/guide_chose_piece_button.dart
+++ b/frontend/lib/views/guide_view/components/guide_chose_piece_button.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:flutter_svg/flutter_svg.dart";
+import "package:frontend/constants/assets.dart";
import "package:provider/provider.dart";
import "../../../exports.dart";
@@ -75,7 +76,7 @@ class GuideChosePieceButton extends StatelessWidget {
],
),
SvgPicture.asset(
- "assets/images/icons/back_arrow_icon.svg",
+ Assets.backArrowIcon,
colorFilter: ColorFilter.mode(iconArrowColor, BlendMode.srcIn),
),
],
diff --git a/frontend/lib/views/guide_view/components/guide_piece_carousel.dart b/frontend/lib/views/guide_view/components/guide_piece_carousel.dart
index 5545c959..67e3c22c 100644
--- a/frontend/lib/views/guide_view/components/guide_piece_carousel.dart
+++ b/frontend/lib/views/guide_view/components/guide_piece_carousel.dart
@@ -17,7 +17,7 @@ class GuidePieceCarousel extends StatelessWidget {
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Column(
children: [
diff --git a/frontend/lib/views/guide_view/components/points_indicator.dart b/frontend/lib/views/guide_view/components/points_indicator.dart
index c46ab4f5..7d053031 100644
--- a/frontend/lib/views/guide_view/components/points_indicator.dart
+++ b/frontend/lib/views/guide_view/components/points_indicator.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:flutter_svg/svg.dart";
+import "package:frontend/constants/assets.dart";
class PointsIndicator extends StatelessWidget {
const PointsIndicator(
@@ -16,7 +17,7 @@ class PointsIndicator extends StatelessWidget {
return Row(
children: [
SvgPicture.asset(
- "assets/images/icons/point_light.svg",
+ Assets.pointLight,
width: 10,
height: 10,
colorFilter: ColorFilter.mode(
diff --git a/frontend/lib/views/guide_view/guide_chose_view.dart b/frontend/lib/views/guide_view/guide_chose_view.dart
index b611f2ca..6a2c5c6b 100644
--- a/frontend/lib/views/guide_view/guide_chose_view.dart
+++ b/frontend/lib/views/guide_view/guide_chose_view.dart
@@ -34,7 +34,7 @@ class GuideChoseView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Scaffold(
backgroundColor: scheme.background,
body: SafeArea(
@@ -102,7 +102,7 @@ class GuideChoseView extends StatelessWidget {
)
: ProFunctionsTooltip(
isPro: isPro,
- modalHeader: StringConstants.partyHistory,
+ modalHeader: l10n.partyHistoryPage,
child: GuideChosePieceButton(
iconName: null,
label: l10n.partyHistoryPage,
diff --git a/frontend/lib/views/guide_view/guide_piece_view.dart b/frontend/lib/views/guide_view/guide_piece_view.dart
index d36c0977..037805cc 100644
--- a/frontend/lib/views/guide_view/guide_piece_view.dart
+++ b/frontend/lib/views/guide_view/guide_piece_view.dart
@@ -67,7 +67,7 @@ class _GuideViewState extends State {
iconName: GuideStrings.appbarIcon,
iconColor: scheme.onTertiary,
bottomMargin: 32,
- header: AppLocalizations.of(context)!.guideHeader,
+ header: AppLocalizations.of(context).guideHeader,
),
Expanded(
child: GuidePieceCarousel(
diff --git a/frontend/lib/views/menu_view/components/custom_switch.dart b/frontend/lib/views/menu_view/components/custom_switch.dart
index 4dc44d23..8b176b01 100644
--- a/frontend/lib/views/menu_view/components/custom_switch.dart
+++ b/frontend/lib/views/menu_view/components/custom_switch.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:flutter_svg/flutter_svg.dart";
+import "package:frontend/constants/assets.dart";
import "package:frontend/exports.dart";
class CustomSwitch extends StatefulWidget {
@@ -11,9 +12,6 @@ class CustomSwitch extends StatefulWidget {
}
class _CustomSwitchState extends State {
- final activeIcon = "assets/images/icons/dark_switch.svg";
- final inactiveIcon = "assets/images/icons/light_switch.svg";
-
@override
Widget build(BuildContext context) {
bool isToggle = widget.provider.isDarkMode;
@@ -36,7 +34,8 @@ class _CustomSwitchState extends State {
height: 34,
decoration: const BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
- child: SvgPicture.asset(isToggle ? activeIcon : inactiveIcon),
+ child: SvgPicture.asset(
+ isToggle ? Assets.darkSwitch : Assets.lightSwitch),
),
),
),
diff --git a/frontend/lib/views/menu_view/components/menu_app_bar.dart b/frontend/lib/views/menu_view/components/menu_app_bar.dart
index 0e048c39..78133f5e 100644
--- a/frontend/lib/views/menu_view/components/menu_app_bar.dart
+++ b/frontend/lib/views/menu_view/components/menu_app_bar.dart
@@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
+import 'package:frontend/common/shared_functions.dart';
+import 'package:frontend/providers/pro_version_errors.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../../exports.dart';
class MenuAppBar extends StatelessWidget {
@@ -15,18 +18,22 @@ class MenuAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final provider = Provider.of(context, listen: false);
final scheme = Theme.of(context).colorScheme;
- final isPro = context.watch().isPro;
+ final provider = context.watch();
+ final isPro = provider.isPro;
+ provider.addListener(() {
+ _onListenProvider(context);
+ });
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
isPro
? Row(
children: [
- CustomSwitch(provider),
+ CustomSwitch(
+ Provider.of(context, listen: false)),
const SizedBox(width: 16),
- ProStatusIndicator(onTap: () => context.push(promoScreenRoute)),
+ const ProStatusIndicator(),
],
)
: UpgradeToProButton(onTap: () => context.push(promoScreenRoute)),
@@ -39,4 +46,12 @@ class MenuAppBar extends StatelessWidget {
],
);
}
+
+ void _onListenProvider(BuildContext context) {
+ final provider = context.read();
+ if (provider.error == ProVersionError.purchaseError) {
+ SharedFunctions.showSnackBar(
+ context, AppLocalizations.of(context).purchaseError);
+ }
+ }
}
diff --git a/frontend/lib/views/menu_view/components/pro_status_indicator.dart b/frontend/lib/views/menu_view/components/pro_status_indicator.dart
index c44c6ccc..7b34d511 100644
--- a/frontend/lib/views/menu_view/components/pro_status_indicator.dart
+++ b/frontend/lib/views/menu_view/components/pro_status_indicator.dart
@@ -1,20 +1,22 @@
+import 'dart:io';
+
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:frontend/constants/assets.dart';
import 'package:frontend/exports.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:go_router/go_router.dart';
class ProStatusIndicator extends StatelessWidget {
const ProStatusIndicator({
super.key,
- required this.onTap,
});
- final VoidCallback onTap;
-
@override
Widget build(BuildContext context) {
return GestureDetector(
- onTap: onTap,
+ onTap: () =>
+ (Platform.isIOS) ? context.push(RouteLocations.promoScreen) : null,
child: Row(
children: [
ShaderMask(
@@ -23,7 +25,7 @@ class ProStatusIndicator extends StatelessWidget {
Rect.fromLTWH(0, 0, bounds.width, bounds.height));
},
child: Text(
- AppLocalizations.of(context)!.pro,
+ AppLocalizations.of(context).pro,
style:
TextStyles.body1.copyWith(color: ColorsConst.neutralColor0),
)),
@@ -33,7 +35,7 @@ class ProStatusIndicator extends StatelessWidget {
Rect.fromLTWH(0, 0, bounds.width, bounds.height));
},
child: SvgPicture.asset(
- 'assets/images/icons/pro_sparkles.svg',
+ Assets.proSparkles,
)),
],
),
diff --git a/frontend/lib/views/menu_view/components/upgrade_to_pro_button.dart b/frontend/lib/views/menu_view/components/upgrade_to_pro_button.dart
index 69e81324..b36e024b 100644
--- a/frontend/lib/views/menu_view/components/upgrade_to_pro_button.dart
+++ b/frontend/lib/views/menu_view/components/upgrade_to_pro_button.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:frontend/constants/assets.dart';
import 'package:frontend/exports.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -12,7 +13,7 @@ class UpgradeToProButton extends StatelessWidget {
});
final VoidCallback onTap;
- final int? price;
+ final String? price;
@override
Widget build(BuildContext context) {
@@ -30,53 +31,41 @@ class UpgradeToProButton extends StatelessWidget {
right: 12,
);
final double iconSize = isExtended ? 29 : 24;
- final l10n = AppLocalizations.of(context)!;
- return GestureDetector(
+ final l10n = AppLocalizations.of(context);
+ return CustomButton(
+ borderRadius: isExtended ? 16 : 24,
onTap: onTap,
- child: DecoratedBox(
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(isExtended ? 16 : 24),
- gradient: const LinearGradient(
- colors: [
- Color.fromRGBO(255, 190, 146, 1),
- Color.fromRGBO(220, 101, 35, 1)
+ child: FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Padding(
+ padding: padding,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Builder(builder: (context) {
+ return Text(
+ context.watch().isPro
+ ? l10n.downgradeFromPro
+ : l10n.becomePro,
+ style: style,
+ );
+ }),
+ SvgPicture.asset(
+ fit: BoxFit.fill,
+ height: iconSize,
+ width: iconSize,
+ Assets.proSparkles,
+ colorFilter: const ColorFilter.mode(
+ ColorsConst.neutralColor0, BlendMode.srcIn),
+ ),
+ if (price != null) ...[
+ Text(
+ price!,
+ style: style,
+ )
+ ]
],
- begin: Alignment.topRight,
- end: Alignment.bottomLeft,
- ),
- ),
- child: FittedBox(
- fit: BoxFit.scaleDown,
- child: Padding(
- padding: padding,
- child: Row(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Builder(builder: (context) {
- return Text(
- context.watch().isPro
- ? l10n.downgradeFromPro
- : l10n.becomePro,
- style: style,
- );
- }),
- SvgPicture.asset(
- fit: BoxFit.fill,
- height: iconSize,
- width: iconSize,
- 'assets/images/icons/pro_sparkles.svg',
- colorFilter: const ColorFilter.mode(
- ColorsConst.neutralColor0, BlendMode.srcIn),
- ),
- if (price != null) ...[
- Text(
- '$price ₽',
- style: style,
- )
- ]
- ],
- ),
),
),
),
diff --git a/frontend/lib/views/menu_view/constants/menu_page_string_const.dart b/frontend/lib/views/menu_view/constants/menu_page_string_const.dart
index 82b918f1..a06457b3 100644
--- a/frontend/lib/views/menu_view/constants/menu_page_string_const.dart
+++ b/frontend/lib/views/menu_view/constants/menu_page_string_const.dart
@@ -1,6 +1,3 @@
class MenuPageStringConst {
- static String slogan = "Побеждать\nв шахматах — \nпобеждать\nв жизни";
- static String sloganWide = "Побеждать в шахматах — \nпобеждать в жизни";
- static String localButton = "Начать игру";
static String pathToIcon = "assets/images/icons/";
}
diff --git a/frontend/lib/views/menu_view/phone_menu_layout.dart b/frontend/lib/views/menu_view/phone_menu_layout.dart
index 5be2516a..42c00792 100644
--- a/frontend/lib/views/menu_view/phone_menu_layout.dart
+++ b/frontend/lib/views/menu_view/phone_menu_layout.dart
@@ -20,7 +20,7 @@ class PhoneMenuView extends StatelessWidget {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final colorScheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return ConstrainedBox(
constraints: BoxConstraints(minWidth: width, minHeight: height),
diff --git a/frontend/lib/views/menu_view/tablet_menu_layout.dart b/frontend/lib/views/menu_view/tablet_menu_layout.dart
index 4c00b114..891aee7b 100644
--- a/frontend/lib/views/menu_view/tablet_menu_layout.dart
+++ b/frontend/lib/views/menu_view/tablet_menu_layout.dart
@@ -20,7 +20,7 @@ class TabletMenuView extends StatelessWidget {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final colorScheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return ConstrainedBox(
constraints: BoxConstraints(minWidth: width, minHeight: height),
@@ -77,7 +77,7 @@ class TabletMenuView extends StatelessWidget {
child: MenuButton(
gameModel: gameModel,
height: height * 0.24,
- buttonText: MenuPageStringConst.localButton,
+ buttonText: AppLocalizations.of(context).startGame,
settingsScreenRoute: RouteLocations.settingsScreen,
),
),
diff --git a/frontend/lib/views/party_history_view/components/info_bar_item.dart b/frontend/lib/views/party_history_view/components/info_bar_item.dart
index b413cafd..07c4e6c1 100644
--- a/frontend/lib/views/party_history_view/components/info_bar_item.dart
+++ b/frontend/lib/views/party_history_view/components/info_bar_item.dart
@@ -3,45 +3,28 @@ import 'package:flutter_svg/svg.dart';
import 'package:frontend/exports.dart';
class InfoBarItem extends StatelessWidget {
- const InfoBarItem({super.key, required this.index, required this.isComputer});
+ const InfoBarItem({super.key, required this.text, required this.iconColor});
- final int index;
- final bool isComputer;
+ final String text;
+ final Color iconColor;
@override
Widget build(BuildContext context) {
- final scheme = Theme.of(context).colorScheme;
- List computerColors = [
- scheme.onSecondaryContainer,
- scheme.primary,
- ColorsConst.secondaryColor100
- ];
-
- List friendColors = [
- scheme.primaryContainer,
- scheme.onSecondary,
- scheme.onSurface
- ];
-
return Row(
children: [
SvgPicture.asset(
PartyHistoryConst.infoPartyIconName,
height: 24,
width: 24,
- colorFilter: ColorFilter.mode(
- isComputer ? computerColors[index] : friendColors[index],
- BlendMode.srcIn),
+ colorFilter: ColorFilter.mode(iconColor, BlendMode.srcIn),
),
const SizedBox(
width: 4,
),
Text(
- isComputer
- ? PartyHistoryConst.gameResults[index]
- : PartyHistoryConst.friendGameResults[index],
+ text,
style: TextStyles.caption2.copyWith(
- color: scheme.primary,
+ color: Theme.of(context).colorScheme.primary,
height: 0.09,
),
),
diff --git a/frontend/lib/views/party_history_view/components/info_party_bar.dart b/frontend/lib/views/party_history_view/components/info_party_bar.dart
index 7439b89d..f0cbe4a6 100644
--- a/frontend/lib/views/party_history_view/components/info_party_bar.dart
+++ b/frontend/lib/views/party_history_view/components/info_party_bar.dart
@@ -1,20 +1,19 @@
import 'package:flutter/material.dart';
import 'package:frontend/exports.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class InfoPartyBar extends StatelessWidget {
const InfoPartyBar({
super.key,
required this.height,
- required this.isComputer,
});
final double height;
- final bool isComputer;
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
-
+ final l10n = AppLocalizations.of(context);
return Container(
height: height,
width: double.infinity,
@@ -23,49 +22,33 @@ class InfoPartyBar extends StatelessWidget {
decoration: BoxDecoration(
color: scheme.onSurfaceVariant,
borderRadius: BorderRadius.circular(16)),
- child: isComputer
- ? Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- mainAxisSize: MainAxisSize.min,
- children: List.generate(PartyHistoryConst.gameResults.length,
- (index) {
- return Row(
- children: [
- InfoBarItem(
- index: index,
- isComputer: isComputer,
- ),
- ],
- );
- }),
- )
- : Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- InfoBarItem(
- index: 0,
- isComputer: isComputer,
- ),
- const SizedBox(),
- InfoBarItem(
- index: 1,
- isComputer: isComputer,
- )
- ],
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- InfoBarItem(
- index: 2,
- isComputer: isComputer,
- ),
- ],
- )
- ],
- ));
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ InfoBarItem(
+ text: l10n.whiteVictory,
+ iconColor: scheme.primaryContainer,
+ ),
+ const SizedBox(),
+ InfoBarItem(
+ text: l10n.blackVictory,
+ iconColor: scheme.onSecondary,
+ )
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ InfoBarItem(
+ text: l10n.draw,
+ iconColor: scheme.onSurface,
+ ),
+ ],
+ )
+ ],
+ ));
}
}
diff --git a/frontend/lib/views/party_history_view/components/one_party_view_widget.dart b/frontend/lib/views/party_history_view/components/one_party_view_widget.dart
index b6164e5d..a89efac3 100644
--- a/frontend/lib/views/party_history_view/components/one_party_view_widget.dart
+++ b/frontend/lib/views/party_history_view/components/one_party_view_widget.dart
@@ -4,26 +4,19 @@ import 'package:frontend/exports.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class OnePartyViewWidget extends StatelessWidget {
- const OnePartyViewWidget(
- {super.key, required this.partyData, required this.isComputer});
+ const OnePartyViewWidget({super.key, required this.partyData});
final Map partyData;
- final bool isComputer;
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
- Map computerListOfColorsIcons = {
- l10n.victory: scheme.onSecondaryContainer,
- l10n.defeat: scheme.primary,
- l10n.draw: ColorsConst.secondaryColor100
- };
+ final l10n = AppLocalizations.of(context);
Map friendListOfColorsIcons = {
- l10n.whiteVictory: scheme.primaryContainer,
- l10n.blackVictory: scheme.onSecondary,
- l10n.draw: scheme.onSurface
+ GameResult.whiteVictory.name: scheme.primaryContainer,
+ GameResult.blackVictory.name: scheme.onSecondary,
+ GameResult.draw.name: scheme.onSurface
};
return Container(
margin: const EdgeInsets.only(bottom: 12, left: 24, right: 24),
@@ -36,9 +29,8 @@ class OnePartyViewWidget extends StatelessWidget {
height: 35,
width: 35,
colorFilter: ColorFilter.mode(
- isComputer
- ? computerListOfColorsIcons[partyData["result"]]!
- : friendListOfColorsIcons[partyData["result"]]!,
+ friendListOfColorsIcons[partyData["result"]] ??
+ ColorsConst.disabledColor,
BlendMode.srcIn),
),
const SizedBox(
@@ -68,9 +60,7 @@ class OnePartyViewWidget extends StatelessWidget {
child: Row(
children: [
Column(
- mainAxisAlignment: isComputer
- ? MainAxisAlignment.spaceBetween
- : MainAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
@@ -82,23 +72,12 @@ class OnePartyViewWidget extends StatelessWidget {
height: 1,
),
),
- isComputer
- ? Text(
- l10n.pieceColor,
- style: TextStyles.caption1.copyWith(
- color: scheme.error,
- height: 1,
- ),
- )
- : const SizedBox(),
],
),
SizedBox(
width: 50,
child: Column(
- mainAxisAlignment: isComputer
- ? MainAxisAlignment.spaceBetween
- : MainAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
partyData["durationGame"] != "00:00"
@@ -110,18 +89,6 @@ class OnePartyViewWidget extends StatelessWidget {
),
)
: const SizedBox(),
- isComputer
- ? Container(
- width: 12,
- height: 12,
- margin: const EdgeInsets.only(right: 4),
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(50),
- color: partyData["color"] == l10n.whitePieces
- ? scheme.inverseSurface
- : ColorsConst.neutralColor100),
- )
- : const SizedBox()
],
),
)
diff --git a/frontend/lib/views/party_history_view/constants/party_history_const.dart b/frontend/lib/views/party_history_view/constants/party_history_const.dart
index 83003a3f..401b6b4b 100644
--- a/frontend/lib/views/party_history_view/constants/party_history_const.dart
+++ b/frontend/lib/views/party_history_view/constants/party_history_const.dart
@@ -1,22 +1,10 @@
class PartyHistoryConst {
- static String partyHistoryHeader = "История партий";
-
static String appbarIconName = "assets/images/icons/left_big_arrow_icon.svg";
static String appbarMainIcon = "assets/images/icons/cancel.svg";
static String infoPartyIconName = "assets/images/icons/black.svg";
- static List gameResults = ["Победа", "Поражение", "Ничья"];
-
- static List friendGameResults = [
- "Победа белых",
- "Победа чёрных",
- "Ничья"
- ];
-
- static List gameEnemies = ["Компьютер", "Друг"];
-
static String dbCreateScript = """CREATE TABLE History (
id INTEGER PRIMARY KEY,
enemy STRING,
diff --git a/frontend/lib/views/party_history_view/party_history_main_view.dart b/frontend/lib/views/party_history_view/party_history_main_view.dart
index bb345667..16a8a417 100644
--- a/frontend/lib/views/party_history_view/party_history_main_view.dart
+++ b/frontend/lib/views/party_history_view/party_history_main_view.dart
@@ -57,7 +57,7 @@ class _PartyHistoryMainViewState extends State {
iconName: PartyHistoryConst.appbarMainIcon,
iconColor: scheme.onTertiary,
bottomMargin: 32,
- header: AppLocalizations.of(context)!.gameHistory,
+ header: AppLocalizations.of(context).gameHistory,
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 24),
@@ -65,7 +65,6 @@ class _PartyHistoryMainViewState extends State {
children: [
InfoPartyBar(
height: 80,
- isComputer: false,
),
SizedBox(height: 24),
],
@@ -76,7 +75,6 @@ class _PartyHistoryMainViewState extends State {
itemCount: friendParties.length,
itemBuilder: (context, index) {
return OnePartyViewWidget(
- isComputer: false,
partyData: friendParties[index],
);
},
diff --git a/frontend/lib/views/promo_view/components/bottom_buttons_section.dart b/frontend/lib/views/promo_view/components/bottom_buttons_section.dart
new file mode 100644
index 00000000..6864eebc
--- /dev/null
+++ b/frontend/lib/views/promo_view/components/bottom_buttons_section.dart
@@ -0,0 +1,55 @@
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:frontend/exports.dart';
+import 'package:go_router/go_router.dart';
+import 'package:provider/provider.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+class BottomButtonsSection extends StatelessWidget {
+ const BottomButtonsSection({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ if (!context.watch().isPro) ...[
+ SizedBox(
+ width: double.infinity,
+ child: ConstrainedBox(
+ constraints: BoxConstraints(
+ maxHeight: MediaQuery.sizeOf(context).height * 0.07,
+ ),
+ child: UpgradeToProButton(
+ onTap: () {
+ context.read().isPro
+ ? _onDownGradeFromPro(context)
+ : context.read().upgradeToPro();
+ context.pop();
+ },
+ price: AppLocalizations.of(context).price),
+ ),
+ ),
+ SizedBox(
+ height: MediaQuery.sizeOf(context).height * 0.02,
+ ),
+ ],
+ if (Platform.isIOS) ...[
+ SizedBox(
+ width: double.infinity,
+ child: ConstrainedBox(
+ constraints: BoxConstraints(
+ maxHeight: MediaQuery.sizeOf(context).height * 0.07,
+ ),
+ child: const RestorePurchasesButton()),
+ )
+ ]
+ ],
+ );
+ }
+
+ void _onDownGradeFromPro(BuildContext context) {
+ context.read().downgradeFromPro();
+ context.read().resetTheme();
+ }
+}
diff --git a/frontend/lib/views/promo_view/components/components.dart b/frontend/lib/views/promo_view/components/components.dart
index d11ae818..96edbc1a 100644
--- a/frontend/lib/views/promo_view/components/components.dart
+++ b/frontend/lib/views/promo_view/components/components.dart
@@ -1,3 +1,5 @@
export 'promo_feature_card.dart';
export 'promo_screen_header.dart';
export 'promo_cards_section.dart';
+export 'restore_purchases_button.dart';
+export 'bottom_buttons_section.dart';
diff --git a/frontend/lib/views/promo_view/components/promo_cards_section.dart b/frontend/lib/views/promo_view/components/promo_cards_section.dart
index 146a105b..477cd44c 100644
--- a/frontend/lib/views/promo_view/components/promo_cards_section.dart
+++ b/frontend/lib/views/promo_view/components/promo_cards_section.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:frontend/constants/assets.dart';
import 'package:frontend/exports.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -11,7 +12,7 @@ class PromoCardsSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Column(
children: [
PromoFeatureCard(
@@ -23,9 +24,9 @@ class PromoCardsSection extends StatelessWidget {
columnAlignment: CrossAxisAlignment.end,
backgroundImages: [
SvgPicture.asset(
- 'assets/images/icons/sun.svg',
+ Assets.sun,
),
- SvgPicture.asset('assets/images/icons/moon.svg')
+ SvgPicture.asset(Assets.moon)
],
),
const SizedBox(height: 10),
@@ -36,7 +37,7 @@ class PromoCardsSection extends StatelessWidget {
columnAlignment: CrossAxisAlignment.start,
backgroundImages: [
SvgPicture.asset(
- 'assets/images/icons/chess_piece.svg',
+ Assets.chessPiece,
)
],
),
@@ -50,7 +51,7 @@ class PromoCardsSection extends StatelessWidget {
gradient: GradientConsts.orange,
backgroundImages: [
SvgPicture.asset(
- 'assets/images/icons/explosion.svg',
+ Assets.explosion,
)
],
)),
@@ -62,7 +63,7 @@ class PromoCardsSection extends StatelessWidget {
gradient: GradientConsts.orange,
backgroundImages: [
SvgPicture.asset(
- 'assets/images/icons/lamp.svg',
+ Assets.lamp,
)
],
))
@@ -76,7 +77,7 @@ class PromoCardsSection extends StatelessWidget {
gradient: GradientConsts.lightGrey,
backgroundImages: [
SvgPicture.asset(
- 'assets/images/icons/book.svg',
+ Assets.book,
)
],
),
diff --git a/frontend/lib/views/promo_view/components/promo_screen_header.dart b/frontend/lib/views/promo_view/components/promo_screen_header.dart
index c03852a3..d3674daa 100644
--- a/frontend/lib/views/promo_view/components/promo_screen_header.dart
+++ b/frontend/lib/views/promo_view/components/promo_screen_header.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:frontend/constants/assets.dart';
import 'package:frontend/exports.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -18,7 +19,7 @@ class PromoScreenHeader extends StatelessWidget {
alignment: AlignmentDirectional.centerStart,
children: [
CustomIconButton(
- iconName: "assets/images/icons/left_big_arrow_icon.svg",
+ iconName: Assets.leftBigArrowIcon,
color: scheme.onTertiary,
iconSize: 40,
onTap: () {
@@ -28,7 +29,7 @@ class PromoScreenHeader extends StatelessWidget {
Center(
child: FittedBox(
child: Text(
- AppLocalizations.of(context)!.proVersion,
+ AppLocalizations.of(context).proVersion,
style: TextStyles.header2
.copyWith(color: scheme.primary, height: 1.3),
),
diff --git a/frontend/lib/views/promo_view/components/restore_purchases_button.dart b/frontend/lib/views/promo_view/components/restore_purchases_button.dart
new file mode 100644
index 00000000..d6ce2803
--- /dev/null
+++ b/frontend/lib/views/promo_view/components/restore_purchases_button.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:frontend/common/shared_functions.dart';
+import 'package:frontend/exports.dart';
+import 'package:frontend/providers/pro_version_errors.dart';
+import 'package:frontend/providers/pro_version_states.dart';
+import 'package:provider/provider.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+class RestorePurchasesButton extends StatelessWidget {
+ const RestorePurchasesButton({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final provider = context.read();
+ provider.addListener(() {
+ _onListenProvider(context);
+ });
+
+ return CustomButton(
+ gradient: GradientConsts.grey,
+ onTap: provider.restorePurchases,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 16),
+ child: Text(
+ AppLocalizations.of(context).restorePurchases,
+ style:
+ TextStyles.header1.copyWith(color: ColorsConst.neutralColor0),
+ ),
+ ));
+ }
+
+ void _onListenProvider(BuildContext context) {
+ final provider = context.read();
+ if (provider.error == ProVersionError.restoreError) {
+ SharedFunctions.showSnackBar(
+ context, AppLocalizations.of(context).restorePurchasesError);
+ }
+ if (provider.state is SuccessfulRestorePurchasesState) {
+ SharedFunctions.showSnackBar(
+ context, AppLocalizations.of(context).restorePurchasesCompleted);
+ }
+ }
+}
diff --git a/frontend/lib/views/promo_view/constants/constants.dart b/frontend/lib/views/promo_view/constants/constants.dart
deleted file mode 100644
index 30f477bf..00000000
--- a/frontend/lib/views/promo_view/constants/constants.dart
+++ /dev/null
@@ -1 +0,0 @@
-export 'promo_page_constants.dart';
diff --git a/frontend/lib/views/promo_view/constants/promo_page_constants.dart b/frontend/lib/views/promo_view/constants/promo_page_constants.dart
deleted file mode 100644
index 457746b7..00000000
--- a/frontend/lib/views/promo_view/constants/promo_page_constants.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-sealed class PromoPageConstants {
- static const themeSwitchHeader = 'Смена темы приложения';
- static const themeSwitchDescription =
- 'Настраивай приложение \nпод себя в один клик';
- static const personalModeHeader = 'Персональный режим';
- static const personalModeDescription =
- 'Настраивай параметры \nи собирай свой режим игры';
- static const threatsDescription = 'Угрозы \nвашим фигурам';
- static const hintsDesctiption = 'Подсказки \nво время игры';
- static const gamesHistoryHeader = 'История партий';
- static const gamesHistoryDescription = 'Смотри историю \nсыгранных партий';
- static const proVersion = 'Pro-версия';
- static const proVersionPrice = 120;
-}
diff --git a/frontend/lib/views/promo_view/promo_page_view.dart b/frontend/lib/views/promo_view/promo_page_view.dart
index d7c8e605..703b1651 100644
--- a/frontend/lib/views/promo_view/promo_page_view.dart
+++ b/frontend/lib/views/promo_view/promo_page_view.dart
@@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
import 'package:frontend/exports.dart';
-import 'package:go_router/go_router.dart';
-import 'package:provider/provider.dart';
class PromoPageView extends StatelessWidget {
const PromoPageView({super.key});
@@ -15,38 +13,15 @@ class PromoPageView extends StatelessWidget {
horizontal: 24,
vertical: MediaQuery.sizeOf(context).height * 0.02,
),
- child: Column(
+ child: const Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- const PromoScreenHeader(),
- const PromoCardsSection(),
- SizedBox(
- width: double.infinity,
- child: ConstrainedBox(
- constraints: BoxConstraints(
- maxHeight: MediaQuery.sizeOf(context).height * 0.07,
- ),
- child: UpgradeToProButton(
- onTap: () {
- context.read().isPro
- ? _onDownGradeFromPro(context)
- : context.read().upgradeToPro();
- context.pop();
- },
- price: context.read().isPro
- ? null
- : PromoPageConstants.proVersionPrice,
- ),
- ),
- )
+ PromoScreenHeader(),
+ PromoCardsSection(),
+ BottomButtonsSection(),
],
),
)),
);
}
-
- void _onDownGradeFromPro(BuildContext context) {
- context.read().downgradeFromPro();
- context.read().resetTheme();
- }
}
diff --git a/frontend/lib/views/promo_view/promo_view.dart b/frontend/lib/views/promo_view/promo_view.dart
index c52e298f..8be1cb02 100644
--- a/frontend/lib/views/promo_view/promo_view.dart
+++ b/frontend/lib/views/promo_view/promo_view.dart
@@ -1,3 +1,2 @@
export 'components/components.dart';
export 'promo_page_view.dart';
-export 'constants/constants.dart';
diff --git a/frontend/lib/views/setting_view/components/app_bar_settings.dart b/frontend/lib/views/setting_view/components/app_bar_settings.dart
index 6ed2754a..ade06f16 100644
--- a/frontend/lib/views/setting_view/components/app_bar_settings.dart
+++ b/frontend/lib/views/setting_view/components/app_bar_settings.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:frontend/common/shared_functions.dart";
+import "package:frontend/constants/assets.dart";
import "package:go_router/go_router.dart";
import "../../../exports.dart";
@@ -16,7 +17,7 @@ class AppBarSettings extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomIconButton(
- iconName: "assets/images/icons/left_big_arrow_icon.svg",
+ iconName: Assets.leftBigArrowIcon,
color: scheme.onTertiary,
iconSize: isTablet ? 50 : 40,
onTap: () {
diff --git a/frontend/lib/views/setting_view/components/chose_color_widget.dart b/frontend/lib/views/setting_view/components/chose_color_widget.dart
index d00502a4..6e85bbaa 100644
--- a/frontend/lib/views/setting_view/components/chose_color_widget.dart
+++ b/frontend/lib/views/setting_view/components/chose_color_widget.dart
@@ -17,7 +17,7 @@ class ChoseColorWidget extends StatelessWidget {
return Column(
children: [
TextHeading(
- text: AppLocalizations.of(context)!.pieceColor,
+ text: AppLocalizations.of(context).pieceColor,
topMargin: 32,
bottomMargin: 16,
),
diff --git a/frontend/lib/views/setting_view/components/chose_time_carousel.dart b/frontend/lib/views/setting_view/components/chose_time_carousel.dart
index 31d28fbd..a79fa11c 100644
--- a/frontend/lib/views/setting_view/components/chose_time_carousel.dart
+++ b/frontend/lib/views/setting_view/components/chose_time_carousel.dart
@@ -1,4 +1,5 @@
import "package:flutter/material.dart";
+import "package:frontend/constants/assets.dart";
import "package:provider/provider.dart";
import "package:wheel_chooser/wheel_chooser.dart";
@@ -56,7 +57,7 @@ class _ChoseTimeCarouselState extends State {
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomIconButton(
- iconName: "assets/images/icons/left_big_arrow_icon.svg",
+ iconName: Assets.leftBigArrowIcon,
color: scheme.onTertiary,
iconSize: 30,
onTap: () {
@@ -91,7 +92,7 @@ class _ChoseTimeCarouselState extends State {
),
),
CustomIconButton(
- iconName: "assets/images/icons/right_big_arrow_icon.svg",
+ iconName: Assets.rightBigArrowIcon,
color: scheme.onTertiary,
iconSize: 30,
onTap: () {
diff --git a/frontend/lib/views/setting_view/components/color_chose_button.dart b/frontend/lib/views/setting_view/components/color_chose_button.dart
index 7967863c..b40b6d59 100644
--- a/frontend/lib/views/setting_view/components/color_chose_button.dart
+++ b/frontend/lib/views/setting_view/components/color_chose_button.dart
@@ -18,7 +18,7 @@ class ColorChoseButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
Map icon = {
Player.player2: "black.svg",
Player.player1: "white.svg",
diff --git a/frontend/lib/views/setting_view/components/set_time_section.dart b/frontend/lib/views/setting_view/components/set_time_section.dart
index e27c4ec8..a1719ddf 100644
--- a/frontend/lib/views/setting_view/components/set_time_section.dart
+++ b/frontend/lib/views/setting_view/components/set_time_section.dart
@@ -17,7 +17,7 @@ class SetTimeSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Column(
children: [
ChoseTimeCarousel(
diff --git a/frontend/lib/views/setting_view/components/settings_row.dart b/frontend/lib/views/setting_view/components/settings_row.dart
index dc7ec97a..8879e6de 100644
--- a/frontend/lib/views/setting_view/components/settings_row.dart
+++ b/frontend/lib/views/setting_view/components/settings_row.dart
@@ -1,5 +1,6 @@
import "package:flutter/material.dart";
import "package:flutter_svg/flutter_svg.dart";
+import "package:frontend/constants/assets.dart";
import "package:frontend/common/shared_functions.dart";
import "package:frontend/exports.dart";
import "package:provider/provider.dart";
@@ -51,7 +52,7 @@ class _SettingsRowState extends State {
isPro: isPro,
modalHeader: widget.modalHeader,
child: SvgPicture.asset(
- "assets/images/icons/question_icon.svg",
+ Assets.questionIcon,
colorFilter: ColorFilter.mode(
isPro
? scheme.tertiaryContainer
diff --git a/frontend/lib/views/setting_view/components/settings_rows_section.dart b/frontend/lib/views/setting_view/components/settings_rows_section.dart
index 5a9d4f75..0f4eabe7 100644
--- a/frontend/lib/views/setting_view/components/settings_rows_section.dart
+++ b/frontend/lib/views/setting_view/components/settings_rows_section.dart
@@ -12,7 +12,7 @@ class SettingsRowsSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context)!;
+ final l10n = AppLocalizations.of(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
diff --git a/frontend/lib/views/setting_view/constants/game_setting_const.dart b/frontend/lib/views/setting_view/constants/game_setting_const.dart
index b36bead9..c2d90d5b 100644
--- a/frontend/lib/views/setting_view/constants/game_setting_const.dart
+++ b/frontend/lib/views/setting_view/constants/game_setting_const.dart
@@ -1,30 +1,6 @@
class GameSettingConsts {
- static String appBarLabel = "Параметры";
- static String gameModeText = "Режим игры";
- static String colorPiecesText = "Цвет фигур";
- static String timeText = "Время";
- static String gameSettingsHeader = "Настройки партии";
- static String choseDiffModalHeader = "Уровень сложности бота";
- static String personalLevelDifficultyText = "Сложность бота";
- static String additionalSettingsText = "Дополнительно";
- static String startGameText = "Начать партию";
- static String gameWithComputerText = "С компьютером";
- static String gameWithHumanText = "С другом";
- static String gameWithTimeText = "С часами";
- static String gameWithoutTimeText = "Без часов";
- static String minutesSubtitle = "Минут на партию";
- static String secondsSubtitle = "Добавление секунд на ход";
- static String moveBackText = "Возврат ходов";
- static String threatsText = "Угрозы";
- static String hintsText = "Подсказки";
- static String easyDescription = "Подсказки и возврат хода";
- static String mediumDescription = "Только возврат хода";
- static String hardDescription = "Никакой помощи";
- static String personalityDescription = "Настрой под себя";
static String longDashSymbol = "—";
- static String whiteColorChose = "Белые";
- static String blackColorChose = "Чёрные";
- static String randomColorChose = "Случайный цвет";
+
static int countOfDifficultyLevels = 3;
static List listOfDurations = [
diff --git a/frontend/lib/views/setting_view/game_settings_mobile.dart b/frontend/lib/views/setting_view/game_settings_mobile.dart
index 561b6329..188a5e9c 100644
--- a/frontend/lib/views/setting_view/game_settings_mobile.dart
+++ b/frontend/lib/views/setting_view/game_settings_mobile.dart
@@ -9,6 +9,8 @@ class GameSettingsMobile extends StatelessWidget {
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
final gameSettingsProvider = context.read();
+ final l10n = AppLocalizations.of(context);
+
return DefaultTabController(
length: 2,
child: Scaffold(
@@ -41,14 +43,13 @@ class GameSettingsMobile extends StatelessWidget {
builder: (_, values, __) => Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
- AppBarSettings(
- label: GameSettingConsts.appBarLabel),
+ AppBarSettings(label: l10n.settings),
CustomTabBar(
initialIndex: values.withoutTime ? 0 : 1,
- header: GameSettingConsts.timeText,
+ header: l10n.time,
subTitles: [
- GameSettingConsts.gameWithoutTimeText,
- GameSettingConsts.gameWithTimeText,
+ l10n.withoutTimer,
+ l10n.withTimer,
],
isSettingsPage: true,
onTap: (dynamic index) =>
@@ -88,7 +89,7 @@ class GameSettingsMobile extends StatelessWidget {
right: 23,
),
child: NextPageButton(
- text: GameSettingConsts.startGameText,
+ text: l10n.startGameButton,
textColor: ColorsConst.primaryColor0,
buttonColor: scheme.secondaryContainer,
isClickable: true,
diff --git a/frontend/lib/views/setting_view/game_settings_tablet.dart b/frontend/lib/views/setting_view/game_settings_tablet.dart
index 5d95758d..be914e16 100644
--- a/frontend/lib/views/setting_view/game_settings_tablet.dart
+++ b/frontend/lib/views/setting_view/game_settings_tablet.dart
@@ -8,7 +8,7 @@ class GameSettingsTablet extends StatelessWidget {
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
final gameSettingsProvider = context.read();
-
+ final l10n = AppLocalizations.of(context);
return DefaultTabController(
length: 2,
child: Scaffold(
@@ -40,14 +40,13 @@ class GameSettingsTablet extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
- AppBarSettings(
- label: GameSettingConsts.appBarLabel),
+ AppBarSettings(label: l10n.settings),
CustomTabBar(
initialIndex: values.withoutTime ? 0 : 1,
- header: GameSettingConsts.timeText,
+ header: l10n.time,
subTitles: [
- GameSettingConsts.gameWithoutTimeText,
- GameSettingConsts.gameWithTimeText,
+ l10n.withoutTimer,
+ l10n.withTimer,
],
isSettingsPage: true,
onTap: (dynamic index) =>
@@ -90,7 +89,7 @@ class GameSettingsTablet extends StatelessWidget {
right: 23,
),
child: NextPageButton(
- text: GameSettingConsts.startGameText,
+ text: l10n.startGameButton,
textColor: ColorsConst.primaryColor0,
buttonColor: scheme.secondaryContainer,
isClickable: true,
diff --git a/frontend/lib/views/setting_view/game_settings_view.dart b/frontend/lib/views/setting_view/game_settings_view.dart
index 171db46c..41d356b2 100644
--- a/frontend/lib/views/setting_view/game_settings_view.dart
+++ b/frontend/lib/views/setting_view/game_settings_view.dart
@@ -1,6 +1,7 @@
import "package:flutter/material.dart";
import "package:frontend/common/shared_functions.dart";
import "package:frontend/views/setting_view/providers/game_settings_provider.dart";
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import "package:provider/provider.dart";
diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock
index dc616a49..decbc298 100644
--- a/frontend/pubspec.lock
+++ b/frontend/pubspec.lock
@@ -126,6 +126,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ flutter_dotenv:
+ dependency: "direct main"
+ description:
+ name: flutter_dotenv
+ sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.2.1"
flutter_launcher_icons:
dependency: "direct dev"
description:
@@ -165,6 +173,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ freezed_annotation:
+ dependency: transitive
+ description:
+ name: freezed_annotation
+ sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.4"
go_router:
dependency: "direct main"
description:
@@ -201,10 +217,10 @@ packages:
dependency: "direct main"
description:
name: intl
- sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
+ sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
- version: "0.18.1"
+ version: "0.19.0"
json_annotation:
dependency: transitive
description:
@@ -213,6 +229,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.9.0"
+ leak_tracker:
+ dependency: transitive
+ description:
+ name: leak_tracker
+ sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "10.0.4"
+ leak_tracker_flutter_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_flutter_testing
+ sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.3"
+ leak_tracker_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_testing
+ sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.1"
lints:
dependency: transitive
description:
@@ -233,26 +273,26 @@ packages:
dependency: transitive
description:
name: matcher
- sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
+ sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
- version: "0.12.16"
+ version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
- sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
+ sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
- version: "0.5.0"
+ version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
- sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
+ sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
- version: "1.10.0"
+ version: "1.12.0"
nested:
dependency: transitive
description:
@@ -273,10 +313,10 @@ packages:
dependency: transitive
description:
name: path
- sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+ sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
- version: "1.8.3"
+ version: "1.9.0"
path_parsing:
dependency: transitive
description:
@@ -301,6 +341,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.1.2"
+ purchases_flutter:
+ dependency: "direct main"
+ description:
+ name: purchases_flutter
+ sha256: ccf446dc474dab5e07fcb359845928c1f7e7cb269223f058d42f1254fa25bcdf
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.8.2"
sky_engine:
dependency: transitive
description: flutter
@@ -391,10 +439,10 @@ packages:
dependency: transitive
description:
name: test_api
- sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
+ sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev"
source: hosted
- version: "0.6.1"
+ version: "0.7.0"
typed_data:
dependency: transitive
description:
@@ -435,6 +483,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
+ url: "https://pub.dev"
+ source: hosted
+ version: "14.2.1"
web:
dependency: transitive
description:
diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml
index 4ab46ddb..5f3104f0 100644
--- a/frontend/pubspec.yaml
+++ b/frontend/pubspec.yaml
@@ -27,6 +27,8 @@ dependencies:
super_tooltip: ^2.0.9
flutter_localizations:
sdk: flutter
+ purchases_flutter: ^5.8.0
+ flutter_dotenv: ^5.2.1
dev_dependencies:
flutter_test:
@@ -51,6 +53,7 @@ flutter:
- assets/images/small_pieces/
- assets/images/icons/
- assets/images/guide_boards/
+ - .env
fonts:
- family: Roboto