Browse Source

Merge pull request 'feature/websocket' (#18) from feature/websocket into develop

Reviewed-on: #18
pull/19/head
amirreza.chegini 5 days ago
parent
commit
25acbb787f
  1. 16
      android/app/build.gradle.kts
  2. 18
      lib/core/constants/my_api.dart
  3. 5
      lib/core/params/battle_league_params.dart
  4. 14
      lib/core/params/bl_params.dart
  5. 22
      lib/core/routers/my_routes.dart
  6. 176
      lib/core/services/web_socket_service.dart
  7. 71
      lib/features/battle_league/data/datasource/battle_league_datasource.dart
  8. 9
      lib/features/battle_league/data/model/answer_model.dart
  9. 17
      lib/features/battle_league/data/model/clock_model.dart
  10. 23
      lib/features/battle_league/data/model/match_making_model.dart
  11. 13
      lib/features/battle_league/data/model/player_token_model.dart
  12. 18
      lib/features/battle_league/data/model/question_model.dart
  13. 2
      lib/features/battle_league/data/model/topics_model.dart
  14. 94
      lib/features/battle_league/data/repository_impl/battle_league_repository_impl.dart
  15. 11
      lib/features/battle_league/domain/entity/answer_entity.dart
  16. 12
      lib/features/battle_league/domain/entity/clock_entity.dart
  17. 29
      lib/features/battle_league/domain/entity/match_making_entity.dart
  18. 12
      lib/features/battle_league/domain/entity/player_token_entity.dart
  19. 14
      lib/features/battle_league/domain/entity/question_entity.dart
  20. 0
      lib/features/battle_league/domain/entity/topics_entity.dart
  21. 22
      lib/features/battle_league/domain/repository/battle_league_repository.dart
  22. 17
      lib/features/battle_league/domain/usecases/get_clock_usecase.dart
  23. 18
      lib/features/battle_league/domain/usecases/get_player_token_usecase.dart
  24. 18
      lib/features/battle_league/domain/usecases/get_topics_usecase.dart
  25. 17
      lib/features/battle_league/domain/usecases/match_making_usecase.dart
  26. 28
      lib/features/battle_league/first_part/data/datasource/battle_league_datasource.dart
  27. 14
      lib/features/battle_league/first_part/data/model/battle_league_model.dart
  28. 33
      lib/features/battle_league/first_part/data/repository_impl/battle_league_repository_impl.dart
  29. 15
      lib/features/battle_league/first_part/domain/entity/battle_league_entity.dart
  30. 10
      lib/features/battle_league/first_part/domain/repository/battle_league_repository.dart
  31. 18
      lib/features/battle_league/first_part/domain/usecases/get_topics_usecase.dart
  32. 70
      lib/features/battle_league/first_part/presentation/controller/battle_league_controller.dart
  33. 9
      lib/features/battle_league/presentation/binding/battle_league_binding.dart
  34. 280
      lib/features/battle_league/presentation/controller/battle_league_controller.dart
  35. 45
      lib/features/battle_league/presentation/ui/first_part/battle_league_finding_page.dart
  36. 6
      lib/features/battle_league/presentation/ui/first_part/battle_league_founded_page.dart
  37. 10
      lib/features/battle_league/presentation/ui/first_part/battle_league_page.dart
  38. 19
      lib/features/battle_league/presentation/ui/first_part/battle_league_topic_page.dart
  39. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_golden_button.dart
  40. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_grey_button.dart
  41. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_purple_button.dart
  42. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/founded_page/founded_avatar.dart
  43. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/battle_league_tab_bar.dart
  44. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/filter_ranking_button.dart
  45. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/my_ranking_widget.dart
  46. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_region.dart
  47. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_scrollbar.dart
  48. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_time.dart
  49. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_widget.dart
  50. 10
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/regional_ranking.dart
  51. 10
      lib/features/battle_league/presentation/ui/first_part/widgets/main_page/time_ranking.dart
  52. 0
      lib/features/battle_league/presentation/ui/first_part/widgets/rank_title.dart
  53. 18
      lib/features/battle_league/presentation/ui/first_part/widgets/topic_page/topic_widget.dart
  54. 59
      lib/features/battle_league/presentation/ui/second_part/battle_league_result_page.dart
  55. 89
      lib/features/battle_league/presentation/ui/second_part/bl_question_page.dart
  56. 6
      lib/features/battle_league/presentation/ui/second_part/widgets/battle_league_question_avatar.dart
  57. 26
      lib/features/battle_league/presentation/ui/second_part/widgets/question_board.dart
  58. 0
      lib/features/battle_league/presentation/ui/second_part/widgets/question_timer_ready_widget.dart
  59. 28
      lib/features/battle_league/question_part/bl_question/data/datasource/bl_question_datasource.dart
  60. 13
      lib/features/battle_league/question_part/bl_question/data/model/bl_question_model.dart
  61. 29
      lib/features/battle_league/question_part/bl_question/data/repository_impl/bl_question_repository_impl.dart
  62. 14
      lib/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart
  63. 8
      lib/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart
  64. 19
      lib/features/battle_league/question_part/bl_question/domain/usecases/get_bl_question_usecase.dart
  65. 20
      lib/features/battle_league/question_part/bl_question/presentation/binding/bl_question_binding.dart
  66. 54
      lib/features/battle_league/question_part/bl_question/presentation/controller/bl_question_controller.dart
  67. 34
      lib/features/battle_league/question_part/bl_question/presentation/ui/bl_question_page.dart
  68. 23
      lib/init_bindings.dart
  69. 2
      pubspec.yaml

16
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 {

18
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';
}

5
lib/core/params/battle_league_params.dart

@ -1,5 +0,0 @@
class BattleLeagueParams {
int? id;
BattleLeagueParams({this.id});
}

14
lib/core/params/bl_params.dart

@ -0,0 +1,14 @@
class BlParams {
List<int>? chooseTopics;
BlParams({this.chooseTopics});
Map<String, dynamic> get toCockJson => {
'client_time': DateTime.now().millisecondsSinceEpoch,
};
Map<String, dynamic> get toMatchMakingJson => {
'skill_level': 0,
if (chooseTopics?.isNotEmpty ?? false) 'topic_ids': chooseTopics,
};
}

22
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<GetPage> appPages = [
@ -103,6 +104,11 @@ final List<GetPage> appPages = [
GetPage(
name: Routes.battleLeagueQuestionPage,
page: () => const BLQuestionPage(),
binding: BLQuestionBinding(),
binding: BattleLeagueBinding(),
),
GetPage(
name: Routes.battleLeagueResultPage,
page: () => const BattleLeagueResultPage(),
binding: BattleLeagueBinding(),
),
];

176
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<void> 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<ConnectingEvent> get clientConnecting => _client.connecting;
Stream<ConnectedEvent> get clientConnected => _client.connected;
Stream<DisconnectedEvent> get clientDisconnected => _client.disconnected;
Stream<ServerPublicationEvent> get clientPublication => _client.publication;
Future<void> disconnect() async {
try {
await _client.disconnect();
} catch (e) {
rethrow;
}
}
Future<RPCResult> sendRpc({
required String method,
required Map<String, dynamic> 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<void> 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<JoinEvent> get subscribeJoin => _subscription.join;
Stream<PublicationEvent> get subscribePublication => _subscription.publication;
Future<void> unSubscribe() async {
try {
await _subscription.unsubscribe();
} catch (e) {
rethrow;
}
}
}

71
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<PlayerTokenEntity> getPlayerToken({required BlParams params});
Future<List<TopicsEntity>> getTopics({required BlParams params});
Future<ClockEntity> getClock({required BlParams params});
Future<MatchMakingEntity> matchMaking({required BlParams params});
}
class BattleLeagueDatasourceImpl implements IBattleLeagueDatasource {
final IHttpRequest httpRequest;
const BattleLeagueDatasourceImpl(this.httpRequest);
@override
Future<PlayerTokenEntity> getPlayerToken({required BlParams params}) async {
final response = await httpRequest.post(path: MyApi.centrifugoToken);
return BaseResponse.getData<PlayerTokenEntity>(
response,
(json) => PlayerTokenModel.fromJson(json),
);
}
@override
Future<List<TopicsEntity>> getTopics({required BlParams params}) async {
final response = await httpRequest.get(path: MyApi.topics);
return BaseResponse.getDataList<TopicsEntity>(
response?['results'],
(json) => TopicsModel.fromJson(json),
);
}
@override
Future<ClockEntity> getClock({required BlParams params}) async {
final response = await httpRequest.post(
path: MyApi.clock,
data: params.toCockJson,
);
return BaseResponse.getData<ClockEntity>(
response,
(json) => ClockModel.fromJson(json),
);
}
@override
Future<MatchMakingEntity> matchMaking({required BlParams params}) async {
final response = await httpRequest.post(
path: MyApi.matchMaking,
data: params.toMatchMakingJson,
);
return BaseResponse.getData<MatchMakingEntity>(
response,
(json) => MatchMakingModel.fromJson(json),
);
}
}

9
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<String, dynamic> json) {
return AnswerModel(id: json['id'], text: json['text']);
}
}

17
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<String, dynamic> json) {
return ClockModel(
clientTime: json['client_time'],
serverTime: json['server_time'],
serverReceiveTime: json['server_receive_time'],
);
}
}

23
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<String, dynamic> json) {
return MatchMakingModel(
estimatedWaitTime: json['estimated_wait_time'],
message: json['message'],
position: json['position'],
queueSize: json['queue_size'],
selectedTopics: json['selected_topics']?.map<int>((e) => int.parse('$e')).toList(),
status: json['status'],
);
}
}

13
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<String, dynamic> json) {
return PlayerTokenModel(
token: json['token'],
user: json['user'],
channel: json['channel'],
);
}
}

18
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<String, dynamic> json) {
return QuestionModel(
id: json['id'],
text: json['text'],
options: json['options']
?.map<AnswerEntity>((e) => AnswerModel.fromJson(e))
.toList(),
timeLimit: json['time_limit'],
);
}
}

2
lib/features/battle_league/first_part/data/model/topics_model.dart → 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({

94
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<DataState<PlayerTokenEntity, MyException>> 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<DataState<List<TopicsEntity>, MyException>> getTopics({
required BlParams params,
}) async {
try {
final List<TopicsEntity> 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<DataState<ClockEntity, MyException>> 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<DataState<MatchMakingEntity, MyException>> 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'));
}
}
}
}

11
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<Object?> get props => [id, text];
}

12
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<Object?> get props => [serverTime, clientTime, serverReceiveTime];
}

29
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<int>? selectedTopics;
final String? status;
const MatchMakingEntity({
this.estimatedWaitTime,
this.message,
this.position,
this.queueSize,
this.selectedTopics,
this.status,
});
@override
List<Object?> get props => [
estimatedWaitTime,
message,
position,
queueSize,
selectedTopics,
status,
];
}

12
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<Object?> get props => [token, user, channel];
}

14
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<AnswerEntity>? options;
final int? timeLimit;
const QuestionEntity({this.id, this.text, this.options, this.timeLimit});
@override
List<Object?> get props => [id, text, options, timeLimit];
}

0
lib/features/battle_league/first_part/domain/entity/topics_entity.dart → lib/features/battle_league/domain/entity/topics_entity.dart

22
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<DataState<PlayerTokenEntity, MyException>> getPlayerToken({
required BlParams params,
});
Future<DataState<List<TopicsEntity>, MyException>> getTopics({
required BlParams params,
});
Future<DataState<ClockEntity, MyException>> getClock({
required BlParams params,
});
Future<DataState<MatchMakingEntity, MyException>> matchMaking({
required BlParams params,
});
}

17
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<ClockEntity, BlParams> {
final IBattleLeagueRepository repository;
const GetClockUseCase(this.repository);
@override
Future<DataState<ClockEntity, MyException>> call(BlParams params) {
return repository.getClock(params: params);
}
}

18
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<PlayerTokenEntity, BlParams> {
final IBattleLeagueRepository repository;
const GetPlayerTokenUseCase(this.repository);
@override
Future<DataState<PlayerTokenEntity, MyException>> call(BlParams params) {
return repository.getPlayerToken(params: params);
}
}

18
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<List<TopicsEntity>, BlParams> {
final IBattleLeagueRepository repository;
const GetTopicsUseCase(this.repository);
@override
Future<DataState<List<TopicsEntity>, MyException>> call(BlParams params,) {
return repository.getTopics(params: params);
}
}

17
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<MatchMakingEntity, BlParams> {
final IBattleLeagueRepository repository;
const MatchMakingUseCase(this.repository);
@override
Future<DataState<MatchMakingEntity, MyException>> call(BlParams params) {
return repository.matchMaking(params: params);
}
}

28
lib/features/battle_league/first_part/data/datasource/battle_league_datasource.dart

@ -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<List<TopicsEntity>> getTopics({required BattleLeagueParams params});
}
class BattleLeagueDatasourceImpl implements IBattleLeagueDatasource {
final IHttpRequest httpRequest;
const BattleLeagueDatasourceImpl(this.httpRequest);
@override
Future<List<TopicsEntity>> getTopics({
required BattleLeagueParams params,
}) async {
final response = await httpRequest.get(path: MyApi.topics);
return BaseResponse.getDataList<TopicsEntity>(
response?['results'],
(json) => TopicsModel.fromJson(json),
);
}
}

14
lib/features/battle_league/first_part/data/model/battle_league_model.dart

@ -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<String, dynamic> json) {
return BattleLeagueModel(
id: json['id'],
);
}
}

33
lib/features/battle_league/first_part/data/repository_impl/battle_league_repository_impl.dart

@ -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<DataState<List<TopicsEntity>, MyException>> getTopics({
required BattleLeagueParams params,
}) async {
try {
final List<TopicsEntity> 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'));
}
}
}
}

15
lib/features/battle_league/first_part/domain/entity/battle_league_entity.dart

@ -1,15 +0,0 @@
import 'package:equatable/equatable.dart';
class BattleLeagueEntity extends Equatable {
final int? id;
const BattleLeagueEntity({
this.id,
});
@override
List<Object?> get props => [
id,
];
}

10
lib/features/battle_league/first_part/domain/repository/battle_league_repository.dart

@ -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<DataState<List<TopicsEntity>, MyException>> getTopics({
required BattleLeagueParams params,
});
}

18
lib/features/battle_league/first_part/domain/usecases/get_topics_usecase.dart

@ -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<List<TopicsEntity>, BattleLeagueParams> {
final IBattleLeagueRepository repository;
const GetTopicsUseCase(this.repository);
@override
Future<DataState<List<TopicsEntity>, MyException>> call(BattleLeagueParams params,) {
return repository.getTopics(params: params);
}
}

70
lib/features/battle_league/first_part/presentation/controller/battle_league_controller.dart

@ -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<TopicsEntity> topicList = RxList.empty();
/// ------ Controllers ------
final TextEditingController textEditingController = TextEditingController();
late final TabController tabController;
/// ------ Statuses ------
final Rx<BaseStatus> getBattleLeagueStatus = Rx(const BaseInit());
final Rx<BaseStatus> 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<void> 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);
},
),
);
}
}

9
lib/features/battle_league/first_part/presentation/binding/battle_league_binding.dart → 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>(BattleLeagueController(Get.find()));
Get.put<BattleLeagueController>(BattleLeagueController(
Get.find(),
Get.find(),
Get.find(),
Get.find(),
));
}
Future<void> deleteBindings() async {

280
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<TopicsEntity> topicList = RxList.empty();
final RxList<TopicsEntity> chooseTopicList = RxList.empty();
PlayerTokenEntity playerToken = const PlayerTokenEntity();
final Rx<QuestionEntity> question = Rx(const QuestionEntity());
int battleId = 0;
final RxInt roundNumber = RxInt(0);
final Rx<bool?> 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<String?> winnerId = Rx(null);
/// ------ Controllers ------
final TextEditingController textEditingController = TextEditingController();
late final TabController tabController;
/// ------ Statuses ------
final Rx<BaseStatus> getTopicsStatus = Rx(const BaseInit());
final Rx<BaseStatus> connectStatus = Rx(const BaseLoading());
final Rx<BaseStatus> getClockStatus = Rx(const BaseInit());
final Rx<BaseStatus> 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<void> 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<TopicsEntity> newTopicList = List.from(topicList);
newTopicList.shuffle();
chooseTopicList.value = newTopicList.take(3).toList();
}
Future<void> 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<void> getPlayerToken() async {
await _getPlayerTokenUseCase(blParams).then(
(value) => value.fold((data) {
playerToken = data;
_webSocketService.connect();
}, (error) {}),
);
}
Future<void> 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<void> 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<void> 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);
},
),
);
}
}

45
lib/features/battle_league/first_part/presentation/ui/battle_league_finding_page.dart → 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<BattleLeagueController> {
const BattleLeagueFindingPage({super.key});
@ -46,10 +47,38 @@ class BattleLeagueFindingPage extends GetView<BattleLeagueController> {
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<BattleLeagueController> {
Widget _startFindingButton(BuildContext context) {
return BattlePurpleButton(
label: context.translate.stop_finding,
onTap: controller.goToFoundedPage,
onTap: controller.cancelFinding,
);
}
}

6
lib/features/battle_league/first_part/presentation/ui/battle_league_founded_page.dart → 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<BattleLeagueController> {
const BattleLeagueFoundedPage({super.key});

10
lib/features/battle_league/first_part/presentation/ui/battle_league_page.dart → 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<BattleLeagueController> {
const BattleLeaguePage({super.key});

19
lib/features/battle_league/first_part/presentation/ui/battle_league_topic_page.dart → 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<BattleLeagueController> {
const BattleLeagueTopicPage({super.key});
@ -97,9 +97,12 @@ class BattleLeagueTopicPage extends GetView<BattleLeagueController> {
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<BattleLeagueController> {
child: BattleGreyButton(
label: context.translate.random,
image: MyAssets.iconRandom,
onTap: () {},
onTap: controller.choosRandomTopic,
),
);
}

0
lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_golden_button.dart → lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_golden_button.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_grey_button.dart → lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_grey_button.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/button/battle_purple_button.dart → lib/features/battle_league/presentation/ui/first_part/widgets/button/battle_purple_button.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/founded_page/founded_avatar.dart → lib/features/battle_league/presentation/ui/first_part/widgets/founded_page/founded_avatar.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/battle_league_tab_bar.dart → lib/features/battle_league/presentation/ui/first_part/widgets/main_page/battle_league_tab_bar.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/filter_ranking_button.dart → lib/features/battle_league/presentation/ui/first_part/widgets/main_page/filter_ranking_button.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/my_ranking_widget.dart → lib/features/battle_league/presentation/ui/first_part/widgets/main_page/my_ranking_widget.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_region.dart → lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_region.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_scrollbar.dart → lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_scrollbar.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_time.dart → lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_time.dart

0
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/ranking_widget.dart → lib/features/battle_league/presentation/ui/first_part/widgets/main_page/ranking_widget.dart

10
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/regional_ranking.dart → 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});

10
lib/features/battle_league/first_part/presentation/ui/widgets/main_page/time_ranking.dart → 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});

0
lib/features/battle_league/first_part/presentation/ui/widgets/rank_title.dart → lib/features/battle_league/presentation/ui/first_part/widgets/rank_title.dart

18
lib/features/battle_league/first_part/presentation/ui/widgets/topic_page/topic_widget.dart → 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),

59
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<BattleLeagueController> {
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,
),
),
],
),
),
),
);
}
}

89
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<BattleLeagueController> {
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(),
],
),
),
),
);
}
}

6
lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/battle_league_question_avatar.dart → 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)),
],
);
}

26
lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_board.dart → 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),
],
),
);

0
lib/features/battle_league/question_part/bl_question/presentation/ui/widgets/question_timer_ready_widget.dart → lib/features/battle_league/presentation/ui/second_part/widgets/question_timer_ready_widget.dart

28
lib/features/battle_league/question_part/bl_question/data/datasource/bl_question_datasource.dart

@ -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<BLQuestionEntity> getData({required BLQuestionParams params});
}
class BLQuestionDatasourceImpl implements IBLQuestionDatasource {
final IHttpRequest httpRequest;
const BLQuestionDatasourceImpl(this.httpRequest);
@override
Future<BLQuestionEntity> getData({required BLQuestionParams params}) async {
final response = await httpRequest.get(
path: MyApi.baseUrl,
);
return BaseResponse.getData<BLQuestionEntity>(
response?['data'],
(json) => BLQuestionModel.fromJson(json),
);
}
}

13
lib/features/battle_league/question_part/bl_question/data/model/bl_question_model.dart

@ -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<String, dynamic> json) {
return BLQuestionModel(
id: json['id'],
);
}
}

29
lib/features/battle_league/question_part/bl_question/data/repository_impl/bl_question_repository_impl.dart

@ -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<DataState<BLQuestionEntity, MyException>> 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'));
}
}
}
}

14
lib/features/battle_league/question_part/bl_question/domain/entity/bl_question_entity.dart

@ -1,14 +0,0 @@
import 'package:equatable/equatable.dart';
class BLQuestionEntity extends Equatable {
final int? id;
const BLQuestionEntity({
this.id,
});
@override
List<Object?> get props => [
id,
];
}

8
lib/features/battle_league/question_part/bl_question/domain/repository/bl_question_repository.dart

@ -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<DataState<BLQuestionEntity, MyException>> getData({required BLQuestionParams params});
}

19
lib/features/battle_league/question_part/bl_question/domain/usecases/get_bl_question_usecase.dart

@ -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<BLQuestionEntity, BLQuestionParams> {
final IBLQuestionRepository repository;
const GetBLQuestionUseCase(this.repository);
@override
Future<DataState<BLQuestionEntity, MyException>> call(BLQuestionParams params) {
return repository.getData(params: params);
}
}

20
lib/features/battle_league/question_part/bl_question/presentation/binding/bl_question_binding.dart

@ -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>(BLQuestionController(Get.find()));
}
Future<void> deleteBindings() async {
await Future.wait([
Get.delete<BLQuestionController>(),
]);
}
Future<void> refreshBinding() async {
await deleteBindings();
dependencies();
}
}

54
lib/features/battle_league/question_part/bl_question/presentation/controller/bl_question_controller.dart

@ -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> bLQuestionParams = Rx(BLQuestionParams());
final Rx<BLQuestionEntity> bLQuestionEntity = Rx(const BLQuestionEntity());
/// ------ Controllers ------
final TextEditingController textEditingController = TextEditingController();
/// ------ Statuses ------
final Rx<BaseStatus> getBLQuestionStatus = Rx(const BaseInit());
/// ------ Functions ------
/// ------ Api Calls ------
Future<void> 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));
},
),
);
}
}

34
lib/features/battle_league/question_part/bl_question/presentation/ui/bl_question_page.dart

@ -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<BLQuestionController> {
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(),
],
),
),
),
);
}
}

23
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<IBattleLeagueDatasource>(() => BattleLeagueDatasourceImpl(Get.find()), fenix: true);
Get.lazyPut<IBattleLeagueRepository>(() => BattleLeagueRepositoryImpl(Get.find()), fenix: true);
Get.lazyPut<GetPlayerTokenUseCase>(() => GetPlayerTokenUseCase(Get.find()), fenix: true);
Get.lazyPut<GetTopicsUseCase>(() => GetTopicsUseCase(Get.find()), fenix: true);
/// ----- BattleLeagueQuestion Feature -----
Get.lazyPut<IBLQuestionDatasource>(() => BLQuestionDatasourceImpl(Get.find()), fenix: true);
Get.lazyPut<IBLQuestionRepository>(() => BLQuestionRepositoryImpl(Get.find()), fenix: true);
Get.lazyPut<GetBLQuestionUseCase>(() => GetBLQuestionUseCase(Get.find()), fenix: true);
Get.lazyPut<GetClockUseCase>(() => GetClockUseCase(Get.find()), fenix: true);
Get.lazyPut<MatchMakingUseCase>(() => MatchMakingUseCase(Get.find()), fenix: true);
}

2
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

Loading…
Cancel
Save