34 changed files with 512 additions and 21 deletions
-
BINassets/fonts/Lexend-Black.ttf
-
BINassets/fonts/Lexend-Bold.ttf
-
BINassets/fonts/Lexend-ExtraBold.ttf
-
BINassets/fonts/Lexend-ExtraLight.ttf
-
BINassets/fonts/Lexend-Light.ttf
-
BINassets/fonts/Lexend-Medium.ttf
-
BINassets/fonts/Lexend-Regular.ttf
-
BINassets/fonts/Lexend-SemiBold.ttf
-
BINassets/fonts/Lexend-Thin.ttf
-
BINassets/images/question.png
-
BINassets/images/shia_mind.png
-
13lib/common_ui/resources/my_assets.dart
-
1lib/common_ui/resources/my_colors.dart
-
53lib/common_ui/resources/my_text_style.dart
-
10lib/common_ui/theme/my_theme.dart
-
13lib/core/params/intro_params.dart
-
20lib/core/routers/my_routes.dart
-
45lib/core/widgets/image/my_image.dart
-
28lib/features/intro/data/datasource/intro_datasource.dart
-
13lib/features/intro/data/model/intro_model.dart
-
29lib/features/intro/data/repository_impl/intro_repository_impl.dart
-
14lib/features/intro/domain/entity/intro_entity.dart
-
8lib/features/intro/domain/repository/intro_repository.dart
-
19lib/features/intro/domain/usecases/get_intro_usecase.dart
-
20lib/features/intro/presentation/binding/intro_binding.dart
-
54lib/features/intro/presentation/controller/intro_controller.dart
-
99lib/features/intro/presentation/ui/intro_page.dart
-
49lib/features/intro/presentation/ui/widgets/intro_loading.dart
-
9lib/init_bindings.dart
-
3lib/l10n/app_en.arb
-
6lib/l10n/app_localizations.dart
-
3lib/l10n/app_localizations_en.dart
-
2lib/main.dart
-
22pubspec.yaml
|
After Width: 25 | Height: 38 | Size: 1.1 KiB |
|
After Width: 169 | Height: 130 | Size: 32 KiB |
@ -1,15 +1,54 @@ |
|||
import 'package:flutter/material.dart'; |
|||
|
|||
class MyTextStyle { |
|||
static const MyTextStyle _i = MyTextStyle._internal(); |
|||
const MyTextStyle._internal(); |
|||
factory MyTextStyle() => _i; |
|||
class Lexend { |
|||
static const Lexend _i = Lexend._internal(); |
|||
const Lexend._internal(); |
|||
factory Lexend() => _i; |
|||
|
|||
static const String fontFamily = ''; |
|||
static const String fontFamily = 'Lexend'; |
|||
|
|||
static const TextStyle lightXS = TextStyle( |
|||
static const TextStyle thin = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w100, |
|||
); |
|||
|
|||
static const TextStyle extraLight = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w200, |
|||
); |
|||
|
|||
static const TextStyle light = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w300, |
|||
); |
|||
|
|||
static const TextStyle regular = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontSize: 10, |
|||
fontWeight: FontWeight.w400, |
|||
); |
|||
|
|||
static const TextStyle medium = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w500, |
|||
); |
|||
|
|||
static const TextStyle semiBold = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w600, |
|||
); |
|||
|
|||
static const TextStyle bold = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w700, |
|||
); |
|||
|
|||
static const TextStyle extraBold = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w800, |
|||
); |
|||
|
|||
static const TextStyle black = TextStyle( |
|||
fontFamily: fontFamily, |
|||
fontWeight: FontWeight.w900, |
|||
); |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
class IntroParams { |
|||
int? id; |
|||
|
|||
IntroParams({this.id}); |
|||
|
|||
IntroParams copyWith({ |
|||
int? id, |
|||
}) { |
|||
return IntroParams( |
|||
id: id ?? this.id, |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:vector_graphics/vector_graphics.dart'; |
|||
|
|||
class MyImage extends StatelessWidget { |
|||
const MyImage({ |
|||
super.key, |
|||
required this.asset, |
|||
this.size, |
|||
this.fit = BoxFit.contain, |
|||
this.color, |
|||
}); |
|||
|
|||
final String asset; |
|||
final double? size; |
|||
final BoxFit fit; |
|||
final Color? color; |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Builder( |
|||
builder: (context) { |
|||
if (asset.endsWith('.jpg') || |
|||
asset.endsWith('.jpeg') || |
|||
asset.endsWith('.png')) { |
|||
return Image.asset( |
|||
asset, |
|||
width: size, |
|||
height: size, |
|||
fit: fit, |
|||
color: color, |
|||
); |
|||
} else { |
|||
return VectorGraphic( |
|||
loader: AssetBytesLoader(asset), |
|||
height: size, |
|||
fit: fit, |
|||
colorFilter: color == null |
|||
? null |
|||
: ColorFilter.mode(color!, BlendMode.srcIn), |
|||
); |
|||
} |
|||
}, |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
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/intro_params.dart'; |
|||
import 'package:shia_game_flutter/core/response/base_response.dart'; |
|||
import 'package:shia_game_flutter/features/intro/data/model/intro_model.dart'; |
|||
import 'package:shia_game_flutter/features/intro/domain/entity/intro_entity.dart'; |
|||
|
|||
abstract class IIntroDatasource { |
|||
Future<IntroEntity> getData({required IntroParams params}); |
|||
} |
|||
|
|||
class IntroDatasourceImpl implements IIntroDatasource { |
|||
final IHttpRequest httpRequest; |
|||
|
|||
const IntroDatasourceImpl(this.httpRequest); |
|||
|
|||
@override |
|||
Future<IntroEntity> getData({required IntroParams params}) async { |
|||
final response = await httpRequest.get( |
|||
path: MyApi.baseUrl, |
|||
); |
|||
|
|||
return BaseResponse.getData<IntroEntity>( |
|||
response?['data'], |
|||
(json) => IntroModel.fromJson(json), |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
import 'package:shia_game_flutter/features/intro/domain/entity/intro_entity.dart'; |
|||
|
|||
class IntroModel extends IntroEntity { |
|||
const IntroModel({ |
|||
super.id, |
|||
}); |
|||
|
|||
factory IntroModel.fromJson(Map<String, dynamic> json) { |
|||
return IntroModel( |
|||
id: json['id'], |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
import 'package:flutter/foundation.dart'; |
|||
import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; |
|||
import 'package:shia_game_flutter/core/params/intro_params.dart'; |
|||
import 'package:shia_game_flutter/core/utils/data_state.dart'; |
|||
import 'package:shia_game_flutter/features/intro/data/datasource/intro_datasource.dart'; |
|||
import 'package:shia_game_flutter/features/intro/domain/entity/intro_entity.dart'; |
|||
import 'package:shia_game_flutter/features/intro/domain/repository/intro_repository.dart'; |
|||
|
|||
class IntroRepositoryImpl implements IIntroRepository { |
|||
final IIntroDatasource datasource; |
|||
|
|||
const IntroRepositoryImpl(this.datasource); |
|||
|
|||
@override |
|||
Future<DataState<IntroEntity, MyException>> getData({required IntroParams params}) async { |
|||
try { |
|||
final IntroEntity 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')); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
import 'package:equatable/equatable.dart'; |
|||
|
|||
class IntroEntity extends Equatable { |
|||
final int? id; |
|||
|
|||
const IntroEntity({ |
|||
this.id, |
|||
}); |
|||
|
|||
@override |
|||
List<Object?> get props => [ |
|||
id, |
|||
]; |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; |
|||
import 'package:shia_game_flutter/core/params/intro_params.dart'; |
|||
import 'package:shia_game_flutter/core/utils/data_state.dart'; |
|||
import 'package:shia_game_flutter/features/intro/domain/entity/intro_entity.dart'; |
|||
|
|||
abstract class IIntroRepository { |
|||
Future<DataState<IntroEntity, MyException>> getData({required IntroParams params}); |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
import 'package:shia_game_flutter/core/error_handler/my_exception.dart'; |
|||
import 'package:shia_game_flutter/core/params/intro_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/intro/domain/entity/intro_entity.dart'; |
|||
import 'package:shia_game_flutter/features/intro/domain/repository/intro_repository.dart'; |
|||
|
|||
class GetIntroUseCase implements UseCase<IntroEntity, IntroParams> { |
|||
final IIntroRepository repository; |
|||
|
|||
const GetIntroUseCase(this.repository); |
|||
|
|||
@override |
|||
Future<DataState<IntroEntity, MyException>> call(IntroParams params) { |
|||
return repository.getData(params: params); |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,20 @@ |
|||
import 'package:shia_game_flutter/features/intro/presentation/controller/intro_controller.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
class IntroBinding extends Bindings { |
|||
@override |
|||
void dependencies() { |
|||
Get.put<IntroController>(IntroController(Get.find())); |
|||
} |
|||
|
|||
Future<void> deleteBindings() async { |
|||
await Future.wait([ |
|||
Get.delete<IntroController>(), |
|||
]); |
|||
} |
|||
|
|||
Future<void> refreshBinding() async { |
|||
await deleteBindings(); |
|||
dependencies(); |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
import 'package:flutter/cupertino.dart'; |
|||
import 'package:shia_game_flutter/core/params/intro_params.dart'; |
|||
import 'package:shia_game_flutter/core/status/base_status.dart'; |
|||
import 'package:shia_game_flutter/features/intro/domain/entity/intro_entity.dart'; |
|||
import 'package:shia_game_flutter/features/intro/domain/usecases/get_intro_usecase.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
class IntroController extends GetxController with StateMixin { |
|||
/// ----- Constructor ----- |
|||
IntroController(this.getIntroUseCase); |
|||
|
|||
@override |
|||
void onInit() { |
|||
super.onInit(); |
|||
change('', status: RxStatus.success()); |
|||
} |
|||
|
|||
@override |
|||
void onClose() { |
|||
textEditingController.dispose(); |
|||
super.onClose(); |
|||
} |
|||
|
|||
/// ----- UseCases ----- |
|||
final GetIntroUseCase getIntroUseCase; |
|||
|
|||
/// ----- Variables ----- |
|||
final Rx<IntroParams> introParams = Rx(IntroParams()); |
|||
final Rx<IntroEntity> introEntity = Rx(const IntroEntity()); |
|||
|
|||
/// ------ Controllers ------ |
|||
final TextEditingController textEditingController = TextEditingController(); |
|||
|
|||
/// ------ Statuses ------ |
|||
final Rx<BaseStatus> getIntroStatus = Rx(const BaseInit()); |
|||
|
|||
/// ------ Functions ------ |
|||
|
|||
/// ------ Api Calls ------ |
|||
Future<void> getIntro() async { |
|||
change('', status: RxStatus.loading()); |
|||
await getIntroUseCase(introParams.value).then( |
|||
(value) => value.fold( |
|||
(data) { |
|||
introEntity.value = data; |
|||
change('', status: RxStatus.success()); |
|||
}, |
|||
(error) { |
|||
change('', status: RxStatus.error(error.errorMessage)); |
|||
}, |
|||
), |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,99 @@ |
|||
import 'package:flutter/material.dart'; |
|||
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_spaces.dart'; |
|||
import 'package:shia_game_flutter/common_ui/resources/my_text_style.dart'; |
|||
import 'package:shia_game_flutter/common_ui/theme/my_theme.dart'; |
|||
import 'package:shia_game_flutter/core/utils/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/intro/presentation/controller/intro_controller.dart'; |
|||
import 'package:shia_game_flutter/features/intro/presentation/ui/widgets/intro_loading.dart'; |
|||
|
|||
class IntroPage extends GetView<IntroController> { |
|||
const IntroPage({super.key}); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Scaffold( |
|||
backgroundColor: context.introBackgroundColor, |
|||
body: SafeArea( |
|||
child: SizedBox.expand( |
|||
child: Stack( |
|||
alignment: Alignment.center, |
|||
children: [ |
|||
_logo(context), |
|||
_bottomLoading(context), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
); |
|||
} |
|||
|
|||
Stack _logo(BuildContext context) { |
|||
return Stack( |
|||
alignment: Alignment.center, |
|||
children: [ |
|||
PositionedDirectional( |
|||
top: context.heightScreen / 3.2, |
|||
end: 50, |
|||
child: MyImage(asset: MyAssets.question), |
|||
), |
|||
PositionedDirectional( |
|||
top: context.heightScreen / 3.5, |
|||
end: context.widthScreen / 2.4, |
|||
child: MyImage(asset: MyAssets.question, size: 30), |
|||
), |
|||
PositionedDirectional( |
|||
top: context.heightScreen / 2.8, |
|||
start: 80, |
|||
child: MyImage(asset: MyAssets.question, size: 24), |
|||
), |
|||
PositionedDirectional( |
|||
bottom: context.heightScreen / 3.2, |
|||
start: 80, |
|||
child: MyImage(asset: MyAssets.question), |
|||
), |
|||
PositionedDirectional( |
|||
bottom: context.heightScreen / 3.2, |
|||
end: 50, |
|||
child: MyImage(asset: MyAssets.question, size: 20), |
|||
), |
|||
PositionedDirectional( |
|||
bottom: context.heightScreen / 2.6, |
|||
start: context.widthScreen / 2, |
|||
child: MyImage(asset: MyAssets.question, size: 20), |
|||
), |
|||
Container( |
|||
width: context.widthScreen, |
|||
height: context.heightScreen, |
|||
decoration: ShapeDecoration( |
|||
gradient: RadialGradient( |
|||
colors: [const Color(0xFF321A6D), const Color(0x00160C30)], |
|||
), |
|||
shape: OvalBorder(), |
|||
), |
|||
), |
|||
MyImage(asset: MyAssets.shiaMind), |
|||
], |
|||
); |
|||
} |
|||
|
|||
Positioned _bottomLoading(BuildContext context) { |
|||
return Positioned( |
|||
bottom: MySpaces.s16, |
|||
child: Column( |
|||
spacing: MySpaces.s10, |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: [ |
|||
Text( |
|||
context.translate.loading, |
|||
style: Lexend.regular.copyWith(fontSize: MySpaces.s14), |
|||
), |
|||
IntroLoading(), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:shia_game_flutter/common_ui/resources/my_spaces.dart'; |
|||
|
|||
class IntroLoading extends StatelessWidget { |
|||
const IntroLoading({ |
|||
super.key, |
|||
}); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Container( |
|||
width: 188, |
|||
height: MySpaces.s16, |
|||
padding: EdgeInsetsDirectional.only( |
|||
start: MySpaces.s2, |
|||
top: MySpaces.s2, |
|||
bottom: MySpaces.s2, |
|||
end: MySpaces.s20, |
|||
), |
|||
decoration: ShapeDecoration( |
|||
shape: StadiumBorder( |
|||
side: BorderSide( |
|||
width: 1, |
|||
color: Color(0XFFA579EA), |
|||
), |
|||
), |
|||
), |
|||
child: Container( |
|||
height: MySpaces.s14, |
|||
decoration: ShapeDecoration( |
|||
shape: StadiumBorder( |
|||
side: BorderSide( |
|||
width: 1, |
|||
color: Colors.white.withValues(alpha: 0.5), |
|||
), |
|||
), |
|||
gradient: LinearGradient( |
|||
begin: AlignmentDirectional.centerStart, |
|||
end: AlignmentDirectional.centerEnd, |
|||
colors: [ |
|||
Color(0XFF9C7EEC), |
|||
Color(0XFF3BBDFF), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
); |
|||
} |
|||
} |
|||
@ -1,3 +1,4 @@ |
|||
{ |
|||
"@@locale": "en" |
|||
"@@locale": "en", |
|||
"loading": "Loading..." |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue