diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 52b5592..9c073b4 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -37,6 +37,22 @@ android { signingConfig = signingConfigs.getByName("debug") } } + + applicationVariants.all { + val variant = this + variant.outputs.all { + val output = this + // Get the architecture (ABI) for the current output. Note: Flutter often uses 'armeabi-v7a', 'arm64-v8a', etc. + val abi = output.filters.find { it.filterType == "ABI" }?.identifier?.replace("armeabi-", "") ?: "" + + // Make sure we are dealing with an APK output + if (output is com.android.build.gradle.internal.api.ApkVariantOutputImpl) { + // Append the ABI to the filename, with a hyphen if it exists + val abiSuffix = if (abi.isNotEmpty()) "-$abi" else "" + output.outputFileName = "ShiaMind v${variant.versionName}+${variant.versionCode}${abiSuffix}.apk" + } + } + } } flutter { diff --git a/lib/core/constants/my_api.dart b/lib/core/constants/my_api.dart index bafa090..1db239c 100644 --- a/lib/core/constants/my_api.dart +++ b/lib/core/constants/my_api.dart @@ -7,12 +7,22 @@ class MyApi { static const String contentType = 'application/json'; static const String defaultError = 'An unexpected error has occurred.'; - static const String baseUrl = 'https://shiamind.newhorizonco.uk/backend/api'; + static const String baseUrl = 'https://shiamind.newhorizonco.uk'; + + /// Main Api + static const String backend = '/backend/api'; + static const String realTime = '/realtime/api'; /// Player Auth - static const String guestToken = '/player/guest-token/'; - static const String centrifugoToken = '/player/centrifugo-connect/'; + static const String guestToken = '$backend/player/guest-token/'; + static const String centrifugoToken = '$backend/player/centrifugo-connect/'; /// Quiz - static const String topics = '/quiz/topics/'; + static const String topics = '$backend/quiz/topics/'; + static const String clock = '$realTime/sync/clock'; + static const String matchMaking = '$realTime/matchmaking/join'; + + + /// WebSocketUrls + static const String webSocketUrl = 'wss://centrifugo.newhorizonco.uk/connection/websocket'; } diff --git a/lib/core/params/battle_league_params.dart b/lib/core/params/battle_league_params.dart deleted file mode 100644 index bd495e0..0000000 --- a/lib/core/params/battle_league_params.dart +++ /dev/null @@ -1,5 +0,0 @@ -class BattleLeagueParams { - int? id; - - BattleLeagueParams({this.id}); -} diff --git a/lib/core/params/bl_params.dart b/lib/core/params/bl_params.dart new file mode 100644 index 0000000..ad8a1a8 --- /dev/null +++ b/lib/core/params/bl_params.dart @@ -0,0 +1,14 @@ +class BlParams { + List? chooseTopics; + + BlParams({this.chooseTopics}); + + Map get toCockJson => { + 'client_time': DateTime.now().millisecondsSinceEpoch, + }; + + Map get toMatchMakingJson => { + 'skill_level': 0, + if (chooseTopics?.isNotEmpty ?? false) 'topic_ids': chooseTopics, + }; +} diff --git a/lib/core/routers/my_routes.dart b/lib/core/routers/my_routes.dart index e3dfcf1..97521d9 100644 --- a/lib/core/routers/my_routes.dart +++ b/lib/core/routers/my_routes.dart @@ -1,12 +1,12 @@ import 'package:shia_game_flutter/features/awards/presentation/binding/awards_binding.dart'; import 'package:shia_game_flutter/features/awards/presentation/ui/awards_page.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/binding/battle_league_binding.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/battle_league_finding_page.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/battle_league_founded_page.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/battle_league_page.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/battle_league_topic_page.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/presentation/binding/bl_question_binding.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/presentation/ui/bl_question_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/first_part/battle_league_finding_page.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/battle_league_founded_page.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/battle_league_page.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/battle_league_topic_page.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/second_part/bl_question_page.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/second_part/battle_league_result_page.dart'; import 'package:shia_game_flutter/features/home/presentation/binding/home_binding.dart'; import 'package:shia_game_flutter/features/home/presentation/pages/home_page.dart'; import 'package:shia_game_flutter/features/intro/presentation/binding/intro_binding.dart'; @@ -40,6 +40,7 @@ class Routes { static const String battleLeagueFindingPage = '/battle_league_finding_page'; static const String battleLeagueFoundedPage = '/battle_league_founded_page'; static const String battleLeagueQuestionPage = '/battle_league_question_page'; + static const String battleLeagueResultPage = '/battle_league_result_page'; } final List appPages = [ @@ -103,6 +104,11 @@ final List appPages = [ GetPage( name: Routes.battleLeagueQuestionPage, page: () => const BLQuestionPage(), - binding: BLQuestionBinding(), + binding: BattleLeagueBinding(), + ), + GetPage( + name: Routes.battleLeagueResultPage, + page: () => const BattleLeagueResultPage(), + binding: BattleLeagueBinding(), ), ]; diff --git a/lib/core/services/web_socket_service.dart b/lib/core/services/web_socket_service.dart new file mode 100644 index 0000000..d7a7e3d --- /dev/null +++ b/lib/core/services/web_socket_service.dart @@ -0,0 +1,176 @@ +import 'dart:convert'; + +import 'package:centrifuge/centrifuge.dart'; +import 'package:flutter/foundation.dart'; + +class WebSocketService { + final Client _client; + late final Subscription _subscription; + + WebSocketService(this._client) { + _attachListeners(); + } + + /// ------- Connection ------- + Future connect() async { + try { + await _client.connect(); + } catch (e) { + rethrow; + } + } + + void _attachListeners() { + _client.connecting.listen((event) { + if (kDebugMode) { + print('Client Connection: $event'); + } + }); + + _client.connected.listen((event) { + if (kDebugMode) { + print('Client Connected: $event'); + } + }); + + _client.disconnected.listen((event) { + if (kDebugMode) { + print('Client Disconnected: $event'); + } + }); + + _client.message.listen((event) { + if (kDebugMode) { + print('Client Message: $event'); + } + }); + + _client.error.listen((event) { + if (kDebugMode) { + print('Client Error: $event'); + } + }); + + _client.join.listen((event) { + if (kDebugMode) { + print('Client Join: $event'); + } + }); + + _client.leave.listen((event) { + if (kDebugMode) { + print('Client Leave: $event'); + } + }); + + _client.publication.listen((event) { + if (kDebugMode) { + print('Client Publication: $event'); + } + }); + } + + Stream get clientConnecting => _client.connecting; + + Stream get clientConnected => _client.connected; + + Stream get clientDisconnected => _client.disconnected; + + Stream get clientPublication => _client.publication; + + Future disconnect() async { + try { + await _client.disconnect(); + } catch (e) { + rethrow; + } + } + + Future sendRpc({ + required String method, + required Map data, + }) async { + if (_client.state != State.connected) { + throw Exception('Websocket Is NOT Connected'); + } + try { + final RPCResult result = await _client.rpc(method, utf8.encode(json.encode(data))); + if (kDebugMode) { + print('RPC sent successfully. Result: $result'); + } + return result; + } catch (e) { + if (kDebugMode) { + print('Error sending RPC: $e'); + } + rethrow; + } + } + + /// ------- Connection ------- + Future subscribe({required String channel}) async { + try { + _subscription = _client.newSubscription(channel); + _attachSubscribeListeners(); + await _subscription.subscribe(); + } catch (e) { + rethrow; + } + } + + void _attachSubscribeListeners() { + _subscription.error.listen((event) { + if (kDebugMode) { + print('Subscribe Error: $event'); + } + }); + + _subscription.join.listen((event) { + if (kDebugMode) { + print('Subscribe Join: $event'); + } + }); + + _subscription.leave.listen((event) { + if (kDebugMode) { + print('Subscribe Leave: $event'); + } + }); + + _subscription.publication.listen((event) { + if (kDebugMode) { + print('Subscribe Publication: $event'); + } + }); + + _subscription.subscribing.listen((event) { + if (kDebugMode) { + print('Subscribe Subscribing: $event'); + } + }); + + _subscription.subscribed.listen((event) { + if (kDebugMode) { + print('Subscribe Subscribed: $event'); + } + }); + + _subscription.unsubscribed.listen((event) { + if (kDebugMode) { + print('Subscribe Unsubscribed: $event'); + } + }); + } + + Stream get subscribeJoin => _subscription.join; + + Stream get subscribePublication => _subscription.publication; + + Future unSubscribe() async { + try { + await _subscription.unsubscribe(); + } catch (e) { + rethrow; + } + } +} 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..ab0d6fc --- /dev/null +++ b/lib/features/battle_league/data/datasource/battle_league_datasource.dart @@ -0,0 +1,71 @@ +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/bl_params.dart'; +import 'package:shia_game_flutter/core/response/base_response.dart'; +import 'package:shia_game_flutter/features/battle_league/data/model/clock_model.dart'; +import 'package:shia_game_flutter/features/battle_league/data/model/match_making_model.dart'; +import 'package:shia_game_flutter/features/battle_league/data/model/player_token_model.dart'; +import 'package:shia_game_flutter/features/battle_league/data/model/topics_model.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/clock_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/match_making_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/player_token_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/topics_entity.dart'; + +abstract class IBattleLeagueDatasource { + Future getPlayerToken({required BlParams params}); + Future> getTopics({required BlParams params}); + Future getClock({required BlParams params}); + Future matchMaking({required BlParams params}); +} + +class BattleLeagueDatasourceImpl implements IBattleLeagueDatasource { + final IHttpRequest httpRequest; + + const BattleLeagueDatasourceImpl(this.httpRequest); + + @override + Future getPlayerToken({required BlParams params}) async { + final response = await httpRequest.post(path: MyApi.centrifugoToken); + + return BaseResponse.getData( + response, + (json) => PlayerTokenModel.fromJson(json), + ); + } + + @override + Future> getTopics({required BlParams params}) async { + final response = await httpRequest.get(path: MyApi.topics); + + return BaseResponse.getDataList( + response?['results'], + (json) => TopicsModel.fromJson(json), + ); + } + + @override + Future getClock({required BlParams params}) async { + final response = await httpRequest.post( + path: MyApi.clock, + data: params.toCockJson, + ); + + return BaseResponse.getData( + response, + (json) => ClockModel.fromJson(json), + ); + } + + @override + Future matchMaking({required BlParams params}) async { + final response = await httpRequest.post( + path: MyApi.matchMaking, + data: params.toMatchMakingJson, + ); + + return BaseResponse.getData( + response, + (json) => MatchMakingModel.fromJson(json), + ); + } +} diff --git a/lib/features/battle_league/data/model/answer_model.dart b/lib/features/battle_league/data/model/answer_model.dart new file mode 100644 index 0000000..d42352d --- /dev/null +++ b/lib/features/battle_league/data/model/answer_model.dart @@ -0,0 +1,9 @@ +import 'package:shia_game_flutter/features/battle_league/domain/entity/answer_entity.dart'; + +class AnswerModel extends AnswerEntity { + const AnswerModel({super.id, super.text}); + + factory AnswerModel.fromJson(Map json) { + return AnswerModel(id: json['id'], text: json['text']); + } +} diff --git a/lib/features/battle_league/data/model/clock_model.dart b/lib/features/battle_league/data/model/clock_model.dart new file mode 100644 index 0000000..be39667 --- /dev/null +++ b/lib/features/battle_league/data/model/clock_model.dart @@ -0,0 +1,17 @@ +import 'package:shia_game_flutter/features/battle_league/domain/entity/clock_entity.dart'; + +class ClockModel extends ClockEntity { + const ClockModel({ + super.serverTime, + super.clientTime, + super.serverReceiveTime, + }); + + factory ClockModel.fromJson(Map json) { + return ClockModel( + clientTime: json['client_time'], + serverTime: json['server_time'], + serverReceiveTime: json['server_receive_time'], + ); + } +} diff --git a/lib/features/battle_league/data/model/match_making_model.dart b/lib/features/battle_league/data/model/match_making_model.dart new file mode 100644 index 0000000..0acec68 --- /dev/null +++ b/lib/features/battle_league/data/model/match_making_model.dart @@ -0,0 +1,23 @@ +import 'package:shia_game_flutter/features/battle_league/domain/entity/match_making_entity.dart'; + +class MatchMakingModel extends MatchMakingEntity { + const MatchMakingModel({ + super.estimatedWaitTime, + super.message, + super.position, + super.queueSize, + super.selectedTopics, + super.status, + }); + + factory MatchMakingModel.fromJson(Map json) { + return MatchMakingModel( + estimatedWaitTime: json['estimated_wait_time'], + message: json['message'], + position: json['position'], + queueSize: json['queue_size'], + selectedTopics: json['selected_topics']?.map((e) => int.parse('$e')).toList(), + status: json['status'], + ); + } +} diff --git a/lib/features/battle_league/data/model/player_token_model.dart b/lib/features/battle_league/data/model/player_token_model.dart new file mode 100644 index 0000000..abe3dff --- /dev/null +++ b/lib/features/battle_league/data/model/player_token_model.dart @@ -0,0 +1,13 @@ +import 'package:shia_game_flutter/features/battle_league/domain/entity/player_token_entity.dart'; + +class PlayerTokenModel extends PlayerTokenEntity { + const PlayerTokenModel({super.token, super.user, super.channel}); + + factory PlayerTokenModel.fromJson(Map json) { + return PlayerTokenModel( + token: json['token'], + user: json['user'], + channel: json['channel'], + ); + } +} diff --git a/lib/features/battle_league/data/model/question_model.dart b/lib/features/battle_league/data/model/question_model.dart new file mode 100644 index 0000000..25d4f6c --- /dev/null +++ b/lib/features/battle_league/data/model/question_model.dart @@ -0,0 +1,18 @@ +import 'package:shia_game_flutter/features/battle_league/data/model/answer_model.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/answer_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/question_entity.dart'; + +class QuestionModel extends QuestionEntity { + const QuestionModel({super.id, super.text, super.options, super.timeLimit}); + + factory QuestionModel.fromJson(Map json) { + return QuestionModel( + id: json['id'], + text: json['text'], + options: json['options'] + ?.map((e) => AnswerModel.fromJson(e)) + .toList(), + timeLimit: json['time_limit'], + ); + } +} diff --git a/lib/features/battle_league/first_part/data/model/topics_model.dart b/lib/features/battle_league/data/model/topics_model.dart similarity index 90% rename from lib/features/battle_league/first_part/data/model/topics_model.dart rename to lib/features/battle_league/data/model/topics_model.dart index 08c604c..987190f 100644 --- a/lib/features/battle_league/first_part/data/model/topics_model.dart +++ b/lib/features/battle_league/data/model/topics_model.dart @@ -1,4 +1,4 @@ -import 'package:shia_game_flutter/features/battle_league/first_part/domain/entity/topics_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/topics_entity.dart'; class TopicsModel extends TopicsEntity { const TopicsModel({ 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..c709bd9 --- /dev/null +++ b/lib/features/battle_league/data/repository_impl/battle_league_repository_impl.dart @@ -0,0 +1,94 @@ +import 'package:flutter/foundation.dart'; +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/bl_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/clock_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/match_making_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/player_token_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/topics_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> getPlayerToken({ + required BlParams params, + }) async { + try { + final PlayerTokenEntity response = await datasource.getPlayerToken( + 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')); + } + } + } + + @override + Future, MyException>> getTopics({ + required BlParams params, + }) async { + try { + final List response = await datasource.getTopics( + 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')); + } + } + } + + @override + Future> getClock({ + required BlParams params, + }) async { + try { + final ClockEntity response = await datasource.getClock(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')); + } + } + } + + @override + Future> matchMaking({ + required BlParams params, + }) async { + try { + final MatchMakingEntity response = await datasource.matchMaking( + 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/answer_entity.dart b/lib/features/battle_league/domain/entity/answer_entity.dart new file mode 100644 index 0000000..7c4d773 --- /dev/null +++ b/lib/features/battle_league/domain/entity/answer_entity.dart @@ -0,0 +1,11 @@ +import 'package:equatable/equatable.dart'; + +class AnswerEntity extends Equatable { + final int? id; + final String? text; + + const AnswerEntity({this.id, this.text}); + + @override + List get props => [id, text]; +} diff --git a/lib/features/battle_league/domain/entity/clock_entity.dart b/lib/features/battle_league/domain/entity/clock_entity.dart new file mode 100644 index 0000000..bfb2c8e --- /dev/null +++ b/lib/features/battle_league/domain/entity/clock_entity.dart @@ -0,0 +1,12 @@ +import 'package:equatable/equatable.dart'; + +class ClockEntity extends Equatable { + final double? serverTime; + final double? clientTime; + final double? serverReceiveTime; + + const ClockEntity({this.serverTime, this.clientTime, this.serverReceiveTime}); + + @override + List get props => [serverTime, clientTime, serverReceiveTime]; +} diff --git a/lib/features/battle_league/domain/entity/match_making_entity.dart b/lib/features/battle_league/domain/entity/match_making_entity.dart new file mode 100644 index 0000000..bfeb158 --- /dev/null +++ b/lib/features/battle_league/domain/entity/match_making_entity.dart @@ -0,0 +1,29 @@ +import 'package:equatable/equatable.dart'; + +class MatchMakingEntity extends Equatable { + final int? estimatedWaitTime; + final String? message; + final int? position; + final int? queueSize; + final List? selectedTopics; + final String? status; + + const MatchMakingEntity({ + this.estimatedWaitTime, + this.message, + this.position, + this.queueSize, + this.selectedTopics, + this.status, + }); + + @override + List get props => [ + estimatedWaitTime, + message, + position, + queueSize, + selectedTopics, + status, + ]; +} diff --git a/lib/features/battle_league/domain/entity/player_token_entity.dart b/lib/features/battle_league/domain/entity/player_token_entity.dart new file mode 100644 index 0000000..39fbb40 --- /dev/null +++ b/lib/features/battle_league/domain/entity/player_token_entity.dart @@ -0,0 +1,12 @@ +import 'package:equatable/equatable.dart'; + +class PlayerTokenEntity extends Equatable { + final String? token; + final String? user; + final String? channel; + + const PlayerTokenEntity({this.token, this.user, this.channel}); + + @override + List get props => [token, user, channel]; +} diff --git a/lib/features/battle_league/domain/entity/question_entity.dart b/lib/features/battle_league/domain/entity/question_entity.dart new file mode 100644 index 0000000..efaa6b2 --- /dev/null +++ b/lib/features/battle_league/domain/entity/question_entity.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/answer_entity.dart'; + +class QuestionEntity extends Equatable { + final int? id; + final String? text; + final List? options; + final int? timeLimit; + + const QuestionEntity({this.id, this.text, this.options, this.timeLimit}); + + @override + List get props => [id, text, options, timeLimit]; +} diff --git a/lib/features/battle_league/first_part/domain/entity/topics_entity.dart b/lib/features/battle_league/domain/entity/topics_entity.dart similarity index 100% rename from lib/features/battle_league/first_part/domain/entity/topics_entity.dart rename to lib/features/battle_league/domain/entity/topics_entity.dart 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..a3cc3f1 --- /dev/null +++ b/lib/features/battle_league/domain/repository/battle_league_repository.dart @@ -0,0 +1,22 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/bl_params.dart'; +import 'package:shia_game_flutter/core/utils/data_state.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/clock_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/match_making_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/player_token_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/topics_entity.dart'; + +abstract class IBattleLeagueRepository { + Future> getPlayerToken({ + required BlParams params, + }); + Future, MyException>> getTopics({ + required BlParams params, + }); + Future> getClock({ + required BlParams params, + }); + Future> matchMaking({ + required BlParams params, + }); +} diff --git a/lib/features/battle_league/domain/usecases/get_clock_usecase.dart b/lib/features/battle_league/domain/usecases/get_clock_usecase.dart new file mode 100644 index 0000000..618e35a --- /dev/null +++ b/lib/features/battle_league/domain/usecases/get_clock_usecase.dart @@ -0,0 +1,17 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/bl_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/clock_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/repository/battle_league_repository.dart'; + +class GetClockUseCase implements UseCase { + final IBattleLeagueRepository repository; + + const GetClockUseCase(this.repository); + + @override + Future> call(BlParams params) { + return repository.getClock(params: params); + } +} diff --git a/lib/features/battle_league/domain/usecases/get_player_token_usecase.dart b/lib/features/battle_league/domain/usecases/get_player_token_usecase.dart new file mode 100644 index 0000000..1aaeb59 --- /dev/null +++ b/lib/features/battle_league/domain/usecases/get_player_token_usecase.dart @@ -0,0 +1,18 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/bl_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/player_token_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/repository/battle_league_repository.dart'; + +class GetPlayerTokenUseCase + implements UseCase { + final IBattleLeagueRepository repository; + + const GetPlayerTokenUseCase(this.repository); + + @override + Future> call(BlParams params) { + return repository.getPlayerToken(params: params); + } +} diff --git a/lib/features/battle_league/domain/usecases/get_topics_usecase.dart b/lib/features/battle_league/domain/usecases/get_topics_usecase.dart new file mode 100644 index 0000000..079ea4c --- /dev/null +++ b/lib/features/battle_league/domain/usecases/get_topics_usecase.dart @@ -0,0 +1,18 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/bl_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/topics_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/repository/battle_league_repository.dart'; + +class GetTopicsUseCase + implements UseCase, BlParams> { + final IBattleLeagueRepository repository; + + const GetTopicsUseCase(this.repository); + + @override + Future, MyException>> call(BlParams params,) { + return repository.getTopics(params: params); + } +} diff --git a/lib/features/battle_league/domain/usecases/match_making_usecase.dart b/lib/features/battle_league/domain/usecases/match_making_usecase.dart new file mode 100644 index 0000000..1809af5 --- /dev/null +++ b/lib/features/battle_league/domain/usecases/match_making_usecase.dart @@ -0,0 +1,17 @@ +import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; +import 'package:shia_game_flutter/core/params/bl_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/match_making_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/repository/battle_league_repository.dart'; + +class MatchMakingUseCase implements UseCase { + final IBattleLeagueRepository repository; + + const MatchMakingUseCase(this.repository); + + @override + Future> call(BlParams params) { + return repository.matchMaking(params: params); + } +} diff --git a/lib/features/battle_league/first_part/data/datasource/battle_league_datasource.dart b/lib/features/battle_league/first_part/data/datasource/battle_league_datasource.dart deleted file mode 100644 index 719a20e..0000000 --- a/lib/features/battle_league/first_part/data/datasource/battle_league_datasource.dart +++ /dev/null @@ -1,28 +0,0 @@ -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/battle_league_params.dart'; -import 'package:shia_game_flutter/core/response/base_response.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/data/model/topics_model.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/entity/topics_entity.dart'; - -abstract class IBattleLeagueDatasource { - Future> getTopics({required BattleLeagueParams params}); -} - -class BattleLeagueDatasourceImpl implements IBattleLeagueDatasource { - final IHttpRequest httpRequest; - - const BattleLeagueDatasourceImpl(this.httpRequest); - - @override - Future> getTopics({ - required BattleLeagueParams params, - }) async { - final response = await httpRequest.get(path: MyApi.topics); - - return BaseResponse.getDataList( - response?['results'], - (json) => TopicsModel.fromJson(json), - ); - } -} diff --git a/lib/features/battle_league/first_part/data/model/battle_league_model.dart b/lib/features/battle_league/first_part/data/model/battle_league_model.dart deleted file mode 100644 index a0dc921..0000000 --- a/lib/features/battle_league/first_part/data/model/battle_league_model.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:shia_game_flutter/features/battle_league/first_part/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/first_part/data/repository_impl/battle_league_repository_impl.dart b/lib/features/battle_league/first_part/data/repository_impl/battle_league_repository_impl.dart deleted file mode 100644 index 5eea715..0000000 --- a/lib/features/battle_league/first_part/data/repository_impl/battle_league_repository_impl.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; -import 'package:shia_game_flutter/core/params/battle_league_params.dart'; -import 'package:shia_game_flutter/core/utils/data_state.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/data/datasource/battle_league_datasource.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/entity/topics_entity.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/repository/battle_league_repository.dart'; - -class BattleLeagueRepositoryImpl implements IBattleLeagueRepository { - final IBattleLeagueDatasource datasource; - - const BattleLeagueRepositoryImpl(this.datasource); - - @override - Future, MyException>> getTopics({ - required BattleLeagueParams params, - }) async { - try { - final List response = await datasource.getTopics( - 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/first_part/domain/entity/battle_league_entity.dart b/lib/features/battle_league/first_part/domain/entity/battle_league_entity.dart deleted file mode 100644 index d532d4b..0000000 --- a/lib/features/battle_league/first_part/domain/entity/battle_league_entity.dart +++ /dev/null @@ -1,15 +0,0 @@ -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/first_part/domain/repository/battle_league_repository.dart b/lib/features/battle_league/first_part/domain/repository/battle_league_repository.dart deleted file mode 100644 index 1b3a80d..0000000 --- a/lib/features/battle_league/first_part/domain/repository/battle_league_repository.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; -import 'package:shia_game_flutter/core/params/battle_league_params.dart'; -import 'package:shia_game_flutter/core/utils/data_state.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/entity/topics_entity.dart'; - -abstract class IBattleLeagueRepository { - Future, MyException>> getTopics({ - required BattleLeagueParams params, - }); -} diff --git a/lib/features/battle_league/first_part/domain/usecases/get_topics_usecase.dart b/lib/features/battle_league/first_part/domain/usecases/get_topics_usecase.dart deleted file mode 100644 index bb1c4d4..0000000 --- a/lib/features/battle_league/first_part/domain/usecases/get_topics_usecase.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; -import 'package:shia_game_flutter/core/params/battle_league_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/first_part/domain/entity/topics_entity.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/repository/battle_league_repository.dart'; - -class GetTopicsUseCase - implements UseCase, BattleLeagueParams> { - final IBattleLeagueRepository repository; - - const GetTopicsUseCase(this.repository); - - @override - Future, MyException>> call(BattleLeagueParams params,) { - return repository.getTopics(params: params); - } -} diff --git a/lib/features/battle_league/first_part/presentation/controller/battle_league_controller.dart b/lib/features/battle_league/first_part/presentation/controller/battle_league_controller.dart deleted file mode 100644 index b949ff1..0000000 --- a/lib/features/battle_league/first_part/presentation/controller/battle_league_controller.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:shia_game_flutter/core/params/battle_league_params.dart'; -import 'package:shia_game_flutter/core/routers/my_routes.dart'; -import 'package:shia_game_flutter/core/status/base_status.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/entity/topics_entity.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/usecases/get_topics_usecase.dart'; - -class BattleLeagueController extends GetxController - with StateMixin, GetSingleTickerProviderStateMixin { - /// ----- Constructor ----- - BattleLeagueController(this._getTopicsUseCase); - - @override - void onInit() { - super.onInit(); - tabController = TabController(length: 2, vsync: this); - } - - @override - void onClose() { - textEditingController.dispose(); - super.onClose(); - } - - /// ----- UseCases ----- - final GetTopicsUseCase _getTopicsUseCase; - - /// ----- Variables ----- - final BattleLeagueParams battleLeagueParams = BattleLeagueParams(); - final RxList topicList = RxList.empty(); - - /// ------ Controllers ------ - final TextEditingController textEditingController = TextEditingController(); - late final TabController tabController; - - /// ------ Statuses ------ - final Rx getBattleLeagueStatus = Rx(const BaseInit()); - final Rx getTopicsStatus = Rx(const BaseInit()); - - /// ------ Functions ------ - void goToTopicPage() { - getTopics(); - Get.toNamed(Routes.battleLeagueTopicPage); - } - - void goToFindingPage() { - Get.toNamed(Routes.battleLeagueFindingPage); - } - - void goToFoundedPage() { - Get.toNamed(Routes.battleLeagueFoundedPage); - } - - /// ------ Api Calls ------ - Future getTopics() async { - getTopicsStatus.value = const BaseLoading(); - await _getTopicsUseCase(battleLeagueParams).then( - (value) => value.fold( - (data) { - topicList.value = data; - getTopicsStatus.value = const BaseComplete(); - }, - (error) { - getTopicsStatus.value = BaseError(errorMessage: error.errorMessage); - }, - ), - ); - } -} diff --git a/lib/features/battle_league/first_part/presentation/binding/battle_league_binding.dart b/lib/features/battle_league/presentation/binding/battle_league_binding.dart similarity index 56% rename from lib/features/battle_league/first_part/presentation/binding/battle_league_binding.dart rename to lib/features/battle_league/presentation/binding/battle_league_binding.dart index c836af8..19fd27c 100644 --- a/lib/features/battle_league/first_part/presentation/binding/battle_league_binding.dart +++ b/lib/features/battle_league/presentation/binding/battle_league_binding.dart @@ -1,10 +1,15 @@ -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/controller/battle_league_controller.dart'; +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())); + Get.put(BattleLeagueController( + Get.find(), + Get.find(), + Get.find(), + Get.find(), + )); } Future deleteBindings() async { 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..7f51f30 --- /dev/null +++ b/lib/features/battle_league/presentation/controller/battle_league_controller.dart @@ -0,0 +1,280 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:centrifuge/centrifuge.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:shia_game_flutter/core/auth_storage/auth_storage.dart'; +import 'package:shia_game_flutter/core/constants/my_api.dart'; +import 'package:shia_game_flutter/core/params/bl_params.dart'; +import 'package:shia_game_flutter/core/routers/my_routes.dart'; +import 'package:shia_game_flutter/core/services/web_socket_service.dart'; +import 'package:shia_game_flutter/core/status/base_status.dart'; +import 'package:shia_game_flutter/features/battle_league/data/model/question_model.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/player_token_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/question_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/topics_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_clock_usecase.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_player_token_usecase.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_topics_usecase.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/match_making_usecase.dart'; + +class BattleLeagueController extends GetxController + with StateMixin, GetSingleTickerProviderStateMixin { + /// ----- Constructor ----- + BattleLeagueController( + this._getTopicsUseCase, + this._getPlayerTokenUseCase, + this._getClockUseCase, + this._matchMakingUseCase, + ); + + @override + void onInit() { + super.onInit(); + tabController = TabController(length: 2, vsync: this); + // getPlayerToken(); + } + + @override + void onClose() { + textEditingController.dispose(); + _webSocketService.disconnect(); + timer?.cancel(); + timer = null; + super.onClose(); + } + + /// ----- UseCases ----- + final GetTopicsUseCase _getTopicsUseCase; + final GetPlayerTokenUseCase _getPlayerTokenUseCase; + final GetClockUseCase _getClockUseCase; + final MatchMakingUseCase _matchMakingUseCase; + final WebSocketService _webSocketService = WebSocketService( + createClient( + MyApi.webSocketUrl, + ClientConfig( + name: 'Amirreza', + data: utf8.encode(jsonEncode({'player_token': AuthStorage.token})), + ), + ), + ); + + /// ----- Variables ----- + final BlParams blParams = BlParams(); + final RxList topicList = RxList.empty(); + final RxList chooseTopicList = RxList.empty(); + PlayerTokenEntity playerToken = const PlayerTokenEntity(); + final Rx question = Rx(const QuestionEntity()); + int battleId = 0; + final RxInt roundNumber = RxInt(0); + final Rx isCorrect = Rx(null); + final RxInt selectedIndex = RxInt(-1); + final RxInt roundTimer = RxInt(0); + final RxInt myWonNumber = RxInt(0); + final RxInt enemyWonNumber = RxInt(0); + Timer? timer; + String clientID = ''; + String player1ID = ''; + String player1Username = ''; + String player2ID = ''; + String player2Username = ''; + String myId = ''; + String enemyId = ''; + final RxString enemyUsername = RxString(''); + final Rx winnerId = Rx(null); + + /// ------ Controllers ------ + final TextEditingController textEditingController = TextEditingController(); + late final TabController tabController; + + /// ------ Statuses ------ + final Rx getTopicsStatus = Rx(const BaseInit()); + final Rx connectStatus = Rx(const BaseLoading()); + final Rx getClockStatus = Rx(const BaseInit()); + final Rx matchMakingStatus = Rx(const BaseInit()); + + /// ------ Functions ------ + void goToTopicPage() { + getTopics(); + Get.toNamed(Routes.battleLeagueTopicPage); + } + + void goToFindingPage() { + print(AuthStorage.token); + Get.toNamed(Routes.battleLeagueFindingPage); + _webSocketService.connect(); + _webSocketService.clientConnected.listen((event) { + clientID = json.decode(utf8.decode(event.data))['player_id']; + print(clientID); + getClock(); + connectStatus.value = const BaseComplete(); + }); + _webSocketService.clientPublication.listen((event) async { + final String type = json.decode(utf8.decode(event.data))['type']; + + if (type == 'match_found'){ + final String channel = json.decode( + utf8.decode(event.data), + )['battle_channel']; + final String battleId = json.decode(utf8.decode(event.data))['battle_id']; + player1ID = json.decode(utf8.decode(event.data))['player1']['id']; + player1Username = json.decode(utf8.decode(event.data))['player1']['username']; + player2ID = json.decode(utf8.decode(event.data))['player2']['id']; + player2Username = json.decode(utf8.decode(event.data))['player2']['username']; + if (player1ID == clientID) { + myId = player1ID; + enemyId = player2ID; + enemyUsername.value = player2Username; + } else { + myId = player2ID; + enemyId = player1ID; + enemyUsername.value = player1Username; + } + this.battleId = int.parse(battleId); + + await _webSocketService.subscribe(channel: channel); + _webSocketService.subscribeJoin.listen((event) { + Get.offNamed(Routes.battleLeagueQuestionPage); + }); + + _webSocketService.subscribePublication.listen((event) { + selectedIndex.value = -1; + isCorrect.value = null; + final String type = json.decode(utf8.decode(event.data))['type']; + + if (type == 'round_start') { + question.value = QuestionModel.fromJson( + json.decode(utf8.decode(event.data))['question'], + ); + roundNumber.value = json.decode(utf8.decode(event.data))['round_number']; + roundTimer.value = json.decode(utf8.decode(event.data))['duration_seconds']; + timer?.cancel(); + timer = null; + timer = Timer.periodic(const Duration(seconds: 1), (timer) { + roundTimer.value--; + }); + } + + if (type == 'battle_complete'){ + timer?.cancel(); + timer = null; + winnerId.value = json.decode(utf8.decode(event.data))['winner_id']; + Get.offNamed(Routes.battleLeagueResultPage); + } + + if (type == 'question_locked') { + final String lockedBy = json.decode( + utf8.decode(event.data))['locked_by']; + if (lockedBy == enemyId) { + print('rich enemy'); + enemyWonNumber.value = enemyWonNumber.value + 1; + } else { + print('rich myself'); + myWonNumber.value = myWonNumber.value + 1; + } + } + }); + } + }); + } + + Future cancelFinding() async { + Get.back(); + connectStatus.value = const BaseLoading(); + await _webSocketService.unSubscribe(); + _webSocketService.disconnect(); + } + + void chooseTopic(TopicsEntity topic) { + if (chooseTopicList.contains(topic)) { + chooseTopicList.remove(topic); + } else { + if (chooseTopicList.length < 3) { + chooseTopicList.add(topic); + } + } + } + + void choosRandomTopic() { + final List newTopicList = List.from(topicList); + newTopicList.shuffle(); + chooseTopicList.value = newTopicList.take(3).toList(); + } + + Future backToTopicPage() async { + Get.back(); + await _webSocketService.unSubscribe(); + _webSocketService.disconnect(); + } + + void chooseAnswer({required int index}) async { + selectedIndex.value = index; + await _webSocketService.sendRpc( + method: 'battle:submit_answer', + data: { + 'battle_id': battleId, + 'round_number': roundNumber.value, + 'selected_option': index, + 'client_timestamp': DateTime.timestamp().millisecondsSinceEpoch / 1000, + }, + ).then((value) { + isCorrect.value = json.decode(utf8.decode(value.data))['is_correct']; + },); + } + + /// ------ Api Calls ------ + Future getPlayerToken() async { + await _getPlayerTokenUseCase(blParams).then( + (value) => value.fold((data) { + playerToken = data; + _webSocketService.connect(); + }, (error) {}), + ); + } + + Future getTopics() async { + getTopicsStatus.value = const BaseLoading(); + await _getTopicsUseCase(blParams).then( + (value) => value.fold( + (data) { + topicList.value = data; + getTopicsStatus.value = const BaseComplete(); + }, + (error) { + getTopicsStatus.value = BaseError(errorMessage: error.errorMessage); + }, + ), + ); + } + + Future getClock() async { + getClockStatus.value = const BaseLoading(); + await _getClockUseCase(blParams).then( + (value) => value.fold( + (data) { + matchMaking(); + getClockStatus.value = const BaseComplete(); + }, + (error) { + getClockStatus.value = BaseError(errorMessage: error.errorMessage); + }, + ), + ); + } + + Future matchMaking() async { + matchMakingStatus.value = const BaseLoading(); + blParams.chooseTopics = chooseTopicList.map((e) => e.id ?? 0).toList(); + await _matchMakingUseCase(blParams).then( + (value) => value.fold( + (data) { + matchMakingStatus.value = const BaseComplete(); + }, + (error) { + matchMakingStatus.value = BaseError(errorMessage: error.errorMessage); + }, + ), + ); + } +} diff --git a/lib/features/battle_league/first_part/presentation/ui/battle_league_finding_page.dart b/lib/features/battle_league/presentation/ui/first_part/battle_league_finding_page.dart similarity index 59% rename from lib/features/battle_league/first_part/presentation/ui/battle_league_finding_page.dart rename to lib/features/battle_league/presentation/ui/first_part/battle_league_finding_page.dart index 1a35752..4656880 100644 --- a/lib/features/battle_league/first_part/presentation/ui/battle_league_finding_page.dart +++ b/lib/features/battle_league/presentation/ui/first_part/battle_league_finding_page.dart @@ -3,13 +3,14 @@ import 'package:get/get.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_text_style.dart'; +import 'package:shia_game_flutter/core/status/base_status.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/utils/screen_size.dart'; import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/controller/battle_league_controller.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/button/battle_purple_button.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/rank_title.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/first_part/widgets/button/battle_purple_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/rank_title.dart'; class BattleLeagueFindingPage extends GetView { const BattleLeagueFindingPage({super.key}); @@ -46,10 +47,38 @@ class BattleLeagueFindingPage extends GetView { const MyImage(asset: MyAssets.magnifier), Positioned( bottom: 0, - child: Text( - context.translate.finding_player, - style: Lexend.semiBold.copyWith(fontSize: 20), - ), + child: Obx(() { + + if(controller.connectStatus.value is BaseLoading){ + return Text( + 'Connecting To The Server', + style: Lexend.semiBold.copyWith(fontSize: 20), + ); + } + + if(controller.getClockStatus.value is BaseLoading){ + return Text( + 'Syncing Clock Time', + style: Lexend.semiBold.copyWith(fontSize: 20), + ); + } + + if(controller.matchMakingStatus.value is BaseLoading){ + return Text( + context.translate.start_finding, + style: Lexend.semiBold.copyWith(fontSize: 20), + ); + } + + if(controller.matchMakingStatus.value is BaseComplete){ + return Text( + context.translate.finding_player, + style: Lexend.semiBold.copyWith(fontSize: 20), + ); + } + + return const SizedBox.shrink(); + }), ), ], ); @@ -74,7 +103,7 @@ class BattleLeagueFindingPage extends GetView { Widget _startFindingButton(BuildContext context) { return BattlePurpleButton( label: context.translate.stop_finding, - onTap: controller.goToFoundedPage, + onTap: controller.cancelFinding, ); } } diff --git a/lib/features/battle_league/first_part/presentation/ui/battle_league_founded_page.dart b/lib/features/battle_league/presentation/ui/first_part/battle_league_founded_page.dart similarity index 82% rename from lib/features/battle_league/first_part/presentation/ui/battle_league_founded_page.dart rename to lib/features/battle_league/presentation/ui/first_part/battle_league_founded_page.dart index 5a9f4fa..817ff5f 100644 --- a/lib/features/battle_league/first_part/presentation/ui/battle_league_founded_page.dart +++ b/lib/features/battle_league/presentation/ui/first_part/battle_league_founded_page.dart @@ -6,9 +6,9 @@ import 'package:shia_game_flutter/core/utils/gap.dart'; import 'package:shia_game_flutter/core/utils/screen_size.dart'; import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; import 'package:shia_game_flutter/core/widgets/loading/my_linear_loading.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/controller/battle_league_controller.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/founded_page/founded_avatar.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/rank_title.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/first_part/widgets/founded_page/founded_avatar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/rank_title.dart'; class BattleLeagueFoundedPage extends GetView { const BattleLeagueFoundedPage({super.key}); diff --git a/lib/features/battle_league/first_part/presentation/ui/battle_league_page.dart b/lib/features/battle_league/presentation/ui/first_part/battle_league_page.dart similarity index 78% rename from lib/features/battle_league/first_part/presentation/ui/battle_league_page.dart rename to lib/features/battle_league/presentation/ui/first_part/battle_league_page.dart index a409cdc..5fe5198 100644 --- a/lib/features/battle_league/first_part/presentation/ui/battle_league_page.dart +++ b/lib/features/battle_league/presentation/ui/first_part/battle_league_page.dart @@ -6,11 +6,11 @@ import 'package:shia_game_flutter/core/utils/my_localization.dart'; import 'package:shia_game_flutter/core/utils/screen_size.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/first_part/presentation/controller/battle_league_controller.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/button/battle_golden_button.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/battle_league_tab_bar.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/regional_ranking.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/time_ranking.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/first_part/widgets/button/battle_golden_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/battle_league_tab_bar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/regional_ranking.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/time_ranking.dart'; class BattleLeaguePage extends GetView { const BattleLeaguePage({super.key}); diff --git a/lib/features/battle_league/first_part/presentation/ui/battle_league_topic_page.dart b/lib/features/battle_league/presentation/ui/first_part/battle_league_topic_page.dart similarity index 82% rename from lib/features/battle_league/first_part/presentation/ui/battle_league_topic_page.dart rename to lib/features/battle_league/presentation/ui/first_part/battle_league_topic_page.dart index f4d208b..fdd795c 100644 --- a/lib/features/battle_league/first_part/presentation/ui/battle_league_topic_page.dart +++ b/lib/features/battle_league/presentation/ui/first_part/battle_league_topic_page.dart @@ -10,10 +10,10 @@ import 'package:shia_game_flutter/core/utils/screen_size.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/core/widgets/loading/my_loading.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/controller/battle_league_controller.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/button/battle_golden_button.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/button/battle_grey_button.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/topic_page/topic_widget.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/first_part/widgets/button/battle_golden_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/button/battle_grey_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/topic_page/topic_widget.dart'; class BattleLeagueTopicPage extends GetView { const BattleLeagueTopicPage({super.key}); @@ -97,9 +97,12 @@ class BattleLeagueTopicPage extends GetView { alignment: WrapAlignment.center, children: List.generate( controller.topicList.length, - (index) => TopicWidget( - topic: controller.topicList[index], - onTap: () {}, + (index) => Obx( + () => TopicWidget( + onPressed: controller.chooseTopic, + topic: controller.topicList[index], + selected: controller.chooseTopicList.contains(controller.topicList[index]), + ), ), ), ), @@ -113,7 +116,7 @@ class BattleLeagueTopicPage extends GetView { child: BattleGreyButton( label: context.translate.random, image: MyAssets.iconRandom, - onTap: () {}, + onTap: controller.choosRandomTopic, ), ); } diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_golden_button.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_golden_button.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_golden_button.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_golden_button.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_grey_button.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_grey_button.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_grey_button.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_grey_button.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_purple_button.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_purple_button.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_purple_button.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_purple_button.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/founded_page/founded_avatar.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/founded_page/founded_avatar.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/founded_page/founded_avatar.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/founded_page/founded_avatar.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/battle_league_tab_bar.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/battle_league_tab_bar.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/battle_league_tab_bar.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/battle_league_tab_bar.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/filter_ranking_button.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/filter_ranking_button.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/filter_ranking_button.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/filter_ranking_button.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/my_ranking_widget.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/my_ranking_widget.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/my_ranking_widget.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/my_ranking_widget.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_region.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_region.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_region.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_region.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_scrollbar.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_scrollbar.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_scrollbar.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_scrollbar.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_time.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_time.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_time.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_time.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_widget.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_widget.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_widget.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_widget.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/regional_ranking.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/regional_ranking.dart similarity index 78% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/regional_ranking.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/regional_ranking.dart index 59be5a7..9d4b216 100644 --- a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/regional_ranking.dart +++ b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/regional_ranking.dart @@ -2,11 +2,11 @@ import 'package:flutter/material.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/utils/screen_size.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/filter_ranking_button.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/my_ranking_widget.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_region.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_scrollbar.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_widget.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/filter_ranking_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/my_ranking_widget.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_region.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_scrollbar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_widget.dart'; class RegionalRanking extends StatefulWidget { const RegionalRanking({super.key}); diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/time_ranking.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/time_ranking.dart similarity index 79% rename from lib/features/battle_league/first_part/presentation/ui/widgets/main_page/time_ranking.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/main_page/time_ranking.dart index 2bd1995..fdeb1b2 100644 --- a/lib/features/battle_league/first_part/presentation/ui/widgets/main_page/time_ranking.dart +++ b/lib/features/battle_league/presentation/ui/first_part/widgets/main_page/time_ranking.dart @@ -2,11 +2,11 @@ import 'package:flutter/material.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/utils/screen_size.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/filter_ranking_button.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/my_ranking_widget.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_scrollbar.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_time.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_widget.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/filter_ranking_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/my_ranking_widget.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_scrollbar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_time.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_widget.dart'; class TimeRanking extends StatefulWidget { const TimeRanking({super.key}); diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/rank_title.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/rank_title.dart similarity index 100% rename from lib/features/battle_league/first_part/presentation/ui/widgets/rank_title.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/rank_title.dart diff --git a/lib/features/battle_league/first_part/presentation/ui/widgets/topic_page/topic_widget.dart b/lib/features/battle_league/presentation/ui/first_part/widgets/topic_page/topic_widget.dart similarity index 74% rename from lib/features/battle_league/first_part/presentation/ui/widgets/topic_page/topic_widget.dart rename to lib/features/battle_league/presentation/ui/first_part/widgets/topic_page/topic_widget.dart index 80e50d5..be2294e 100644 --- a/lib/features/battle_league/first_part/presentation/ui/widgets/topic_page/topic_widget.dart +++ b/lib/features/battle_league/presentation/ui/first_part/widgets/topic_page/topic_widget.dart @@ -1,28 +1,33 @@ 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_text_style.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/image/my_image.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/entity/topics_entity.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/entity/topics_entity.dart'; class TopicWidget extends StatelessWidget { const TopicWidget({ super.key, - this.onTap, required this.topic, + this.onPressed, + this.selected = false, }); - final VoidCallback? onTap; + final void Function(TopicsEntity topic)? onPressed; final TopicsEntity topic; + final bool selected; @override Widget build(BuildContext context) { return MyContainer( - onTap: onTap, + onTap: () { + onPressed?.call(topic); + }, height: 48.h, width: 148.w, borderRadius: const BorderRadius.all(Radius.circular(12)), - borderGradient: LinearGradient( + borderGradient: !selected ? null : LinearGradient( begin: AlignmentDirectional.centerStart, end: AlignmentDirectional.centerEnd, colors: [ @@ -30,7 +35,7 @@ class TopicWidget extends StatelessWidget { const Color(0XFFAA76FF).withValues(alpha: 0), ], ), - gradient: const RadialGradient( + gradient: !selected ? null : const RadialGradient( center: Alignment.center, radius: 3, colors: [ @@ -38,6 +43,7 @@ class TopicWidget extends StatelessWidget { Color(0XFF792BF3), ], ), + color: selected ? null : MyColors.black.withValues(alpha: 0.2), boxShadow: [ BoxShadow( offset: const Offset(0, 3.53), diff --git a/lib/features/battle_league/presentation/ui/second_part/battle_league_result_page.dart b/lib/features/battle_league/presentation/ui/second_part/battle_league_result_page.dart new file mode 100644 index 0000000..8647791 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/second_part/battle_league_result_page.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.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/features/battle_league/presentation/controller/battle_league_controller.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/first_part/widgets/button/battle_purple_button.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/second_part/widgets/question_board.dart'; + +class BattleLeagueResultPage extends GetView { + const BattleLeagueResultPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: DecoratedBox( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFF390F72), Color(0XFF160C30)], + ), + ), + child: SafeArea( + child: Column( + children: [ + Obx( + () => QuestionBoard( + enemyWonNumber: controller.enemyWonNumber.value, + myWonNumber: controller.myWonNumber.value, + roundNumber: controller.roundNumber.value, + enemyUserName: controller.enemyUsername.value, + ), + ), + 50.0.gapHeight, + Obx( + () => Text( + controller.winnerId.value == controller.myId + ? 'YOU WON GAME' + : controller.winnerId.value == controller.enemyId + ? 'YOU LOOS GAME' + : 'DRAW GAME', + style: Lexend.black, + ), + ), + Spacer(), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: BattlePurpleButton( + label: 'Play Another Game', + onTap: controller.backToTopicPage, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/battle_league/presentation/ui/second_part/bl_question_page.dart b/lib/features/battle_league/presentation/ui/second_part/bl_question_page.dart new file mode 100644 index 0000000..2cad043 --- /dev/null +++ b/lib/features/battle_league/presentation/ui/second_part/bl_question_page.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:shia_game_flutter/common_ui/resources/my_colors.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/features/battle_league/presentation/controller/battle_league_controller.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/second_part/widgets/question_board.dart'; + +class BLQuestionPage extends GetView { + const BLQuestionPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: DecoratedBox( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0XFF390F72), Color(0XFF160C30)], + ), + ), + child: SafeArea( + child: Column( + children: [ + Obx( + () => QuestionBoard( + enemyWonNumber: controller.enemyWonNumber.value, + myWonNumber: controller.myWonNumber.value, + roundNumber: controller.roundNumber.value, + enemyUserName: controller.enemyUsername.value, + ), + ), + 50.0.gapHeight, + Obx( + () => Text( + '${controller.roundTimer.value}', + style: Lexend.black, + ), + ), + 25.0.gapHeight, + Obx( + () => Text( + controller.question.value.text ?? '', + style: Lexend.bold, + ), + ), + const Spacer(), + Obx( + () => ListView.separated( + itemCount: controller.question.value.options?.length ?? 0, + shrinkWrap: true, + padding: const EdgeInsets.symmetric(horizontal: 20), + itemBuilder: (context, index) => Material( + type: MaterialType.transparency, + child: Obx( + () => ListTile( + selected: index == controller.selectedIndex.value, + selectedColor: MyColors.white, + selectedTileColor: controller.isCorrect.value == true + ? Colors.green + : controller.isCorrect.value == false + ? Colors.red + : Colors.yellow, + onTap: () { + controller.chooseAnswer(index: index); + }, + title: Text( + controller.question.value.options?[index].text ?? '', + textDirection: TextDirection.rtl, + ), + titleTextStyle: Lexend.bold, + shape: const StadiumBorder( + side: BorderSide(width: 1, color: MyColors.white), + ), + ), + ), + ), + separatorBuilder: (context, index) => 12.0.gapHeight, + ), + ), + const Spacer(), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/battle_league_question_avatar.dart b/lib/features/battle_league/presentation/ui/second_part/widgets/battle_league_question_avatar.dart similarity index 88% rename from lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/battle_league_question_avatar.dart rename to lib/features/battle_league/presentation/ui/second_part/widgets/battle_league_question_avatar.dart index bef7a18..b8eca26 100644 --- a/lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/battle_league_question_avatar.dart +++ b/lib/features/battle_league/presentation/ui/second_part/widgets/battle_league_question_avatar.dart @@ -6,7 +6,9 @@ import 'package:shia_game_flutter/core/utils/screen_size.dart'; import 'package:shia_game_flutter/core/widgets/image/my_image.dart'; class BattleLeagueQuestionAvatar extends StatelessWidget { - const BattleLeagueQuestionAvatar({super.key}); + const BattleLeagueQuestionAvatar({super.key, required this.userName}); + + final String userName; @override Widget build(BuildContext context) { @@ -35,7 +37,7 @@ class BattleLeagueQuestionAvatar extends StatelessWidget { ), ], ), - Text('Jack William', style: Lexend.bold.copyWith(fontSize: 10)), + Text(userName, style: Lexend.bold.copyWith(fontSize: 10)), ], ); } diff --git a/lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_board.dart b/lib/features/battle_league/presentation/ui/second_part/widgets/question_board.dart similarity index 50% rename from lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_board.dart rename to lib/features/battle_league/presentation/ui/second_part/widgets/question_board.dart index a1555a4..62bdcef 100644 --- a/lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_board.dart +++ b/lib/features/battle_league/presentation/ui/second_part/widgets/question_board.dart @@ -1,10 +1,21 @@ import 'package:flutter/material.dart'; import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; import 'package:shia_game_flutter/core/utils/screen_size.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/presentation/ui/widgets/battle_league_question_avatar.dart'; +import 'package:shia_game_flutter/features/battle_league/presentation/ui/second_part/widgets/battle_league_question_avatar.dart'; class QuestionBoard extends StatelessWidget { - const QuestionBoard({super.key}); + const QuestionBoard({ + super.key, + required this.myWonNumber, + required this.enemyWonNumber, + required this.roundNumber, + required this.enemyUserName, + }); + + final int myWonNumber; + final int enemyWonNumber; + final int roundNumber; + final String enemyUserName; @override Widget build(BuildContext context) { @@ -13,12 +24,15 @@ class QuestionBoard extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const BattleLeagueQuestionAvatar(), + const BattleLeagueQuestionAvatar(userName: 'YOU'), Column( children: [ - Text('6 - 4', style: Lexend.bold.copyWith(fontSize: 30)), Text( - 'Question 5', + '$myWonNumber - $enemyWonNumber', + style: Lexend.bold.copyWith(fontSize: 30), + ), + Text( + 'Question $roundNumber', style: Lexend.regular.copyWith( fontSize: 10, color: const Color(0XFF9273C0), @@ -26,7 +40,7 @@ class QuestionBoard extends StatelessWidget { ), ], ), - const BattleLeagueQuestionAvatar(), + BattleLeagueQuestionAvatar(userName: enemyUserName), ], ), ); diff --git a/lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_timer_ready_widget.dart b/lib/features/battle_league/presentation/ui/second_part/widgets/question_timer_ready_widget.dart similarity index 100% rename from lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_timer_ready_widget.dart rename to lib/features/battle_league/presentation/ui/second_part/widgets/question_timer_ready_widget.dart diff --git a/lib/features/battle_league/question_part/bl_question/data/datasource/bl_question_datasource.dart b/lib/features/battle_league/question_part/bl_question/data/datasource/bl_question_datasource.dart deleted file mode 100644 index bd224d8..0000000 --- a/lib/features/battle_league/question_part/bl_question/data/datasource/bl_question_datasource.dart +++ /dev/null @@ -1,28 +0,0 @@ -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/bl_question_params.dart'; -import 'package:shia_game_flutter/core/response/base_response.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/data/model/bl_question_model.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart'; - -abstract class IBLQuestionDatasource { - Future getData({required BLQuestionParams params}); -} - -class BLQuestionDatasourceImpl implements IBLQuestionDatasource { - final IHttpRequest httpRequest; - - const BLQuestionDatasourceImpl(this.httpRequest); - - @override - Future getData({required BLQuestionParams params}) async { - final response = await httpRequest.get( - path: MyApi.baseUrl, - ); - - return BaseResponse.getData( - response?['data'], - (json) => BLQuestionModel.fromJson(json), - ); - } -} diff --git a/lib/features/battle_league/question_part/bl_question/data/model/bl_question_model.dart b/lib/features/battle_league/question_part/bl_question/data/model/bl_question_model.dart deleted file mode 100644 index 99ffc46..0000000 --- a/lib/features/battle_league/question_part/bl_question/data/model/bl_question_model.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart'; - -class BLQuestionModel extends BLQuestionEntity { - const BLQuestionModel({ - super.id, - }); - - factory BLQuestionModel.fromJson(Map json) { - return BLQuestionModel( - id: json['id'], - ); - } -} diff --git a/lib/features/battle_league/question_part/bl_question/data/repository_impl/bl_question_repository_impl.dart b/lib/features/battle_league/question_part/bl_question/data/repository_impl/bl_question_repository_impl.dart deleted file mode 100644 index d3291f9..0000000 --- a/lib/features/battle_league/question_part/bl_question/data/repository_impl/bl_question_repository_impl.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; -import 'package:shia_game_flutter/core/params/bl_question_params.dart'; -import 'package:shia_game_flutter/core/utils/data_state.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/data/datasource/bl_question_datasource.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart'; - -class BLQuestionRepositoryImpl implements IBLQuestionRepository { - final IBLQuestionDatasource datasource; - - const BLQuestionRepositoryImpl(this.datasource); - - @override - Future> getData({required BLQuestionParams params}) async { - try { - final BLQuestionEntity 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/question_part/bl_question/domain/entity/bl_question_entity.dart b/lib/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart deleted file mode 100644 index 7818664..0000000 --- a/lib/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:equatable/equatable.dart'; - -class BLQuestionEntity extends Equatable { - final int? id; - - const BLQuestionEntity({ - this.id, - }); - - @override - List get props => [ - id, - ]; -} diff --git a/lib/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart b/lib/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart deleted file mode 100644 index bc1ce21..0000000 --- a/lib/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; -import 'package:shia_game_flutter/core/params/bl_question_params.dart'; -import 'package:shia_game_flutter/core/utils/data_state.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart'; - -abstract class IBLQuestionRepository { - Future> getData({required BLQuestionParams params}); -} diff --git a/lib/features/battle_league/question_part/bl_question/domain/usecases/get_bl_question_usecase.dart b/lib/features/battle_league/question_part/bl_question/domain/usecases/get_bl_question_usecase.dart deleted file mode 100644 index 6e4c11e..0000000 --- a/lib/features/battle_league/question_part/bl_question/domain/usecases/get_bl_question_usecase.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; -import 'package:shia_game_flutter/core/params/bl_question_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/question_part/bl_question/domain/entity/bl_question_entity.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart'; - -class GetBLQuestionUseCase implements UseCase { - final IBLQuestionRepository repository; - - const GetBLQuestionUseCase(this.repository); - - @override - Future> call(BLQuestionParams params) { - return repository.getData(params: params); - } -} - - diff --git a/lib/features/battle_league/question_part/bl_question/presentation/binding/bl_question_binding.dart b/lib/features/battle_league/question_part/bl_question/presentation/binding/bl_question_binding.dart deleted file mode 100644 index 38440b7..0000000 --- a/lib/features/battle_league/question_part/bl_question/presentation/binding/bl_question_binding.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/presentation/controller/bl_question_controller.dart'; -import 'package:get/get.dart'; - -class BLQuestionBinding extends Bindings { - @override - void dependencies() { - Get.put(BLQuestionController(Get.find())); - } - - Future deleteBindings() async { - await Future.wait([ - Get.delete(), - ]); - } - - Future refreshBinding() async { - await deleteBindings(); - dependencies(); - } -} diff --git a/lib/features/battle_league/question_part/bl_question/presentation/controller/bl_question_controller.dart b/lib/features/battle_league/question_part/bl_question/presentation/controller/bl_question_controller.dart deleted file mode 100644 index d6a42e0..0000000 --- a/lib/features/battle_league/question_part/bl_question/presentation/controller/bl_question_controller.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:shia_game_flutter/core/params/bl_question_params.dart'; -import 'package:shia_game_flutter/core/status/base_status.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/usecases/get_bl_question_usecase.dart'; -import 'package:get/get.dart'; - -class BLQuestionController extends GetxController with StateMixin { - /// ----- Constructor ----- - BLQuestionController(this.getBLQuestionUseCase); - - @override - void onInit() { - super.onInit(); - change('', status: RxStatus.success()); - } - - @override - void onClose() { - textEditingController.dispose(); - super.onClose(); - } - - /// ----- UseCases ----- - final GetBLQuestionUseCase getBLQuestionUseCase; - - /// ----- Variables ----- - final Rx bLQuestionParams = Rx(BLQuestionParams()); - final Rx bLQuestionEntity = Rx(const BLQuestionEntity()); - - /// ------ Controllers ------ - final TextEditingController textEditingController = TextEditingController(); - - /// ------ Statuses ------ - final Rx getBLQuestionStatus = Rx(const BaseInit()); - - /// ------ Functions ------ - - /// ------ Api Calls ------ - Future getBLQuestion() async { - change('', status: RxStatus.loading()); - await getBLQuestionUseCase(bLQuestionParams.value).then( - (value) => value.fold( - (data) { - bLQuestionEntity.value = data; - change('', status: RxStatus.success()); - }, - (error) { - change('', status: RxStatus.error(error.errorMessage)); - }, - ), - ); - } -} diff --git a/lib/features/battle_league/question_part/bl_question/presentation/ui/bl_question_page.dart b/lib/features/battle_league/question_part/bl_question/presentation/ui/bl_question_page.dart deleted file mode 100644 index df10388..0000000 --- a/lib/features/battle_league/question_part/bl_question/presentation/ui/bl_question_page.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:shia_game_flutter/core/widgets/stepper/my_stepper.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/presentation/controller/bl_question_controller.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_board.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_timer_ready_widget.dart'; - -class BLQuestionPage extends GetView { - const BLQuestionPage({super.key}); - - @override - Widget build(BuildContext context) { - return const Scaffold( - body: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [Color(0XFF390F72), Color(0XFF160C30)], - ), - ), - child: SafeArea( - child: Column( - children: [ - QuestionBoard(), - MyStepper(), - QuestionTimerReadyWidget(), - ], - ), - ), - ), - ); - } -} diff --git a/lib/init_bindings.dart b/lib/init_bindings.dart index e39fdd8..526625f 100644 --- a/lib/init_bindings.dart +++ b/lib/init_bindings.dart @@ -5,14 +5,13 @@ import 'package:shia_game_flutter/features/awards/data/datasource/awards_datasou import 'package:shia_game_flutter/features/awards/data/repository_impl/awards_repository_impl.dart'; import 'package:shia_game_flutter/features/awards/domain/repository/awards_repository.dart'; import 'package:shia_game_flutter/features/awards/domain/usecases/get_awards_usecase.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/data/datasource/battle_league_datasource.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/data/repository_impl/battle_league_repository_impl.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/repository/battle_league_repository.dart'; -import 'package:shia_game_flutter/features/battle_league/first_part/domain/usecases/get_topics_usecase.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/data/datasource/bl_question_datasource.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/data/repository_impl/bl_question_repository_impl.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart'; -import 'package:shia_game_flutter/features/battle_league/question_part/bl_question/domain/usecases/get_bl_question_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_clock_usecase.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_player_token_usecase.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/get_topics_usecase.dart'; +import 'package:shia_game_flutter/features/battle_league/domain/usecases/match_making_usecase.dart'; import 'package:shia_game_flutter/features/home/data/datasource/home_datasource.dart'; import 'package:shia_game_flutter/features/home/data/repository_impl/home_repository_impl.dart'; import 'package:shia_game_flutter/features/home/domain/repository/home_repository.dart'; @@ -80,10 +79,8 @@ void initBindings() { /// ----- BattleLeague Feature ----- Get.lazyPut(() => BattleLeagueDatasourceImpl(Get.find()), fenix: true); Get.lazyPut(() => BattleLeagueRepositoryImpl(Get.find()), fenix: true); + Get.lazyPut(() => GetPlayerTokenUseCase(Get.find()), fenix: true); Get.lazyPut(() => GetTopicsUseCase(Get.find()), fenix: true); - - /// ----- BattleLeagueQuestion Feature ----- - Get.lazyPut(() => BLQuestionDatasourceImpl(Get.find()), fenix: true); - Get.lazyPut(() => BLQuestionRepositoryImpl(Get.find()), fenix: true); - Get.lazyPut(() => GetBLQuestionUseCase(Get.find()), fenix: true); + Get.lazyPut(() => GetClockUseCase(Get.find()), fenix: true); + Get.lazyPut(() => MatchMakingUseCase(Get.find()), fenix: true); } diff --git a/pubspec.yaml b/pubspec.yaml index 2ebc492..e07940a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: shia_game_flutter description: "A new Flutter project." publish_to: 'none' -version: 0.1.0 +version: 0.0.1 environment: sdk: ^3.9.2