feature/database
#9
Merged
amirreza.chegini
merged 13 commits from feature/database
into develop
7 days ago
58 changed files with 2729 additions and 287 deletions
-
1181assets/json/levels.json
-
2lib/common_ui/resources/my_assets.dart
-
8lib/common_ui/resources/my_text_style.dart
-
1lib/core/constants/my_constants.dart
-
2lib/core/middleware/auth_middleware.dart
-
13lib/core/params/home_params.dart
-
13lib/core/params/intro_params.dart
-
1lib/core/params/no_params.dart
-
18lib/core/routers/my_routes.dart
-
11lib/core/utils/my_scroll_behavior.dart
-
2lib/core/widgets/answer_box/styles/picture_box.dart
-
28lib/features/home/data/datasource/home_datasource.dart
-
13lib/features/home/data/model/home_model.dart
-
29lib/features/home/data/repository_impl/home_repository_impl.dart
-
4lib/features/home/domain/entity/home_entity.dart
-
8lib/features/home/domain/repository/home_repository.dart
-
17lib/features/home/domain/usecases/get_home_usecase.dart
-
47lib/features/home/presentation/bloc/home_bloc.dart
-
5lib/features/home/presentation/bloc/home_event.dart
-
15lib/features/home/presentation/bloc/home_state.dart
-
93lib/features/home/presentation/ui/home_page.dart
-
95lib/features/intro/data/datasource/intro_datasource.dart
-
13lib/features/intro/data/model/intro_model.dart
-
30lib/features/intro/data/repository_impl/intro_repository_impl.dart
-
7lib/features/intro/domain/repository/intro_repository.dart
-
16lib/features/intro/domain/usecases/extract_data_usecase.dart
-
17lib/features/intro/domain/usecases/get_intro_usecase.dart
-
11lib/features/intro/domain/usecases/loading_stream_usecase.dart
-
16lib/features/intro/domain/usecases/save_levels_usecase.dart
-
59lib/features/intro/presentation/bloc/intro_bloc.dart
-
3lib/features/intro/presentation/bloc/intro_event.dart
-
110lib/features/intro/presentation/ui/intro_page.dart
-
138lib/features/intro/presentation/ui/widgets/intro_loading_widget.dart
-
31lib/features/level/data/datasource/level_datasource.dart
-
12lib/features/level/data/model/level_model.dart
-
10lib/features/level/data/repository_impl/level_repository_impl.dart
-
29lib/features/level/domain/entity/level_entity.dart
-
50lib/features/level/domain/entity/level_entity.g.dart
-
4lib/features/level/domain/entity/level_location.dart
-
2lib/features/level/domain/repository/level_repository.dart
-
6lib/features/level/domain/usecases/get_level_usecase.dart
-
77lib/features/level/presentation/bloc/level_bloc.dart
-
2lib/features/level/presentation/bloc/level_event.dart
-
79lib/features/level/presentation/ui/level_page.dart
-
2lib/features/level/presentation/ui/widgets/level_widget.dart
-
26lib/features/question/data/model/answer_model.dart
-
17lib/features/question/data/model/file_model.dart
-
23lib/features/question/data/model/question_model.dart
-
29lib/features/question/domain/entity/answer_entity.dart
-
56lib/features/question/domain/entity/answer_entity.g.dart
-
19lib/features/question/domain/entity/file_entity.dart
-
47lib/features/question/domain/entity/file_entity.g.dart
-
40lib/features/question/domain/entity/question_entity.dart
-
62lib/features/question/domain/entity/question_entity.g.dart
-
40lib/init_bindings.dart
-
3lib/main.dart
-
314pubspec.lock
-
10pubspec.yaml
1181
assets/json/levels.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,13 @@ |
|||||
|
class HomeParams { |
||||
|
int? id; |
||||
|
|
||||
|
HomeParams({this.id}); |
||||
|
|
||||
|
HomeParams copyWith({ |
||||
|
int? id, |
||||
|
}) { |
||||
|
return HomeParams( |
||||
|
id: id ?? this.id, |
||||
|
); |
||||
|
} |
||||
|
} |
@ -1,13 +0,0 @@ |
|||||
class IntroParams { |
|
||||
int? id; |
|
||||
|
|
||||
IntroParams({this.id}); |
|
||||
|
|
||||
IntroParams copyWith({ |
|
||||
int? id, |
|
||||
}) { |
|
||||
return IntroParams( |
|
||||
id: id ?? this.id, |
|
||||
); |
|
||||
} |
|
||||
} |
|
@ -0,0 +1 @@ |
|||||
|
class NoParams {} |
@ -1,11 +0,0 @@ |
|||||
import 'package:flutter/gestures.dart'; |
|
||||
import 'package:flutter/material.dart'; |
|
||||
|
|
||||
class MyScrollBehavior extends ScrollBehavior { |
|
||||
@override |
|
||||
Set<PointerDeviceKind> get dragDevices => { |
|
||||
PointerDeviceKind.touch, |
|
||||
PointerDeviceKind.mouse, |
|
||||
PointerDeviceKind.trackpad, |
|
||||
}; |
|
||||
} |
|
@ -0,0 +1,28 @@ |
|||||
|
import 'package:hadi_hoda_flutter/core/constants/my_api.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/network/http_request.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/params/home_params.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/response/base_response.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/data/model/home_model.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/entity/home_entity.dart'; |
||||
|
|
||||
|
abstract class IHomeDatasource { |
||||
|
Future<HomeEntity> getData({required HomeParams params}); |
||||
|
} |
||||
|
|
||||
|
class HomeDatasourceImpl implements IHomeDatasource { |
||||
|
final IHttpRequest httpRequest; |
||||
|
|
||||
|
const HomeDatasourceImpl(this.httpRequest); |
||||
|
|
||||
|
@override |
||||
|
Future<HomeEntity> getData({required HomeParams params}) async { |
||||
|
final response = await httpRequest.get( |
||||
|
path: MyApi.baseUrl, |
||||
|
); |
||||
|
|
||||
|
return BaseResponse.getData<HomeEntity>( |
||||
|
response?['data'], |
||||
|
(json) => HomeModel.fromJson(json), |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
import 'package:hadi_hoda_flutter/features/home/domain/entity/home_entity.dart'; |
||||
|
|
||||
|
class HomeModel extends HomeEntity { |
||||
|
const HomeModel({ |
||||
|
super.id, |
||||
|
}); |
||||
|
|
||||
|
factory HomeModel.fromJson(Map<String, dynamic> json) { |
||||
|
return HomeModel( |
||||
|
id: json['id'], |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
import 'package:hadi_hoda_flutter/core/params/home_params.dart'; |
||||
|
import 'package:flutter/foundation.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/data/datasource/home_datasource.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/entity/home_entity.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/repository/home_repository.dart'; |
||||
|
|
||||
|
class HomeRepositoryImpl implements IHomeRepository { |
||||
|
final IHomeDatasource datasource; |
||||
|
|
||||
|
const HomeRepositoryImpl(this.datasource); |
||||
|
|
||||
|
@override |
||||
|
Future<DataState<HomeEntity, MyException>> getData({required HomeParams params}) async { |
||||
|
try { |
||||
|
final HomeEntity 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')); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,9 +1,9 @@ |
|||||
import 'package:equatable/equatable.dart'; |
import 'package:equatable/equatable.dart'; |
||||
|
|
||||
class IntroEntity extends Equatable { |
|
||||
|
class HomeEntity extends Equatable { |
||||
final int? id; |
final int? id; |
||||
|
|
||||
const IntroEntity({ |
|
||||
|
const HomeEntity({ |
||||
this.id, |
this.id, |
||||
}); |
}); |
||||
|
|
@ -0,0 +1,8 @@ |
|||||
|
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/params/home_params.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/entity/home_entity.dart'; |
||||
|
|
||||
|
abstract class IHomeRepository { |
||||
|
Future<DataState<HomeEntity, MyException>> getData({required HomeParams params}); |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/params/home_params.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/usecase/usecase.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/entity/home_entity.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/repository/home_repository.dart'; |
||||
|
|
||||
|
class GetHomeUseCase implements UseCase<HomeEntity, HomeParams> { |
||||
|
final IHomeRepository repository; |
||||
|
|
||||
|
const GetHomeUseCase(this.repository); |
||||
|
|
||||
|
@override |
||||
|
Future<DataState<HomeEntity, MyException>> call(HomeParams params) { |
||||
|
return repository.getData(params: params); |
||||
|
} |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
import 'dart:async'; |
||||
|
import 'package:bloc/bloc.dart'; |
||||
|
import 'package:flutter/cupertino.dart'; |
||||
|
import 'package:go_router/go_router.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/status/base_status.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/entity/home_entity.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/domain/usecases/get_home_usecase.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_event.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_state.dart'; |
||||
|
|
||||
|
class HomeBloc extends Bloc<HomeEvent, HomeState> { |
||||
|
/// ------------constructor------------ |
||||
|
HomeBloc( |
||||
|
this._getHomeUseCase, |
||||
|
) : super(const HomeState()) { |
||||
|
on<GetHomeEvent>(_getHomeEvent); |
||||
|
} |
||||
|
|
||||
|
/// ------------UseCases------------ |
||||
|
final GetHomeUseCase _getHomeUseCase; |
||||
|
|
||||
|
/// ------------Variables------------ |
||||
|
|
||||
|
/// ------------Controllers------------ |
||||
|
|
||||
|
/// ------------Functions------------ |
||||
|
void goToLevelPage(BuildContext context){ |
||||
|
context.pushNamed(Routes.levelPage); |
||||
|
} |
||||
|
|
||||
|
/// ------------Api Calls------------ |
||||
|
FutureOr<void> _getHomeEvent(event, emit) async { |
||||
|
await _getHomeUseCase(event.homeParams).then( |
||||
|
(value) { |
||||
|
value.fold( |
||||
|
(data) { |
||||
|
emit(state.copyWith(getHomeStatus: BaseComplete<HomeEntity>(data))); |
||||
|
}, |
||||
|
(error) { |
||||
|
emit(state.copyWith(getHomeStatus: BaseError(error.errorMessage))); |
||||
|
}, |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
sealed class HomeEvent { |
||||
|
const HomeEvent(); |
||||
|
} |
||||
|
|
||||
|
class GetHomeEvent extends HomeEvent {} |
@ -0,0 +1,15 @@ |
|||||
|
import 'package:hadi_hoda_flutter/core/status/base_status.dart'; |
||||
|
|
||||
|
class HomeState { |
||||
|
final BaseStatus getHomeStatus; |
||||
|
|
||||
|
const HomeState({this.getHomeStatus = const BaseInit()}); |
||||
|
|
||||
|
HomeState copyWith({ |
||||
|
BaseStatus? getHomeStatus, |
||||
|
}) { |
||||
|
return HomeState( |
||||
|
getHomeStatus: getHomeStatus ?? this.getHomeStatus, |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_bloc/flutter_bloc.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/check_platform.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/my_image.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_bloc.dart'; |
||||
|
|
||||
|
class HomePage extends StatelessWidget { |
||||
|
const HomePage({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Scaffold( |
||||
|
appBar: AppBar(backgroundColor: context.noColor), |
||||
|
extendBodyBehindAppBar: true, |
||||
|
body: DecoratedBox( |
||||
|
decoration: BoxDecoration( |
||||
|
image: DecorationImage( |
||||
|
image: AssetImage(MyAssets.backgroundHome), |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
), |
||||
|
child: SizedBox( |
||||
|
width: context.widthScreen, |
||||
|
height: context.heightScreen, |
||||
|
child: Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [ |
||||
|
_music(context), |
||||
|
_name(context), |
||||
|
_bottomBtns(context), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Positioned _music(BuildContext context) { |
||||
|
return Positioned( |
||||
|
top: checkSize(context: context, mobile: 36, tablet: 60), |
||||
|
right: checkSize(context: context, mobile: 16, tablet: 30), |
||||
|
child: MyImage( |
||||
|
image: MyAssets.musicOn, |
||||
|
size: checkSize(context: context, tablet: 120), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Positioned _name(BuildContext context) { |
||||
|
return Positioned( |
||||
|
top: 146, |
||||
|
child: MyImage( |
||||
|
image: MyAssets.hadiHoda, |
||||
|
size: checkSize(context: context, mobile: 232, tablet: 400), |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Positioned _bottomBtns(BuildContext context) { |
||||
|
return Positioned( |
||||
|
bottom: checkSize(context: context, mobile: 40, tablet: 60), |
||||
|
left: checkSize(context: context, mobile: 16, tablet: 30), |
||||
|
right: checkSize(context: context, mobile: 16, tablet: 30), |
||||
|
child: Row( |
||||
|
crossAxisAlignment: CrossAxisAlignment.end, |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
MyImage( |
||||
|
image: MyAssets.language, |
||||
|
size: checkSize(context: context, tablet: 120), |
||||
|
), |
||||
|
InkWell( |
||||
|
child: MyImage( |
||||
|
image: MyAssets.start, |
||||
|
size: checkSize(context: context, mobile: 90, tablet: 160), |
||||
|
), |
||||
|
onTap: () => |
||||
|
BlocProvider.of<HomeBloc>(context).goToLevelPage(context), |
||||
|
), |
||||
|
MyImage( |
||||
|
image: MyAssets.theme, |
||||
|
size: checkSize(context: context, tablet: 120), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
@ -1,28 +1,93 @@ |
|||||
import 'package:hadi_hoda_flutter/core/constants/my_api.dart'; |
|
||||
|
import 'dart:async'; |
||||
|
import 'dart:convert'; |
||||
|
import 'dart:io'; |
||||
|
|
||||
|
import 'package:flutter/services.dart'; |
||||
|
import 'package:flutter_archive/flutter_archive.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
import 'package:hadi_hoda_flutter/core/network/http_request.dart'; |
import 'package:hadi_hoda_flutter/core/network/http_request.dart'; |
||||
import 'package:hadi_hoda_flutter/core/params/intro_params.dart'; |
|
||||
import 'package:hadi_hoda_flutter/core/response/base_response.dart'; |
import 'package:hadi_hoda_flutter/core/response/base_response.dart'; |
||||
import 'package:hadi_hoda_flutter/features/intro/data/model/intro_model.dart'; |
|
||||
import 'package:hadi_hoda_flutter/features/intro/domain/entity/intro_entity.dart'; |
|
||||
|
import 'package:hadi_hoda_flutter/features/level/data/model/level_model.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; |
||||
|
import 'package:hive/hive.dart'; |
||||
|
import 'package:path_provider/path_provider.dart'; |
||||
|
|
||||
abstract class IIntroDatasource { |
abstract class IIntroDatasource { |
||||
Future<IntroEntity> getData({required IntroParams params}); |
|
||||
|
Future<void> saveLevels(); |
||||
|
Future<void> extractData(); |
||||
|
Stream<double> loadingStream(); |
||||
} |
} |
||||
|
|
||||
class IntroDatasourceImpl implements IIntroDatasource { |
class IntroDatasourceImpl implements IIntroDatasource { |
||||
final IHttpRequest httpRequest; |
final IHttpRequest httpRequest; |
||||
|
final StreamController<double> streamController = StreamController<double>.broadcast(); |
||||
|
|
||||
const IntroDatasourceImpl(this.httpRequest); |
|
||||
|
IntroDatasourceImpl(this.httpRequest); |
||||
|
|
||||
@override |
@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), |
|
||||
); |
|
||||
|
Future<void> saveLevels() async { |
||||
|
try { |
||||
|
final Box<LevelEntity> levelBox = Hive.box(MyConstants.levelBox); |
||||
|
if (levelBox.isEmpty) { |
||||
|
final String levelAssets = await rootBundle.loadString( |
||||
|
'assets/json/levels.json', |
||||
|
); |
||||
|
final dynamic response = jsonDecode(levelAssets); |
||||
|
final List<LevelEntity> levelList = BaseResponse.getDataList<LevelEntity>( |
||||
|
response?['result'], |
||||
|
(json) => LevelModel.fromJson(json), |
||||
|
); |
||||
|
|
||||
|
await levelBox.addAll(levelList); |
||||
|
} |
||||
|
} catch (e) { |
||||
|
throw MyException(errorMessage: '$e'); |
||||
|
} |
||||
} |
} |
||||
|
|
||||
|
@override |
||||
|
Future<void> extractData() async { |
||||
|
try { |
||||
|
final Directory dir = await getApplicationDocumentsDirectory(); |
||||
|
final File file = File('${dir.path}/data.zip'); |
||||
|
if (!(await file.exists())) { |
||||
|
final ByteData assetFile = await rootBundle.load('assets/data/data.zip'); |
||||
|
await file.create(recursive: true); |
||||
|
await file.writeAsBytes( |
||||
|
assetFile.buffer.asUint8List( |
||||
|
assetFile.offsetInBytes, |
||||
|
assetFile.lengthInBytes, |
||||
|
), |
||||
|
flush: true, |
||||
|
); |
||||
|
|
||||
|
await ZipFile.extractToDirectory( |
||||
|
zipFile: file, |
||||
|
destinationDir: dir, |
||||
|
onExtracting: (zipEntry, progress) { |
||||
|
streamController.add(progress); |
||||
|
return ZipFileOperation.includeItem; |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
} else { |
||||
|
streamController.add(20); |
||||
|
await Future.delayed(Duration(milliseconds: 150)); |
||||
|
streamController.add(40); |
||||
|
await Future.delayed(Duration(milliseconds: 150)); |
||||
|
streamController.add(60); |
||||
|
await Future.delayed(Duration(milliseconds: 150)); |
||||
|
streamController.add(80); |
||||
|
await Future.delayed(Duration(milliseconds: 150)); |
||||
|
streamController.add(100); |
||||
|
await Future.delayed(Duration(milliseconds: 150)); |
||||
|
} |
||||
|
} catch (e) { |
||||
|
throw MyException(errorMessage: '$e'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Stream<double> loadingStream() => streamController.stream; |
||||
} |
} |
@ -1,13 +0,0 @@ |
|||||
import 'package:hadi_hoda_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'], |
|
||||
); |
|
||||
} |
|
||||
} |
|
@ -1,8 +1,9 @@ |
|||||
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
import 'package:hadi_hoda_flutter/core/params/intro_params.dart'; |
|
||||
|
import 'package:hadi_hoda_flutter/core/params/no_params.dart'; |
||||
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
||||
import 'package:hadi_hoda_flutter/features/intro/domain/entity/intro_entity.dart'; |
|
||||
|
|
||||
abstract class IIntroRepository { |
abstract class IIntroRepository { |
||||
Future<DataState<IntroEntity, MyException>> getData({required IntroParams params}); |
|
||||
|
Future<DataState<NoParams, MyException>> saveLevels(); |
||||
|
Future<DataState<NoParams, MyException>> extractData(); |
||||
|
Stream<double> loadingStream(); |
||||
} |
} |
@ -0,0 +1,16 @@ |
|||||
|
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/params/no_params.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/usecase/usecase.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart'; |
||||
|
|
||||
|
class ExtractDataUseCase implements UseCase<NoParams, NoParams> { |
||||
|
final IIntroRepository repository; |
||||
|
|
||||
|
const ExtractDataUseCase(this.repository); |
||||
|
|
||||
|
@override |
||||
|
Future<DataState<NoParams, MyException>> call(NoParams params) { |
||||
|
return repository.extractData(); |
||||
|
} |
||||
|
} |
@ -1,17 +0,0 @@ |
|||||
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
|
||||
import 'package:hadi_hoda_flutter/core/params/intro_params.dart'; |
|
||||
import 'package:hadi_hoda_flutter/core/usecase/usecase.dart'; |
|
||||
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
|
||||
import 'package:hadi_hoda_flutter/features/intro/domain/entity/intro_entity.dart'; |
|
||||
import 'package:hadi_hoda_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,11 @@ |
|||||
|
import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart'; |
||||
|
|
||||
|
class LoadingStreamUseCase { |
||||
|
final IIntroRepository repository; |
||||
|
|
||||
|
const LoadingStreamUseCase(this.repository); |
||||
|
|
||||
|
Stream<double> call() { |
||||
|
return repository.loadingStream(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/params/no_params.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/usecase/usecase.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/utils/data_state.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart'; |
||||
|
|
||||
|
class SaveLevelsUseCase implements UseCase<NoParams, NoParams> { |
||||
|
final IIntroRepository repository; |
||||
|
|
||||
|
const SaveLevelsUseCase(this.repository); |
||||
|
|
||||
|
@override |
||||
|
Future<DataState<NoParams, MyException>> call(NoParams params) { |
||||
|
return repository.saveLevels(); |
||||
|
} |
||||
|
} |
@ -1,93 +1,65 @@ |
|||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||
import 'package:go_router/go_router.dart'; |
|
||||
|
import 'package:flutter_bloc/flutter_bloc.dart'; |
||||
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
import 'package:hadi_hoda_flutter/common_ui/resources/my_assets.dart'; |
||||
import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart'; |
|
||||
import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; |
|
||||
import 'package:hadi_hoda_flutter/core/utils/check_platform.dart'; |
|
||||
import 'package:hadi_hoda_flutter/core/utils/my_image.dart'; |
import 'package:hadi_hoda_flutter/core/utils/my_image.dart'; |
||||
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_bloc.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_event.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/intro/presentation/ui/widgets/intro_loading_widget.dart'; |
||||
|
|
||||
class IntroPage extends StatelessWidget { |
|
||||
|
class IntroPage extends StatefulWidget { |
||||
const IntroPage({super.key}); |
const IntroPage({super.key}); |
||||
|
|
||||
|
@override |
||||
|
State<IntroPage> createState() => _IntroPageState(); |
||||
|
} |
||||
|
|
||||
|
class _IntroPageState extends State<IntroPage> { |
||||
|
|
||||
|
@override |
||||
|
void initState() { |
||||
|
super.initState(); |
||||
|
context.read<IntroBloc>().add(SaveLevelsEvent()); |
||||
|
} |
||||
|
|
||||
@override |
@override |
||||
Widget build(BuildContext context) { |
Widget build(BuildContext context) { |
||||
return Scaffold( |
return Scaffold( |
||||
appBar: AppBar(backgroundColor: context.noColor), |
|
||||
extendBodyBehindAppBar: true, |
|
||||
body: DecoratedBox( |
|
||||
|
body: Container( |
||||
|
height: context.heightScreen, |
||||
|
width: context.widthScreen, |
||||
decoration: BoxDecoration( |
decoration: BoxDecoration( |
||||
|
gradient: LinearGradient( |
||||
|
begin: Alignment.topCenter, |
||||
|
end: Alignment.bottomCenter, |
||||
|
colors: [Color(0XFF00154C), Color(0XFF150532)], |
||||
|
), |
||||
image: DecorationImage( |
image: DecorationImage( |
||||
image: AssetImage(MyAssets.backgroundIntro), |
|
||||
fit: BoxFit.cover, |
|
||||
|
image: AssetImage(MyAssets.pattern), |
||||
|
scale: 3, |
||||
|
repeat: ImageRepeat.repeat, |
||||
|
colorFilter: ColorFilter.mode( |
||||
|
Colors.white.withValues(alpha: 0.2), |
||||
|
BlendMode.srcIn, |
||||
|
), |
||||
), |
), |
||||
), |
), |
||||
child: SizedBox( |
|
||||
width: context.widthScreen, |
|
||||
height: context.heightScreen, |
|
||||
child: Stack( |
|
||||
alignment: Alignment.center, |
|
||||
children: [ |
|
||||
_music(context), |
|
||||
_name(context), |
|
||||
_bottomBtns(context), |
|
||||
], |
|
||||
), |
|
||||
|
child: Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [_image(), _loading(context)], |
||||
), |
), |
||||
), |
), |
||||
); |
); |
||||
} |
} |
||||
|
|
||||
Positioned _music(BuildContext context) { |
|
||||
return Positioned( |
|
||||
top: checkSize(context: context, mobile: 36, tablet: 60), |
|
||||
right: checkSize(context: context, mobile: 16, tablet: 30), |
|
||||
child: MyImage( |
|
||||
image: MyAssets.musicOn, |
|
||||
size: checkSize(context: context, tablet: 120), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
Positioned _name(BuildContext context) { |
|
||||
return Positioned( |
|
||||
top: 146, |
|
||||
child: MyImage( |
|
||||
image: MyAssets.hadiHoda, |
|
||||
size: checkSize(context: context, mobile: 232, tablet: 400), |
|
||||
fit: BoxFit.cover, |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
MyImage _image() => MyImage(image: MyAssets.hadiHoda, size: 200); |
||||
|
|
||||
Positioned _bottomBtns(BuildContext context) { |
|
||||
|
Positioned _loading(BuildContext context) { |
||||
return Positioned( |
return Positioned( |
||||
bottom: checkSize(context: context, mobile: 40, tablet: 60), |
|
||||
left: checkSize(context: context, mobile: 16, tablet: 30), |
|
||||
right: checkSize(context: context, mobile: 16, tablet: 30), |
|
||||
child: Row( |
|
||||
crossAxisAlignment: CrossAxisAlignment.end, |
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
||||
children: [ |
|
||||
MyImage( |
|
||||
image: MyAssets.language, |
|
||||
size: checkSize(context: context, tablet: 120), |
|
||||
), |
|
||||
InkWell( |
|
||||
child: MyImage( |
|
||||
image: MyAssets.start, |
|
||||
size: checkSize(context: context, mobile: 90, tablet: 160), |
|
||||
), |
|
||||
onTap: () { |
|
||||
context.goNamed(Routes.questionPage); |
|
||||
}, |
|
||||
), |
|
||||
MyImage( |
|
||||
image: MyAssets.theme, |
|
||||
size: checkSize(context: context, tablet: 120), |
|
||||
), |
|
||||
], |
|
||||
|
bottom: MediaQuery.viewPaddingOf(context).bottom, |
||||
|
child: IntroLoadingWidget( |
||||
|
percent: 80, |
||||
|
loadingStream: context.read<IntroBloc>().loadingStream, |
||||
), |
), |
||||
); |
); |
||||
} |
} |
||||
|
@ -0,0 +1,138 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart'; |
||||
|
import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; |
||||
|
|
||||
|
|
||||
|
class IntroLoadingWidget extends StatelessWidget { |
||||
|
const IntroLoadingWidget({ |
||||
|
super.key, |
||||
|
this.percent, |
||||
|
this.loadingStream, |
||||
|
}); |
||||
|
|
||||
|
final double? percent; |
||||
|
final Stream<double>? loadingStream; |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return ClipPath( |
||||
|
clipper: BubbleClip(), |
||||
|
child: Container( |
||||
|
width: 300, |
||||
|
height: 60, |
||||
|
padding: EdgeInsets.symmetric( |
||||
|
vertical: MySpaces.s4, |
||||
|
horizontal: MySpaces.s2, |
||||
|
), |
||||
|
decoration: const BoxDecoration( |
||||
|
gradient: LinearGradient( |
||||
|
begin: Alignment(0, 1), // bottom |
||||
|
end: Alignment(0, -1), // top |
||||
|
colors: [ |
||||
|
Color(0xFFCADCFF), // #CADCFF |
||||
|
Colors.white, // #FFFFFF |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
child: StreamBuilder<double>( |
||||
|
initialData: 0, |
||||
|
stream: loadingStream, |
||||
|
builder: (context, snapshot) { |
||||
|
print(snapshot.data); |
||||
|
return Row( |
||||
|
children: [ |
||||
|
Expanded( |
||||
|
flex: 85, |
||||
|
child: ClipPath( |
||||
|
clipper: BubbleClip(), |
||||
|
child: AnimatedContainer( |
||||
|
duration: const Duration(milliseconds: 300), |
||||
|
padding: EdgeInsetsDirectional.only( |
||||
|
end: 260 - ((snapshot.data ?? 0) * 260 / 100), |
||||
|
), |
||||
|
decoration: BoxDecoration( |
||||
|
color: Color(0xFF1F59BD).withValues(alpha: 0.25), |
||||
|
), |
||||
|
child: ClipPath( |
||||
|
clipper: BubbleClip(), |
||||
|
child: Container( |
||||
|
decoration: BoxDecoration( |
||||
|
gradient: RadialGradient( |
||||
|
radius: 2, |
||||
|
colors: [ |
||||
|
Color(0xFFFFBD00), // #CADCFF |
||||
|
Color(0xFFFF772C), // #CADCFF |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Expanded( |
||||
|
flex: 15, |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
'${snapshot.data?.toInt() ?? 0}%', |
||||
|
style: MyTextStyle.normal17.copyWith( |
||||
|
color: Color(0XFF6E83A8), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class BubbleClip extends CustomClipper<Path> { |
||||
|
@override |
||||
|
Path getClip(Size size) { |
||||
|
// Original SVG viewBox: 334 x 60 |
||||
|
const double w0 = 334.0; |
||||
|
const double h0 = 60.0; |
||||
|
final sx = size.width / w0; |
||||
|
final sy = size.height / h0; |
||||
|
|
||||
|
// SVG path: |
||||
|
// M9.82057 10.3597 |
||||
|
// C -1.70838 17.1589 -3.47995 44.4301 6.60447 53.1719 |
||||
|
// C 16.0075 61.291 305.076 61.9385 323.201 53.4956 |
||||
|
// C 341.326 45.0527 332.116 8.04571 324.829 5.7273 |
||||
|
// C 307.985 -2.06805 28.6539 -0.77294 9.82057 10.3597 |
||||
|
// Z |
||||
|
final p = Path() |
||||
|
..moveTo(9.82057 * sx, 10.3597 * sy) |
||||
|
..cubicTo( |
||||
|
-1.70838 * sx, 17.1589 * sy, |
||||
|
-3.47995 * sx, 44.4301 * sy, |
||||
|
6.60447 * sx, 53.1719 * sy, |
||||
|
) |
||||
|
..cubicTo( |
||||
|
16.0075 * sx, 61.291 * sy, |
||||
|
305.076 * sx, 61.9385 * sy, |
||||
|
323.201 * sx, 53.4956 * sy, |
||||
|
) |
||||
|
..cubicTo( |
||||
|
341.326 * sx, 45.0527 * sy, |
||||
|
332.116 * sx, 8.04571 * sy, |
||||
|
324.829 * sx, 5.7273 * sy, |
||||
|
) |
||||
|
..cubicTo( |
||||
|
307.985 * sx, -2.06805 * sy, |
||||
|
28.6539 * sx, -0.77294 * sy, |
||||
|
9.82057 * sx, 10.3597 * sy, |
||||
|
) |
||||
|
..close(); |
||||
|
|
||||
|
return p; |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false; |
||||
|
} |
@ -1,28 +1,49 @@ |
|||||
import 'package:hadi_hoda_flutter/core/constants/my_api.dart'; |
import 'package:hadi_hoda_flutter/core/constants/my_api.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; |
||||
|
import 'package:hadi_hoda_flutter/core/error_handler/my_exception.dart'; |
||||
import 'package:hadi_hoda_flutter/core/network/http_request.dart'; |
import 'package:hadi_hoda_flutter/core/network/http_request.dart'; |
||||
import 'package:hadi_hoda_flutter/core/params/level_params.dart'; |
import 'package:hadi_hoda_flutter/core/params/level_params.dart'; |
||||
import 'package:hadi_hoda_flutter/core/response/base_response.dart'; |
import 'package:hadi_hoda_flutter/core/response/base_response.dart'; |
||||
import 'package:hadi_hoda_flutter/features/level/data/model/level_model.dart'; |
import 'package:hadi_hoda_flutter/features/level/data/model/level_model.dart'; |
||||
import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; |
import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; |
||||
|
import 'package:hive/hive.dart'; |
||||
|
|
||||
abstract class ILevelDatasource { |
abstract class ILevelDatasource { |
||||
Future<LevelEntity> getData({required LevelParams params}); |
|
||||
|
Future<List<LevelEntity>> getLevels({required LevelParams params}); |
||||
} |
} |
||||
|
|
||||
class LevelDatasourceImpl implements ILevelDatasource { |
|
||||
|
/// Remote |
||||
|
class RemoteLevelDatasourceImpl implements ILevelDatasource { |
||||
final IHttpRequest httpRequest; |
final IHttpRequest httpRequest; |
||||
|
|
||||
const LevelDatasourceImpl(this.httpRequest); |
|
||||
|
const RemoteLevelDatasourceImpl(this.httpRequest); |
||||
|
|
||||
@override |
@override |
||||
Future<LevelEntity> getData({required LevelParams params}) async { |
|
||||
|
Future<List<LevelEntity>> getLevels({required LevelParams params}) async { |
||||
final response = await httpRequest.get( |
final response = await httpRequest.get( |
||||
path: MyApi.baseUrl, |
path: MyApi.baseUrl, |
||||
); |
); |
||||
|
|
||||
return BaseResponse.getData<LevelEntity>( |
|
||||
|
return BaseResponse.getDataList<LevelEntity>( |
||||
response?['data'], |
response?['data'], |
||||
(json) => LevelModel.fromJson(json), |
(json) => LevelModel.fromJson(json), |
||||
); |
); |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
|
||||
|
/// Local |
||||
|
class LocalLevelDatasourceImpl implements ILevelDatasource { |
||||
|
|
||||
|
const LocalLevelDatasourceImpl(); |
||||
|
|
||||
|
@override |
||||
|
Future<List<LevelEntity>> getLevels({required LevelParams params}) async { |
||||
|
try { |
||||
|
final Box<LevelEntity> levelBox = Hive.box(MyConstants.levelBox); |
||||
|
return levelBox.values.toList(); |
||||
|
} catch (_) { |
||||
|
throw MyException(errorMessage: 'Operation Failed'); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,13 +1,23 @@ |
|||||
import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; |
import 'package:hadi_hoda_flutter/features/level/domain/entity/level_entity.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/question/data/model/question_model.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart'; |
||||
|
|
||||
class LevelModel extends LevelEntity { |
class LevelModel extends LevelEntity { |
||||
const LevelModel({ |
|
||||
|
LevelModel({ |
||||
super.id, |
super.id, |
||||
|
super.order, |
||||
|
super.title, |
||||
|
super.questions, |
||||
}); |
}); |
||||
|
|
||||
factory LevelModel.fromJson(Map<String, dynamic> json) { |
factory LevelModel.fromJson(Map<String, dynamic> json) { |
||||
return LevelModel( |
return LevelModel( |
||||
id: json['id'], |
id: json['id'], |
||||
|
order: json['order'], |
||||
|
title: json['title'], |
||||
|
questions: json['questions'] |
||||
|
?.map<QuestionEntity>((e) => QuestionModel.fromJson(e)) |
||||
|
.toList(), |
||||
); |
); |
||||
} |
} |
||||
} |
} |
@ -1,14 +1,23 @@ |
|||||
import 'package:equatable/equatable.dart'; |
|
||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart'; |
||||
|
import 'package:hive/hive.dart'; |
||||
|
|
||||
class LevelEntity extends Equatable { |
|
||||
final int? id; |
|
||||
|
part 'level_entity.g.dart'; |
||||
|
|
||||
const LevelEntity({ |
|
||||
this.id, |
|
||||
}); |
|
||||
|
@HiveType(typeId: 0) |
||||
|
class LevelEntity extends HiveObject { |
||||
|
@HiveField(0) |
||||
|
int? id; |
||||
|
@HiveField(1) |
||||
|
int? order; |
||||
|
@HiveField(2) |
||||
|
String? title; |
||||
|
@HiveField(3) |
||||
|
List<QuestionEntity>? questions; |
||||
|
|
||||
@override |
|
||||
List<Object?> get props => [ |
|
||||
id, |
|
||||
]; |
|
||||
|
LevelEntity({ |
||||
|
this.id, |
||||
|
this.order, |
||||
|
this.title, |
||||
|
this.questions, |
||||
|
}); |
||||
} |
} |
@ -0,0 +1,50 @@ |
|||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
|
||||
|
part of 'level_entity.dart'; |
||||
|
|
||||
|
// ************************************************************************** |
||||
|
// TypeAdapterGenerator |
||||
|
// ************************************************************************** |
||||
|
|
||||
|
class LevelEntityAdapter extends TypeAdapter<LevelEntity> { |
||||
|
@override |
||||
|
final int typeId = 0; |
||||
|
|
||||
|
@override |
||||
|
LevelEntity read(BinaryReader reader) { |
||||
|
final numOfFields = reader.readByte(); |
||||
|
final fields = <int, dynamic>{ |
||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), |
||||
|
}; |
||||
|
return LevelEntity( |
||||
|
id: fields[0] as int?, |
||||
|
order: fields[1] as int?, |
||||
|
title: fields[2] as String?, |
||||
|
questions: (fields[3] as List?)?.cast<QuestionEntity>(), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
void write(BinaryWriter writer, LevelEntity obj) { |
||||
|
writer |
||||
|
..writeByte(4) |
||||
|
..writeByte(0) |
||||
|
..write(obj.id) |
||||
|
..writeByte(1) |
||||
|
..write(obj.order) |
||||
|
..writeByte(2) |
||||
|
..write(obj.title) |
||||
|
..writeByte(3) |
||||
|
..write(obj.questions); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
int get hashCode => typeId.hashCode; |
||||
|
|
||||
|
@override |
||||
|
bool operator ==(Object other) => |
||||
|
identical(this, other) || |
||||
|
other is LevelEntityAdapter && |
||||
|
runtimeType == other.runtimeType && |
||||
|
typeId == other.typeId; |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
import 'package:hadi_hoda_flutter/features/question/data/model/file_model.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; |
||||
|
|
||||
|
class AnswerModel extends AnswerEntity { |
||||
|
AnswerModel({ |
||||
|
super.id, |
||||
|
super.title, |
||||
|
super.imageId, |
||||
|
super.imageInfo, |
||||
|
super.order, |
||||
|
super.isActive, |
||||
|
}); |
||||
|
|
||||
|
factory AnswerModel.fromJson(Map<String, dynamic> json) { |
||||
|
return AnswerModel( |
||||
|
id: json['id'], |
||||
|
title: json['title'], |
||||
|
imageId: json['image_id'], |
||||
|
imageInfo: json['image_info'] == null |
||||
|
? null |
||||
|
: FileModel.fromJson(json['image_info']), |
||||
|
order: json['order'], |
||||
|
isActive: json['is_active'], |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/file_entity.dart'; |
||||
|
|
||||
|
class FileModel extends FileEntity { |
||||
|
FileModel({ |
||||
|
super.filename, |
||||
|
super.size, |
||||
|
super.extension, |
||||
|
}); |
||||
|
|
||||
|
factory FileModel.fromJson(Map<String, dynamic> json) { |
||||
|
return FileModel( |
||||
|
filename: json['filename'], |
||||
|
size: json['size'], |
||||
|
extension: json['extension'], |
||||
|
); |
||||
|
} |
||||
|
} |
@ -1,13 +1,34 @@ |
|||||
|
import 'package:hadi_hoda_flutter/features/question/data/model/answer_model.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/question/data/model/file_model.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; |
||||
import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart'; |
import 'package:hadi_hoda_flutter/features/question/domain/entity/question_entity.dart'; |
||||
|
|
||||
class QuestionModel extends QuestionEntity { |
class QuestionModel extends QuestionEntity { |
||||
const QuestionModel({ |
|
||||
|
QuestionModel({ |
||||
super.id, |
super.id, |
||||
|
super.title, |
||||
|
super.audioId, |
||||
|
super.audioInfo, |
||||
|
super.order, |
||||
|
super.correctAnswer, |
||||
|
super.isActive, |
||||
|
super.answers, |
||||
}); |
}); |
||||
|
|
||||
factory QuestionModel.fromJson(Map<String, dynamic> json) { |
factory QuestionModel.fromJson(Map<String, dynamic> json) { |
||||
return QuestionModel( |
return QuestionModel( |
||||
id: json['id'], |
id: json['id'], |
||||
|
title: json['title'], |
||||
|
audioId: json['audio_id'], |
||||
|
audioInfo: json['audio_info'] == null |
||||
|
? null |
||||
|
: FileModel.fromJson(json['audio_info']), |
||||
|
order: json['order'], |
||||
|
correctAnswer: json['correct_answer'], |
||||
|
isActive: json['is_active'], |
||||
|
answers: json['answers'] |
||||
|
?.map<AnswerEntity>((e) => AnswerModel.fromJson(e)) |
||||
|
.toList(), |
||||
); |
); |
||||
} |
} |
||||
} |
} |
@ -0,0 +1,29 @@ |
|||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/file_entity.dart'; |
||||
|
import 'package:hive/hive.dart'; |
||||
|
|
||||
|
part 'answer_entity.g.dart'; |
||||
|
|
||||
|
@HiveType(typeId: 2) |
||||
|
class AnswerEntity extends HiveObject { |
||||
|
@HiveField(0) |
||||
|
int? id; |
||||
|
@HiveField(1) |
||||
|
String? title; |
||||
|
@HiveField(2) |
||||
|
String? imageId; |
||||
|
@HiveField(3) |
||||
|
FileEntity? imageInfo; |
||||
|
@HiveField(4) |
||||
|
int? order; |
||||
|
@HiveField(5) |
||||
|
bool? isActive; |
||||
|
|
||||
|
AnswerEntity({ |
||||
|
this.id, |
||||
|
this.title, |
||||
|
this.imageId, |
||||
|
this.imageInfo, |
||||
|
this.order, |
||||
|
this.isActive, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
|
||||
|
part of 'answer_entity.dart'; |
||||
|
|
||||
|
// ************************************************************************** |
||||
|
// TypeAdapterGenerator |
||||
|
// ************************************************************************** |
||||
|
|
||||
|
class AnswerEntityAdapter extends TypeAdapter<AnswerEntity> { |
||||
|
@override |
||||
|
final int typeId = 2; |
||||
|
|
||||
|
@override |
||||
|
AnswerEntity read(BinaryReader reader) { |
||||
|
final numOfFields = reader.readByte(); |
||||
|
final fields = <int, dynamic>{ |
||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), |
||||
|
}; |
||||
|
return AnswerEntity( |
||||
|
id: fields[0] as int?, |
||||
|
title: fields[1] as String?, |
||||
|
imageId: fields[2] as String?, |
||||
|
imageInfo: fields[3] as FileEntity?, |
||||
|
order: fields[4] as int?, |
||||
|
isActive: fields[5] as bool?, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
void write(BinaryWriter writer, AnswerEntity obj) { |
||||
|
writer |
||||
|
..writeByte(6) |
||||
|
..writeByte(0) |
||||
|
..write(obj.id) |
||||
|
..writeByte(1) |
||||
|
..write(obj.title) |
||||
|
..writeByte(2) |
||||
|
..write(obj.imageId) |
||||
|
..writeByte(3) |
||||
|
..write(obj.imageInfo) |
||||
|
..writeByte(4) |
||||
|
..write(obj.order) |
||||
|
..writeByte(5) |
||||
|
..write(obj.isActive); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
int get hashCode => typeId.hashCode; |
||||
|
|
||||
|
@override |
||||
|
bool operator ==(Object other) => |
||||
|
identical(this, other) || |
||||
|
other is AnswerEntityAdapter && |
||||
|
runtimeType == other.runtimeType && |
||||
|
typeId == other.typeId; |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
import 'package:hive/hive.dart'; |
||||
|
|
||||
|
part 'file_entity.g.dart'; |
||||
|
|
||||
|
@HiveType(typeId: 3) |
||||
|
class FileEntity extends HiveObject { |
||||
|
@HiveField(0) |
||||
|
String? filename; |
||||
|
@HiveField(1) |
||||
|
int? size; |
||||
|
@HiveField(2) |
||||
|
String? extension; |
||||
|
|
||||
|
FileEntity({ |
||||
|
this.filename, |
||||
|
this.size, |
||||
|
this.extension, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
|
||||
|
part of 'file_entity.dart'; |
||||
|
|
||||
|
// ************************************************************************** |
||||
|
// TypeAdapterGenerator |
||||
|
// ************************************************************************** |
||||
|
|
||||
|
class FileEntityAdapter extends TypeAdapter<FileEntity> { |
||||
|
@override |
||||
|
final int typeId = 3; |
||||
|
|
||||
|
@override |
||||
|
FileEntity read(BinaryReader reader) { |
||||
|
final numOfFields = reader.readByte(); |
||||
|
final fields = <int, dynamic>{ |
||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), |
||||
|
}; |
||||
|
return FileEntity( |
||||
|
filename: fields[0] as String?, |
||||
|
size: fields[1] as int?, |
||||
|
extension: fields[2] as String?, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
void write(BinaryWriter writer, FileEntity obj) { |
||||
|
writer |
||||
|
..writeByte(3) |
||||
|
..writeByte(0) |
||||
|
..write(obj.filename) |
||||
|
..writeByte(1) |
||||
|
..write(obj.size) |
||||
|
..writeByte(2) |
||||
|
..write(obj.extension); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
int get hashCode => typeId.hashCode; |
||||
|
|
||||
|
@override |
||||
|
bool operator ==(Object other) => |
||||
|
identical(this, other) || |
||||
|
other is FileEntityAdapter && |
||||
|
runtimeType == other.runtimeType && |
||||
|
typeId == other.typeId; |
||||
|
} |
@ -1,14 +1,36 @@ |
|||||
import 'package:equatable/equatable.dart'; |
|
||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/answer_entity.dart'; |
||||
|
import 'package:hadi_hoda_flutter/features/question/domain/entity/file_entity.dart'; |
||||
|
import 'package:hive/hive.dart'; |
||||
|
|
||||
class QuestionEntity extends Equatable { |
|
||||
final int? id; |
|
||||
|
part 'question_entity.g.dart'; |
||||
|
|
||||
const QuestionEntity({ |
|
||||
|
@HiveType(typeId: 1) |
||||
|
class QuestionEntity extends HiveObject { |
||||
|
@HiveField(0) |
||||
|
int? id; |
||||
|
@HiveField(1) |
||||
|
String? title; |
||||
|
@HiveField(2) |
||||
|
String? audioId; |
||||
|
@HiveField(3) |
||||
|
FileEntity? audioInfo; |
||||
|
@HiveField(4) |
||||
|
int? order; |
||||
|
@HiveField(5) |
||||
|
int? correctAnswer; |
||||
|
@HiveField(6) |
||||
|
bool? isActive; |
||||
|
@HiveField(7) |
||||
|
List<AnswerEntity>? answers; |
||||
|
|
||||
|
QuestionEntity({ |
||||
this.id, |
this.id, |
||||
|
this.title, |
||||
|
this.audioId, |
||||
|
this.audioInfo, |
||||
|
this.order, |
||||
|
this.correctAnswer, |
||||
|
this.isActive, |
||||
|
this.answers, |
||||
}); |
}); |
||||
|
|
||||
@override |
|
||||
List<Object?> get props => [ |
|
||||
id, |
|
||||
]; |
|
||||
} |
} |
@ -0,0 +1,62 @@ |
|||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
|
||||
|
part of 'question_entity.dart'; |
||||
|
|
||||
|
// ************************************************************************** |
||||
|
// TypeAdapterGenerator |
||||
|
// ************************************************************************** |
||||
|
|
||||
|
class QuestionEntityAdapter extends TypeAdapter<QuestionEntity> { |
||||
|
@override |
||||
|
final int typeId = 1; |
||||
|
|
||||
|
@override |
||||
|
QuestionEntity read(BinaryReader reader) { |
||||
|
final numOfFields = reader.readByte(); |
||||
|
final fields = <int, dynamic>{ |
||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), |
||||
|
}; |
||||
|
return QuestionEntity( |
||||
|
id: fields[0] as int?, |
||||
|
title: fields[1] as String?, |
||||
|
audioId: fields[2] as String?, |
||||
|
audioInfo: fields[3] as FileEntity?, |
||||
|
order: fields[4] as int?, |
||||
|
correctAnswer: fields[5] as int?, |
||||
|
isActive: fields[6] as bool?, |
||||
|
answers: (fields[7] as List?)?.cast<AnswerEntity>(), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
void write(BinaryWriter writer, QuestionEntity obj) { |
||||
|
writer |
||||
|
..writeByte(8) |
||||
|
..writeByte(0) |
||||
|
..write(obj.id) |
||||
|
..writeByte(1) |
||||
|
..write(obj.title) |
||||
|
..writeByte(2) |
||||
|
..write(obj.audioId) |
||||
|
..writeByte(3) |
||||
|
..write(obj.audioInfo) |
||||
|
..writeByte(4) |
||||
|
..write(obj.order) |
||||
|
..writeByte(5) |
||||
|
..write(obj.correctAnswer) |
||||
|
..writeByte(6) |
||||
|
..write(obj.isActive) |
||||
|
..writeByte(7) |
||||
|
..write(obj.answers); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
int get hashCode => typeId.hashCode; |
||||
|
|
||||
|
@override |
||||
|
bool operator ==(Object other) => |
||||
|
identical(this, other) || |
||||
|
other is QuestionEntityAdapter && |
||||
|
runtimeType == other.runtimeType && |
||||
|
typeId == other.typeId; |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue