From bb200df46eb2ab11f7010e5deab5dcced3a6e117 Mon Sep 17 00:00:00 2001 From: AmirrezaChegini Date: Thu, 23 Oct 2025 09:43:41 +0330 Subject: [PATCH 1/2] add: based feature --- lib/core/routers/my_routes.dart | 8 +++ .../datasource/battle_league_datasource.dart | 29 ++++++++++ .../data/model/battle_league_model.dart | 14 +++++ .../battle_league_repository_impl.dart | 30 ++++++++++ .../domain/entity/battle_league_entity.dart | 15 +++++ .../repository/battle_league_repository.dart | 9 +++ .../usecases/get_battle_league_usecase.dart | 18 ++++++ .../binding/battle_league_binding.dart | 21 +++++++ .../controller/battle_league_controller.dart | 55 +++++++++++++++++++ .../presentation/ui/battle_league_page.dart | 13 +++++ lib/init_bindings.dart | 9 +++ 11 files changed, 221 insertions(+) create mode 100644 lib/features/battle_league/data/datasource/battle_league_datasource.dart create mode 100644 lib/features/battle_league/data/model/battle_league_model.dart create mode 100644 lib/features/battle_league/data/repository_impl/battle_league_repository_impl.dart create mode 100644 lib/features/battle_league/domain/entity/battle_league_entity.dart create mode 100644 lib/features/battle_league/domain/repository/battle_league_repository.dart create mode 100644 lib/features/battle_league/domain/usecases/get_battle_league_usecase.dart create mode 100644 lib/features/battle_league/presentation/binding/battle_league_binding.dart create mode 100644 lib/features/battle_league/presentation/controller/battle_league_controller.dart create mode 100644 lib/features/battle_league/presentation/ui/battle_league_page.dart diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index dd600e2..3665101 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -10,6 +10,8 @@ import 'package:shia_game_flutter/features/profile/presentation/binding/profile_ import 'package:shia_game_flutter/features/profile/presentation/ui/profile_page.dart'; import 'package:shia_game_flutter/features/sample/presentation/binding/sample_binding.dart'; import 'package:shia_game_flutter/features/sample/presentation/ui/sample_page.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/binding/battle_league_binding.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/battle_league_page.dart'; import 'package:get/get.dart'; import 'package:shia_game_flutter/features/shop/presentation/binding/shop_binding.dart'; import 'package:shia_game_flutter/features/shop/presentation/ui/shop_page.dart'; @@ -26,6 +28,7 @@ class Routes { static const String shopPage = '/shop_page'; static const String awardsPage = '/awards_page'; static const String profilePage = '/profile_page'; + static const String battleLeaguePage = '/battle_league_page'; } List get appPages => [ @@ -66,4 +69,9 @@ List get appPages => [ ), ], ), + GetPage( + name: Routes.battleLeaguePage, + page: () => const BattleLeaguePage(), + binding: BattleLeagueBinding(), + ), ]; diff --git a/lib/features/battle_league/data/datasource/battle_league_datasource.dart b/lib/features/battle_league/data/datasource/battle_league_datasource.dart new file mode 100644 index 0000000..dce5a9c --- /dev/null +++ b/lib/features/battle_league/data/datasource/battle_league_datasource.dart @@ -0,0 +1,29 @@ +import 'package:shia_game_flutter/core/constants/my_api.dart'; +import 'package:shia_game_flutter/core/network/http_request.dart'; +import 'package:shia_game_flutter/core/params/sample_params.dart'; +import 'package:shia_game_flutter/core/response/base_response.dart'; +import 'package:shia_game_flutter/features/battle_league/data/model/battle_league_model.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/battle_league_entity.dart'; + +abstract class IBattleLeagueDatasource { + Future getData({required SampleParams params}); +} + +class BattleLeagueDatasourceImpl implements IBattleLeagueDatasource { + final IHttpRequest httpRequest; + + const BattleLeagueDatasourceImpl(this.httpRequest); + + @override + Future getData({required SampleParams params}) async { + final response = await httpRequest.get( + path: MyApi.baseUrl, + ); + + return BaseResponse.getData( + response?['data'], + (json) => BattleLeagueModel.fromJson(json), + ); + } +} + diff --git a/lib/features/battle_league/data/model/battle_league_model.dart b/lib/features/battle_league/data/model/battle_league_model.dart new file mode 100644 index 0000000..ad9329c --- /dev/null +++ b/lib/features/battle_league/data/model/battle_league_model.dart @@ -0,0 +1,14 @@ +import 'package:shia_game_flutter/features/battle_league/domain/entity/battle_league_entity.dart'; + +class BattleLeagueModel extends BattleLeagueEntity { + const BattleLeagueModel({ + super.id, + }); + + factory BattleLeagueModel.fromJson(Map json) { + return BattleLeagueModel( + id: json['id'], + ); + } +} + diff --git a/lib/features/battle_league/data/repository_impl/battle_league_repository_impl.dart b/lib/features/battle_league/data/repository_impl/battle_league_repository_impl.dart new file mode 100644 index 0000000..20d6668 --- /dev/null +++ b/lib/features/battle_league/data/repository_impl/battle_league_repository_impl.dart @@ -0,0 +1,30 @@ +import 'package:flutter/foundation.dart'; +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/sample_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/battle_league/data/datasource/battle_league_datasource.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/battle_league_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/repository/battle_league_repository.dart'; + +class BattleLeagueRepositoryImpl implements IBattleLeagueRepository { + final IBattleLeagueDatasource datasource; + + const BattleLeagueRepositoryImpl(this.datasource); + + @override + Future> getData({required SampleParams params}) async { + try { + final BattleLeagueEntity response = await datasource.getData(params: params); + return DataState.success(response); + } on MyException catch (e) { + return DataState.error(e); + } catch (e) { + if (kDebugMode) { + rethrow; + } else { + return DataState.error(MyException(errorMessage: '$e')); + } + } + } +} + diff --git a/lib/features/battle_league/domain/entity/battle_league_entity.dart b/lib/features/battle_league/domain/entity/battle_league_entity.dart new file mode 100644 index 0000000..d532d4b --- /dev/null +++ b/lib/features/battle_league/domain/entity/battle_league_entity.dart @@ -0,0 +1,15 @@ +import 'package:equatable/equatable.dart'; + +class BattleLeagueEntity extends Equatable { + final int? id; + + const BattleLeagueEntity({ + this.id, + }); + + @override + List get props => [ + id, + ]; +} + diff --git a/lib/features/battle_league/domain/repository/battle_league_repository.dart b/lib/features/battle_league/domain/repository/battle_league_repository.dart new file mode 100644 index 0000000..9d7cc47 --- /dev/null +++ b/lib/features/battle_league/domain/repository/battle_league_repository.dart @@ -0,0 +1,9 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/sample_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/battle_league_entity.dart'; + +abstract class IBattleLeagueRepository { + Future> getData({required SampleParams params}); +} + diff --git a/lib/features/battle_league/domain/usecases/get_battle_league_usecase.dart b/lib/features/battle_league/domain/usecases/get_battle_league_usecase.dart new file mode 100644 index 0000000..f69f6e7 --- /dev/null +++ b/lib/features/battle_league/domain/usecases/get_battle_league_usecase.dart @@ -0,0 +1,18 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/sample_params.dart'; +import 'package:shia_game_flutter/core/usecase/usecase.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/battle_league_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/repository/battle_league_repository.dart'; + +class GetBattleLeagueUseCase implements UseCase { + final IBattleLeagueRepository repository; + + const GetBattleLeagueUseCase(this.repository); + + @override + Future> call(SampleParams params) { + return repository.getData(params: params); + } +} + diff --git a/lib/features/battle_league/presentation/binding/battle_league_binding.dart b/lib/features/battle_league/presentation/binding/battle_league_binding.dart new file mode 100644 index 0000000..7ab12a7 --- /dev/null +++ b/lib/features/battle_league/presentation/binding/battle_league_binding.dart @@ -0,0 +1,21 @@ +import 'package:shia_game_flutter/features/battle_league/presentation/controller/battle_league_controller.dart'; +import 'package:get/get.dart'; + +class BattleLeagueBinding extends Bindings { + @override + void dependencies() { + Get.put(BattleLeagueController(Get.find())); + } + + Future deleteBindings() async { + await Future.wait([ + Get.delete(), + ]); + } + + Future refreshBinding() async { + await deleteBindings(); + dependencies(); + } +} + diff --git a/lib/features/battle_league/presentation/controller/battle_league_controller.dart b/lib/features/battle_league/presentation/controller/battle_league_controller.dart new file mode 100644 index 0000000..fd0db52 --- /dev/null +++ b/lib/features/battle_league/presentation/controller/battle_league_controller.dart @@ -0,0 +1,55 @@ +import 'package:flutter/cupertino.dart'; +import 'package:shia_game_flutter/core/params/sample_params.dart'; +import 'package:shia_game_flutter/core/status/base_status.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/battle_league_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_battle_league_usecase.dart'; +import 'package:get/get.dart'; + +class BattleLeagueController extends GetxController with StateMixin { + /// ----- Constructor ----- + BattleLeagueController(this.getBattleLeagueUseCase); + + @override + void onInit() { + super.onInit(); + change('', status: RxStatus.success()); + } + + @override + void onClose() { + textEditingController.dispose(); + super.onClose(); + } + + /// ----- UseCases ----- + final GetBattleLeagueUseCase getBattleLeagueUseCase; + + /// ----- Variables ----- + final Rx battleLeagueParams = Rx(SampleParams()); + final Rx battleLeagueEntity = Rx(const BattleLeagueEntity()); + + /// ------ Controllers ------ + final TextEditingController textEditingController = TextEditingController(); + + /// ------ Statuses ------ + final Rx getBattleLeagueStatus = Rx(const BaseInit()); + + /// ------ Functions ------ + + /// ------ Api Calls ------ + Future getBattleLeague() async { + change('', status: RxStatus.loading()); + await getBattleLeagueUseCase(battleLeagueParams.value).then( + (value) => value.fold( + (data) { + battleLeagueEntity.value = data; + change('', status: RxStatus.success()); + }, + (error) { + change('', status: RxStatus.error(error.errorMessage)); + }, + ), + ); + } +} + diff --git a/lib/features/battle_league/presentation/ui/battle_league_page.dart b/lib/features/battle_league/presentation/ui/battle_league_page.dart new file mode 100644 index 0000000..5f13dca --- /dev/null +++ b/lib/features/battle_league/presentation/ui/battle_league_page.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/controller/battle_league_controller.dart'; +import 'package:get/get.dart'; + +class BattleLeaguePage extends GetView { + const BattleLeaguePage({super.key}); + + @override + Widget build(BuildContext context) { + return const Scaffold(); + } +} + diff --git a/lib/init_bindings.dart b/lib/init_bindings.dart index 0d703b9..213f6b3 100644 --- a/lib/init_bindings.dart +++ b/lib/init_bindings.dart @@ -25,6 +25,10 @@ import 'package:shia_game_flutter/features/sample/data/datasource/sample_datasou import 'package:shia_game_flutter/features/sample/data/repository_impl/sample_repository_impl.dart'; import 'package:shia_game_flutter/features/sample/domain/repository/sample_repository.dart'; import 'package:shia_game_flutter/features/sample/domain/usecases/get_sample_usecase.dart'; +import 'package:shia_game_flutter/features/battle_league/data/datasource/battle_league_datasource.dart'; +import 'package:shia_game_flutter/features/battle_league/data/repository_impl/battle_league_repository_impl.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/repository/battle_league_repository.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_battle_league_usecase.dart'; import 'package:shia_game_flutter/features/shop/data/datasource/shop_datasource.dart'; import 'package:shia_game_flutter/features/shop/data/repository_impl/shop_repository_impl.dart'; import 'package:shia_game_flutter/features/shop/domain/repository/shop_repository.dart'; @@ -68,4 +72,9 @@ void initBindings() { Get.lazyPut(() => ProfileDatasourceImpl(Get.find()), fenix: true); Get.lazyPut(() => ProfileRepositoryImpl(Get.find()), fenix: true); Get.lazyPut(() => GetProfileUseCase(Get.find()), fenix: true); + + /// ----- BattleLeague Feature ----- + Get.lazyPut(() => BattleLeagueDatasourceImpl(Get.find())); + Get.lazyPut(() => BattleLeagueRepositoryImpl(Get.find())); + Get.lazyPut(() => GetBattleLeagueUseCase(Get.find())); } -- 2.30.2 From d88803128a0f06fb9b7d753ba115d902fbf4992d Mon Sep 17 00:00:00 2001 From: AmirrezaChegini Date: Fri, 24 Oct 2025 14:29:34 +0330 Subject: [PATCH 2/2] add: battle league ranking widgets --- assets/svg/icon_rank.svg | 9 ++ lib/common_ui/resources/my_assets.dart | 1 + .../widgets/app_bar/enums/app_bar_type.dart | 36 +++++++ lib/core/widgets/app_bar/master_app_bar.dart | 57 ----------- lib/core/widgets/app_bar/my_app_bar.dart | 56 +++++++++++ .../app_bar/styles/battle_league_app_bar.dart | 40 ++++++++ .../app_bar/styles/master_app_bar.dart | 66 +++++++++++++ .../{styles => widgets}/app_bar_action.dart | 6 +- .../app_bar_add_widget.dart | 16 ++-- .../app_bar/widgets/app_bar_back_button.dart | 27 ++++++ .../widgets/app_bar_gradient_title.dart | 23 +++++ .../widgets/app_bar/widgets/app_bar_info.dart | 29 ++++++ .../controller/battle_league_controller.dart | 7 +- .../presentation/ui/battle_league_page.dart | 66 ++++++++++++- .../widgets/battle_league_start_button.dart | 49 ++++++++++ .../ui/widgets/battle_league_tab_bar.dart | 39 ++++++++ .../ui/widgets/filter_ranking_button.dart | 42 ++++++++ .../ui/widgets/my_ranking_widget.dart | 35 +++++++ .../ui/widgets/ranking_region.dart | 35 +++++++ .../ui/widgets/ranking_scrollbar.dart | 29 ++++++ .../presentation/ui/widgets/ranking_time.dart | 62 ++++++++++++ .../ui/widgets/ranking_widget.dart | 42 ++++++++ .../ui/widgets/regional_ranking.dart | 91 ++++++++++++++++++ .../presentation/ui/widgets/time_ranking.dart | 95 +++++++++++++++++++ .../master/presentation/ui/master_page.dart | 2 +- lib/l10n/app_en.arb | 10 +- lib/l10n/app_localizations.dart | 48 ++++++++++ lib/l10n/app_localizations_en.dart | 24 +++++ lib/main.dart | 2 +- pubspec.lock | 8 ++ pubspec.yaml | 1 + 31 files changed, 977 insertions(+), 76 deletions(-) create mode 100644 assets/svg/icon_rank.svg create mode 100644 lib/core/widgets/app_bar/enums/app_bar_type.dart delete mode 100644 lib/core/widgets/app_bar/master_app_bar.dart create mode 100644 lib/core/widgets/app_bar/my_app_bar.dart create mode 100644 lib/core/widgets/app_bar/styles/battle_league_app_bar.dart create mode 100644 lib/core/widgets/app_bar/styles/master_app_bar.dart rename lib/core/widgets/app_bar/{styles => widgets}/app_bar_action.dart (86%) rename lib/core/widgets/app_bar/{styles => widgets}/app_bar_add_widget.dart (88%) create mode 100644 lib/core/widgets/app_bar/widgets/app_bar_back_button.dart create mode 100644 lib/core/widgets/app_bar/widgets/app_bar_gradient_title.dart create mode 100644 lib/core/widgets/app_bar/widgets/app_bar_info.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/battle_league_start_button.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/battle_league_tab_bar.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/filter_ranking_button.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/my_ranking_widget.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/ranking_region.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/ranking_scrollbar.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/ranking_time.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/ranking_widget.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/regional_ranking.dart create mode 100644 lib/features/battle_league/presentation/ui/widgets/time_ranking.dart diff --git a/assets/svg/icon_rank.svg b/assets/svg/icon_rank.svg new file mode 100644 index 0000000..7f2bd98 --- /dev/null +++ b/assets/svg/icon_rank.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/lib/common_ui/resources/my_assets.dart b/lib/common_ui/resources/my_assets.dart index 98c589f..bf6a215 100644 --- a/lib/common_ui/resources/my_assets.dart +++ b/lib/common_ui/resources/my_assets.dart @@ -63,6 +63,7 @@ class MyAssets { static const String castAwardGold = 'assets/svg/cast_award_gold.svg'; static const String castAwardSilver = 'assets/svg/cast_award_silver.svg'; static const String castAwardBronze = 'assets/svg/cast_award_bronze.svg'; + static const String iconRank = 'assets/svg/icon_rank.svg'; /// ----- Audios ----- diff --git a/lib/core/widgets/app_bar/enums/app_bar_type.dart b/lib/core/widgets/app_bar/enums/app_bar_type.dart new file mode 100644 index 0000000..5ab6666 --- /dev/null +++ b/lib/core/widgets/app_bar/enums/app_bar_type.dart @@ -0,0 +1,36 @@ +import 'package:flutter/cupertino.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/styles/battle_league_app_bar.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/styles/master_app_bar.dart'; + +enum AppBarType { + master, + battleLeague; + + static Map title({ + void Function()? onDiamondTap, + void Function()? onFlashTap, + void Function()? onShareTap, + void Function()? onSettingTap, + void Function()? onInfoTap, + int? diamondNumber, + int? flashNumber, + String? title, + bool? hasInfo + }) { + return { + AppBarType.master: MasterAppBar( + onDiamondTap: onDiamondTap, + onFlashTap: onFlashTap, + onShareTap: onShareTap, + onSettingTap: onSettingTap, + diamondNumber: diamondNumber, + flashNumber: flashNumber, + ), + AppBarType.battleLeague: BattleLeagueAppBar( + title: title, + hasInfo: hasInfo, + onInfoTap: onInfoTap, + ), + }; + } +} \ No newline at end of file diff --git a/lib/core/widgets/app_bar/master_app_bar.dart b/lib/core/widgets/app_bar/master_app_bar.dart deleted file mode 100644 index 5e4ba7f..0000000 --- a/lib/core/widgets/app_bar/master_app_bar.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; -import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; -import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; -import 'package:shia_game_flutter/core/utils/gap.dart'; -import 'package:shia_game_flutter/core/widgets/app_bar/styles/app_bar_action.dart'; -import 'package:shia_game_flutter/core/widgets/app_bar/styles/app_bar_add_widget.dart'; - -class MasterAppBar extends StatelessWidget implements PreferredSizeWidget { - const MasterAppBar({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return AppBar( - backgroundColor: context.backgroundColor, - titleSpacing: MySpaces.s30, - title: Row( - children: [ - AppBarAddWidget( - onTap: () {}, - icon: MyAssets.iconDiamond, - number: 999, - gradientColors: [ - const Color(0XFF52C3ED), - const Color(0XFF4F16A0), - ], - ), - MySpaces.s6.gapWidth, - AppBarAddWidget( - onTap: () {}, - icon: MyAssets.iconFlash, - number: 54, - gradientColors: [ - const Color(0XFFEFB345), - const Color(0XFF4F16A0), - ], - ), - const Spacer(), - AppBarAction( - icon: MyAssets.iconShare, - onTap: () {}, - ), - MySpaces.s12.gapWidth, - AppBarAction( - icon: MyAssets.iconSetting, - onTap: () {}, - ), - ], - ), - ); - } - - @override - Size get preferredSize => const Size.fromHeight(kToolbarHeight); -} diff --git a/lib/core/widgets/app_bar/my_app_bar.dart b/lib/core/widgets/app_bar/my_app_bar.dart new file mode 100644 index 0000000..e4760de --- /dev/null +++ b/lib/core/widgets/app_bar/my_app_bar.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/enums/app_bar_type.dart'; + +class MyAppBar extends StatelessWidget implements PreferredSizeWidget { + const MyAppBar({ + super.key, + this.backgroundColor, + this.type = AppBarType.master, + this.onDiamondTap, + this.onFlashTap, + this.onInfoTap, + this.onSettingTap, + this.onShareTap, + this.diamondNumber, + this.flashNumber, + this.title, + this.hasInfo, + }); + + final AppBarType type; + final Color? backgroundColor; + final VoidCallback? onDiamondTap; + final VoidCallback? onFlashTap; + final VoidCallback? onInfoTap; + final VoidCallback? onSettingTap; + final VoidCallback? onShareTap; + final int? diamondNumber; + final int? flashNumber; + final String? title; + final bool? hasInfo; + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: backgroundColor, + centerTitle: true, + titleSpacing: MySpaces.s30, + title: AppBarType.title( + title: title, + diamondNumber: diamondNumber, + flashNumber: flashNumber, + hasInfo: hasInfo, + onDiamondTap: onDiamondTap, + onFlashTap: onFlashTap, + onInfoTap: onInfoTap, + onSettingTap: onSettingTap, + onShareTap: onShareTap, + )[type], + automaticallyImplyLeading: false, + ); + } + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} diff --git a/lib/core/widgets/app_bar/styles/battle_league_app_bar.dart b/lib/core/widgets/app_bar/styles/battle_league_app_bar.dart new file mode 100644 index 0000000..9684a4b --- /dev/null +++ b/lib/core/widgets/app_bar/styles/battle_league_app_bar.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/widgets/app_bar_back_button.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/widgets/app_bar_gradient_title.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/widgets/app_bar_info.dart'; + +class BattleLeagueAppBar extends StatelessWidget implements PreferredSizeWidget { + const BattleLeagueAppBar({ + super.key, + this.title, + this.hasInfo, + this.onInfoTap, + }); + + final String? title; + final bool? hasInfo; + final VoidCallback? onInfoTap; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const AppBarBackButton(), + AppBarGradientTitle(title: title ?? ''), + Builder( + builder: (context) { + if(hasInfo ?? false){ + return AppBarInfo(onTap: onInfoTap); + } else { + return const SizedBox.shrink(); + } + }, + ), + ], + ); + } + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} \ No newline at end of file diff --git a/lib/core/widgets/app_bar/styles/master_app_bar.dart b/lib/core/widgets/app_bar/styles/master_app_bar.dart new file mode 100644 index 0000000..f8c22c3 --- /dev/null +++ b/lib/core/widgets/app_bar/styles/master_app_bar.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/widgets/app_bar_action.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/widgets/app_bar_add_widget.dart'; + +class MasterAppBar extends StatelessWidget implements PreferredSizeWidget { + const MasterAppBar({ + super.key, + this.onDiamondTap, + this.onFlashTap, + this.onShareTap, + this.onSettingTap, + this.diamondNumber, + this.flashNumber, + }); + + final VoidCallback? onDiamondTap; + final VoidCallback? onFlashTap; + final VoidCallback? onShareTap; + final VoidCallback? onSettingTap; + final int? diamondNumber; + final int? flashNumber; + + + @override + Widget build(BuildContext context) { + return Row( + children: [ + AppBarAddWidget( + onTap: onDiamondTap, + icon: MyAssets.iconDiamond, + number: diamondNumber ?? 0, + gradientColors: [ + const Color(0XFF52C3ED), + const Color(0XFF4F16A0), + ], + ), + MySpaces.s6.gapWidth, + AppBarAddWidget( + onTap: onFlashTap, + icon: MyAssets.iconFlash, + number: flashNumber ?? 0, + gradientColors: [ + const Color(0XFFEFB345), + const Color(0XFF4F16A0), + ], + ), + const Spacer(), + AppBarAction( + icon: MyAssets.iconShare, + onTap: onShareTap, + ), + MySpaces.s12.gapWidth, + AppBarAction( + icon: MyAssets.iconSetting, + onTap: onSettingTap, + ), + ], + ); + } + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} diff --git a/lib/core/widgets/app_bar/styles/app_bar_action.dart b/lib/core/widgets/app_bar/widgets/app_bar_action.dart similarity index 86% rename from lib/core/widgets/app_bar/styles/app_bar_action.dart rename to lib/core/widgets/app_bar/widgets/app_bar_action.dart index a8af150..493e601 100644 --- a/lib/core/widgets/app_bar/styles/app_bar_action.dart +++ b/lib/core/widgets/app_bar/widgets/app_bar_action.dart @@ -4,9 +4,9 @@ import 'package:shia_game_flutter/core/widgets/container/my_container.dart'; import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; class AppBarAction extends StatelessWidget { - const AppBarAction({super.key, this.icon, this.onTap}); + const AppBarAction({super.key, required this.icon, this.onTap}); - final String? icon; + final String icon; final VoidCallback? onTap; @override @@ -23,7 +23,7 @@ class AppBarAction extends StatelessWidget { end: AlignmentDirectional.bottomEnd, colors: [Color(0XFF823FEB), Color(0XFF4F09BF)], ), - child: MyImage(asset: icon ?? ''), + child: MyImage(asset: icon), ); } } \ No newline at end of file diff --git a/lib/core/widgets/app_bar/styles/app_bar_add_widget.dart b/lib/core/widgets/app_bar/widgets/app_bar_add_widget.dart similarity index 88% rename from lib/core/widgets/app_bar/styles/app_bar_add_widget.dart rename to lib/core/widgets/app_bar/widgets/app_bar_add_widget.dart index 584b98e..a7392de 100644 --- a/lib/core/widgets/app_bar/styles/app_bar_add_widget.dart +++ b/lib/core/widgets/app_bar/widgets/app_bar_add_widget.dart @@ -10,16 +10,16 @@ import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; class AppBarAddWidget extends StatelessWidget { const AppBarAddWidget({ super.key, - this.icon, - this.number, + required this.icon, + required this.number, this.onTap, - this.gradientColors, + required this.gradientColors, }); - final String? icon; - final int? number; + final String icon; + final int number; final VoidCallback? onTap; - final List? gradientColors; + final List gradientColors; @override Widget build(BuildContext context) { @@ -31,7 +31,7 @@ class AppBarAddWidget extends StatelessWidget { borderGradient: LinearGradient( begin: AlignmentDirectional.topStart, end: AlignmentDirectional.bottomEnd, - colors: gradientColors ?? [], + colors: gradientColors, ), padding: const EdgeInsetsDirectional.only( start: MySpaces.s8, @@ -40,7 +40,7 @@ class AppBarAddWidget extends StatelessWidget { color: context.backgroundColor, child: Row( children: [ - MyImage(asset: icon ?? ''), + MyImage(asset: icon), Expanded( child: Text( '$number', diff --git a/lib/core/widgets/app_bar/widgets/app_bar_back_button.dart b/lib/core/widgets/app_bar/widgets/app_bar_back_button.dart new file mode 100644 index 0000000..939a50e --- /dev/null +++ b/lib/core/widgets/app_bar/widgets/app_bar_back_button.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/widgets/container/my_container.dart'; + +class AppBarBackButton extends StatelessWidget { + const AppBarBackButton({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MyContainer( + onTap: () => Get.back(), + height: MySpaces.s32, + width: MySpaces.s32, + borderRadius: const BorderRadius.all(Radius.circular(12)), + color: context.primaryColor.withValues(alpha: 0.1), + child: Icon( + Icons.arrow_back_ios_new_rounded, + color: context.primaryColor, + size: MySpaces.s18, + ), + ); + } +} diff --git a/lib/core/widgets/app_bar/widgets/app_bar_gradient_title.dart b/lib/core/widgets/app_bar/widgets/app_bar_gradient_title.dart new file mode 100644 index 0000000..0588b94 --- /dev/null +++ b/lib/core/widgets/app_bar/widgets/app_bar_gradient_title.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/core/widgets/text/gradient_text.dart'; + +class AppBarGradientTitle extends StatelessWidget { + const AppBarGradientTitle({ + super.key, + required this.title, + }); + + final String title; + + @override + Widget build(BuildContext context) { + return GradientText( + text: title, + color: const Color(0XFFCAA8FF), + fontSize: 22, + shadowColor: const Color(0XFF3E1381), + offset: const Offset(0, 1.69), + blurRadius: 0.84, + ); + } +} \ No newline at end of file diff --git a/lib/core/widgets/app_bar/widgets/app_bar_info.dart b/lib/core/widgets/app_bar/widgets/app_bar_info.dart new file mode 100644 index 0000000..893f4ec --- /dev/null +++ b/lib/core/widgets/app_bar/widgets/app_bar_info.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/widgets/container/my_container.dart'; + +class AppBarInfo extends StatelessWidget { + const AppBarInfo({ + super.key, + this.onTap, + }); + + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + return MyContainer( + onTap: onTap, + height: MySpaces.s32, + width: MySpaces.s32, + borderRadius: const BorderRadius.all(Radius.circular(12)), + color: context.primaryColor.withValues(alpha: 0.1), + child: Icon( + Icons.info_outline_rounded, + color: context.primaryColor, + size: MySpaces.s20, + ), + ); + } +} diff --git a/lib/features/battle_league/presentation/controller/battle_league_controller.dart b/lib/features/battle_league/presentation/controller/battle_league_controller.dart index fd0db52..242cfc9 100644 --- a/lib/features/battle_league/presentation/controller/battle_league_controller.dart +++ b/lib/features/battle_league/presentation/controller/battle_league_controller.dart @@ -1,11 +1,12 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:shia_game_flutter/core/params/sample_params.dart'; import 'package:shia_game_flutter/core/status/base_status.dart'; import 'package:shia_game_flutter/features/battle_league/domain/entity/battle_league_entity.dart'; import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_battle_league_usecase.dart'; import 'package:get/get.dart'; -class BattleLeagueController extends GetxController with StateMixin { +class BattleLeagueController extends GetxController + with StateMixin, GetSingleTickerProviderStateMixin { /// ----- Constructor ----- BattleLeagueController(this.getBattleLeagueUseCase); @@ -13,6 +14,7 @@ class BattleLeagueController extends GetxController with StateMixin { void onInit() { super.onInit(); change('', status: RxStatus.success()); + tabController = TabController(length: 2, vsync: this); } @override @@ -30,6 +32,7 @@ class BattleLeagueController extends GetxController with StateMixin { /// ------ Controllers ------ final TextEditingController textEditingController = TextEditingController(); + late final TabController tabController; /// ------ Statuses ------ final Rx getBattleLeagueStatus = Rx(const BaseInit()); diff --git a/lib/features/battle_league/presentation/ui/battle_league_page.dart b/lib/features/battle_league/presentation/ui/battle_league_page.dart index 5f13dca..9d9954f 100644 --- a/lib/features/battle_league/presentation/ui/battle_league_page.dart +++ b/lib/features/battle_league/presentation/ui/battle_league_page.dart @@ -1,13 +1,73 @@ import 'package:flutter/material.dart'; -import 'package:shia_game_flutter/features/battle_league/presentation/controller/battle_league_controller.dart'; import 'package:get/get.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/utils/my_localization.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/enums/app_bar_type.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/my_app_bar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/controller/battle_league_controller.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/battle_league_start_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/battle_league_tab_bar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/regional_ranking.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/time_ranking.dart'; class BattleLeaguePage extends GetView { const BattleLeaguePage({super.key}); @override Widget build(BuildContext context) { - return const Scaffold(); + return Scaffold( + backgroundColor: const Color(0XFF390C82), + appBar: MyAppBar( + type: AppBarType.battleLeague, + backgroundColor: context.noColor, + title: context.translate.battle_league, + hasInfo: true, + onInfoTap: () {}, + ), + body: SafeArea( + child: Column( + children: [ + MySpaces.s30.gapHeight, + Padding( + padding: const EdgeInsets.symmetric(horizontal: MySpaces.s30), + child: BattleLeagueTabBar( + controller: controller.tabController, + tabs: [ + context.translate.time_ranking, + context.translate.regional_ranking, + ], + ), + ), + MySpaces.s12.gapHeight, + Expanded( + child: TabBarView( + controller: controller.tabController, + children: const [ + Padding( + padding: EdgeInsets.symmetric(horizontal: MySpaces.s30), + child: TimeRanking(), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: MySpaces.s30), + child: RegionalRanking(), + ), + ], + ), + ), + 56.0.gapHeight, + Padding( + padding: const EdgeInsets.symmetric(horizontal: MySpaces.s30), + child: BattleLeagueStartButton( + title: context.translate.play_now, + onTap: () {}, + ), + ), + MySpaces.s16.gapHeight, + ], + ), + ), + ); } } - diff --git a/lib/features/battle_league/presentation/ui/widgets/battle_league_start_button.dart b/lib/features/battle_league/presentation/ui/widgets/battle_league_start_button.dart new file mode 100644 index 0000000..d2b7ca1 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/battle_league_start_button.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/core/utils/screen_size.dart'; +import 'package:shia_game_flutter/core/widgets/container/my_container.dart'; +import 'package:shia_game_flutter/core/widgets/text/gradient_text.dart'; + +class BattleLeagueStartButton extends StatelessWidget { + const BattleLeagueStartButton({ + super.key, + this.onTap, + this.title, + }); + + final VoidCallback? onTap; + final String? title; + + @override + Widget build(BuildContext context) { + return MyContainer( + onTap: onTap, + width: context.widthScreen, + height: 64, + borderRadius: const BorderRadius.all(Radius.circular(20)), + borderGradient: const LinearGradient( + begin: AlignmentDirectional.topStart, + end: AlignmentDirectional.bottomEnd, + colors: [ + Color(0XFFFFD66E), + Color(0XFFD28F18), + ] + ), + gradient: const RadialGradient( + radius: 5, + center: Alignment(-0.5, 0), + colors: [ + Color(0xFFF6BA0C), + Color(0xFFCD8402), + ], + ), + child: GradientText( + text: title, + fontSize: 22, + color: const Color(0xFFF5D69F), + offset: const Offset(0, 1.04), + blurRadius: 0.52, + shadowColor: const Color(0xFFC48F30), + ), + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/widgets/battle_league_tab_bar.dart b/lib/features/battle_league/presentation/ui/widgets/battle_league_tab_bar.dart new file mode 100644 index 0000000..748254e --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/battle_league_tab_bar.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; + +class BattleLeagueTabBar extends StatelessWidget { + const BattleLeagueTabBar({ + super.key, + required this.controller, + required this.tabs, + }); + + final TabController controller; + final List tabs; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(3), + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(MySpaces.s10)), + color: Color(0XFF310D6F), + ), + child: TabBar( + controller: controller, + tabs: tabs.map((e) => Tab(text: e)).toList(), + indicator: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(MySpaces.s8)), + color: Color(0XFF897AB8), + ), + indicatorSize: TabBarIndicatorSize.tab, + labelColor: context.primaryColor, + unselectedLabelColor: const Color(0XFF897AB8), + labelStyle: Lexend.semiBold.copyWith(fontSize: 14), + dividerHeight: 0, + ), + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/widgets/filter_ranking_button.dart b/lib/features/battle_league/presentation/ui/widgets/filter_ranking_button.dart new file mode 100644 index 0000000..3d853f6 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/filter_ranking_button.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_colors.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/widgets/container/my_container.dart'; + +class FilterRankingButton extends StatelessWidget { + const FilterRankingButton({ + super.key, + this.onTap, + this.title, + this.select = false, + }); + + final VoidCallback? onTap; + final String? title; + final bool select; + + @override + Widget build(BuildContext context) { + return MyContainer( + onTap: select ? null : onTap, + padding: const EdgeInsets.symmetric(vertical: MySpaces.s16), + borderRadius: const BorderRadius.all(Radius.circular(7)), + color: select ? null : MyColors.black.withValues(alpha: 0.2), + gradient: select + ? const LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFFA672FF), Color(0XFF5B1DC3)], + ) + : null, + child: Text( + title ?? '', + style: Lexend.semiBold.copyWith( + fontSize: 12, + color: select ? MyColors.white : const Color(0XFFBCA1EA), + ), + ), + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/widgets/my_ranking_widget.dart b/lib/features/battle_league/presentation/ui/widgets/my_ranking_widget.dart new file mode 100644 index 0000000..7cbb774 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/my_ranking_widget.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +class MyRankingWidget extends StatelessWidget { + const MyRankingWidget({super.key}); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 48, + child: Row( + children: [ + Text('1', style: Lexend.extraBold.copyWith(fontSize: 12)), + MySpaces.s20.gapWidth, + const MyImage(asset: MyAssets.sampleAvatar, size: MySpaces.s20), + MySpaces.s6.gapWidth, + Expanded( + child: Text( + 'Amirreza', + style: Lexend.medium.copyWith(fontSize: 12), + ), + ), + MySpaces.s6.gapWidth, + const MyImage(asset: MyAssets.iconRank), + MySpaces.s6.gapWidth, + Text('1234', style: Lexend.black.copyWith(fontSize: 12)), + ], + ), + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/widgets/ranking_region.dart b/lib/features/battle_league/presentation/ui/widgets/ranking_region.dart new file mode 100644 index 0000000..8099757 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/ranking_region.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/my_localization.dart'; + +class RankingRegion extends StatelessWidget { + const RankingRegion({super.key}); + + @override + Widget build(BuildContext context) { + return Row( + spacing: MySpaces.s2, + children: [ + const Icon( + Icons.location_on_rounded, + size: MySpaces.s18, + color: Color(0xFF8249E2), + ), + Text.rich( + style: Lexend.medium.copyWith(fontSize: 12), + TextSpan( + text: '${context.translate.region}: ', + style: const TextStyle(color: Color(0xFF8249E2)), + children: [ + const TextSpan( + text: 'Iran - Tehran', + style: TextStyle(color: Color(0xFFBCA1EA)), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/widgets/ranking_scrollbar.dart b/lib/features/battle_league/presentation/ui/widgets/ranking_scrollbar.dart new file mode 100644 index 0000000..70577f5 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/ranking_scrollbar.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; + +class RankingScrollbar extends StatelessWidget { + const RankingScrollbar({ + super.key, + required this.child, + required this.scrollController, + }); + + final Widget child; + final ScrollController scrollController; + + @override + Widget build(BuildContext context) { + return RawScrollbar( + controller: scrollController, + thumbVisibility: true, + thumbColor: const Color(0XFF935BE0), + trackColor: const Color(0XFF541E9E), + trackRadius: const Radius.circular(10), + radius: const Radius.circular(10), + thickness: 3, + crossAxisMargin: MySpaces.s0, + trackVisibility: true, + child: child, + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/widgets/ranking_time.dart b/lib/features/battle_league/presentation/ui/widgets/ranking_time.dart new file mode 100644 index 0000000..a10faad --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/ranking_time.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/container/my_container.dart'; + +class RankingTime extends StatelessWidget { + const RankingTime({ + super.key, + required this.filterTitles, + required this.selectedIndex, + }); + + final List filterTitles; + final int selectedIndex; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text( + '1ST ${filterTitles[selectedIndex]}', + style: Lexend.black.copyWith( + fontSize: 14, + ), + ), + MySpaces.s8.gapWidth, + Text( + '(May 2024)', + style: Lexend.medium.copyWith( + fontSize: 10, + ), + ), + const Spacer(), + MyContainer( + height: MySpaces.s32, + width: MySpaces.s32, + borderRadius: const BorderRadius.all(Radius.circular(7)), + color: const Color(0XFF5210AC), + child: Icon( + Icons.arrow_back_ios_rounded, + color: context.primaryColor, + size: MySpaces.s18, + ), + ), + MySpaces.s10.gapWidth, + MyContainer( + height: MySpaces.s32, + width: MySpaces.s32, + borderRadius: const BorderRadius.all(Radius.circular(7)), + color: const Color(0XFF5210AC), + child: Icon( + Icons.arrow_forward_ios_rounded, + color: context.primaryColor, + size: MySpaces.s18, + ), + ) + ], + ); + } +} \ No newline at end of file diff --git a/lib/features/battle_league/presentation/ui/widgets/ranking_widget.dart b/lib/features/battle_league/presentation/ui/widgets/ranking_widget.dart new file mode 100644 index 0000000..e6f7c32 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/ranking_widget.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_assets.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_colors.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; + +class RankingWidget extends StatelessWidget { + const RankingWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + height: 48, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(MySpaces.s10)), + color: MyColors.black.withValues(alpha: 0.2), + ), + child: Row( + children: [ + MySpaces.s10.gapWidth, + Text('1', style: Lexend.extraBold.copyWith(fontSize: 12)), + MySpaces.s20.gapWidth, + const MyImage(asset: MyAssets.sampleAvatar, size: MySpaces.s20), + MySpaces.s6.gapWidth, + Expanded( + child: Text( + 'Amirreza', + style: Lexend.medium.copyWith(fontSize: 12), + ), + ), + MySpaces.s6.gapWidth, + const MyImage(asset: MyAssets.iconRank), + MySpaces.s6.gapWidth, + Text('1234', style: Lexend.black.copyWith(fontSize: 12)), + MySpaces.s30.gapWidth, + ], + ), + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/widgets/regional_ranking.dart b/lib/features/battle_league/presentation/ui/widgets/regional_ranking.dart new file mode 100644 index 0000000..c34f63e --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/regional_ranking.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/utils/my_localization.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/filter_ranking_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/my_ranking_widget.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/ranking_region.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/ranking_scrollbar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/ranking_widget.dart'; + +class RegionalRanking extends StatefulWidget { + const RegionalRanking({super.key}); + + @override + State createState() => _RegionalRankingState(); +} + +class _RegionalRankingState extends State { + late final List filterTitles; + int selectedIndex = 0; + final ScrollController scrollController = ScrollController(); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + filterTitles = [ + context.translate.country, + context.translate.city, + ]; + } + + @override + void dispose() { + scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only( + top: MySpaces.s12, + left: MySpaces.s12, + right: MySpaces.s12, + ), + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(MySpaces.s10)), + color: Color(0XFF310D6F), + ), + child: Column( + children: [ + Row( + spacing: MySpaces.s10, + children: List.generate( + filterTitles.length, + (index) => Expanded( + child: FilterRankingButton( + onTap: () { + setState(() { + selectedIndex = index; + }); + }, + title: filterTitles[index], + select: index == selectedIndex, + ), + ), + ), + ), + MySpaces.s22.gapHeight, + const RankingRegion(), + MySpaces.s12.gapHeight, + Expanded( + child: RankingScrollbar( + scrollController: scrollController, + child: ListView.separated( + controller: scrollController, + itemCount: 10, + padding: const EdgeInsetsDirectional.only(end: MySpaces.s14), + itemBuilder: (context, index) => const RankingWidget(), + separatorBuilder: (context, index) => MySpaces.s10.gapHeight, + ), + ), + ), + const MyRankingWidget(), + ], + ), + ); + } +} + + diff --git a/lib/features/battle_league/presentation/ui/widgets/time_ranking.dart b/lib/features/battle_league/presentation/ui/widgets/time_ranking.dart new file mode 100644 index 0000000..dbaf45b --- /dev/null +++ b/lib/features/battle_league/presentation/ui/widgets/time_ranking.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; +import 'package:shia_game_flutter/core/utils/gap.dart'; +import 'package:shia_game_flutter/core/utils/my_localization.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/filter_ranking_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/my_ranking_widget.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/ranking_scrollbar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/ranking_time.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/widgets/ranking_widget.dart'; + +class TimeRanking extends StatefulWidget { + const TimeRanking({super.key}); + + @override + State createState() => _TimeRankingState(); +} + +class _TimeRankingState extends State { + late final List filterTitles; + int selectedIndex = 0; + final ScrollController scrollController = ScrollController(); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + filterTitles = [ + context.translate.all_time, + context.translate.month, + context.translate.week, + ]; + } + + @override + void dispose() { + super.dispose(); + scrollController.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only( + top: MySpaces.s12, + left: MySpaces.s12, + right: MySpaces.s12, + ), + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(MySpaces.s10)), + color: Color(0XFF310D6F), + ), + child: Column( + children: [ + Row( + spacing: MySpaces.s10, + children: List.generate( + filterTitles.length, + (index) => Expanded( + child: FilterRankingButton( + onTap: () { + setState(() { + selectedIndex = index; + }); + }, + title: filterTitles[index], + select: index == selectedIndex, + ), + ), + ), + ), + MySpaces.s22.gapHeight, + if(selectedIndex != 0) ...{ + RankingTime( + filterTitles: filterTitles, + selectedIndex: selectedIndex, + ), + MySpaces.s12.gapHeight, + }, + Expanded( + child: RankingScrollbar( + scrollController: scrollController, + child: ListView.separated( + controller: scrollController, + itemCount: 10, + padding: const EdgeInsetsDirectional.only(end: MySpaces.s14), + itemBuilder: (context, index) => const RankingWidget(), + separatorBuilder: (context, index) => MySpaces.s10.gapHeight, + ), + ), + ), + const MyRankingWidget(), + ], + ), + ); + } +} diff --git a/lib/features/master/presentation/ui/master_page.dart b/lib/features/master/presentation/ui/master_page.dart index d47546c..79786e2 100644 --- a/lib/features/master/presentation/ui/master_page.dart +++ b/lib/features/master/presentation/ui/master_page.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:shia_game_flutter/core/routers/my_routes.dart'; -import 'package:shia_game_flutter/core/widgets/app_bar/master_app_bar.dart'; +import 'package:shia_game_flutter/core/widgets/app_bar/styles/master_app_bar.dart'; import 'package:shia_game_flutter/core/widgets/bottom_nav_bar/bottom_nav_bar.dart'; import 'package:shia_game_flutter/features/master/presentation/controller/master_controller.dart'; import 'package:get/get.dart'; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f761f5f..1363b7c 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -28,5 +28,13 @@ "second_place": "Second Place", "third_place": "Third Place", "week": "Week", - "do_not_have_award": "Don't Have Award" + "month": "Month", + "all_time": "All Time", + "do_not_have_award": "Don't Have Award", + "time_ranking": "Time Ranking", + "regional_ranking": "Regional Ranking", + "play_now": "Play Now", + "country": "Country", + "city": "City", + "region": "Region" } \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index a9d3172..4076f4a 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -262,11 +262,59 @@ abstract class AppLocalizations { /// **'Week'** String get week; + /// No description provided for @month. + /// + /// In en, this message translates to: + /// **'Month'** + String get month; + + /// No description provided for @all_time. + /// + /// In en, this message translates to: + /// **'All Time'** + String get all_time; + /// No description provided for @do_not_have_award. /// /// In en, this message translates to: /// **'Don\'t Have Award'** String get do_not_have_award; + + /// No description provided for @time_ranking. + /// + /// In en, this message translates to: + /// **'Time Ranking'** + String get time_ranking; + + /// No description provided for @regional_ranking. + /// + /// In en, this message translates to: + /// **'Regional Ranking'** + String get regional_ranking; + + /// No description provided for @play_now. + /// + /// In en, this message translates to: + /// **'Play Now'** + String get play_now; + + /// No description provided for @country. + /// + /// In en, this message translates to: + /// **'Country'** + String get country; + + /// No description provided for @city. + /// + /// In en, this message translates to: + /// **'City'** + String get city; + + /// No description provided for @region. + /// + /// In en, this message translates to: + /// **'Region'** + String get region; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 23f7712..0b5f8e8 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -92,6 +92,30 @@ class AppLocalizationsEn extends AppLocalizations { @override String get week => 'Week'; + @override + String get month => 'Month'; + + @override + String get all_time => 'All Time'; + @override String get do_not_have_award => 'Don\'t Have Award'; + + @override + String get time_ranking => 'Time Ranking'; + + @override + String get regional_ranking => 'Regional Ranking'; + + @override + String get play_now => 'Play Now'; + + @override + String get country => 'Country'; + + @override + String get city => 'City'; + + @override + String get region => 'Region'; } diff --git a/lib/main.dart b/lib/main.dart index 98bea17..2939bb2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -31,7 +31,7 @@ class MainApp extends StatelessWidget { fallbackLocale: const Locale('en', 'US'), supportedLocales: const [Locale('en', 'US')], getPages: appPages, - initialRoute: Routes.masterPage, + initialRoute: Routes.battleLeaguePage, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/pubspec.lock b/pubspec.lock index fc3519b..88903b8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -73,6 +73,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + draggable_scrollbar: + dependency: "direct main" + description: + name: draggable_scrollbar + sha256: a906e27fc1ee056e2942d66989dd0cb5b70a361e7d44af566cfa1b584054eac3 + url: "https://pub.dev" + source: hosted + version: "0.1.0" equatable: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index a55a011..0852b32 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,6 +8,7 @@ environment: dependencies: dio: ^5.9.0 + draggable_scrollbar: ^0.1.0 equatable: ^2.0.7 flutter: sdk: flutter -- 2.30.2