2 Commits

  1. 2
      lib/core/auth_storage/auth_storage.dart
  2. 3
      lib/core/constants/my_api.dart
  3. 6
      lib/core/constants/my_constants.dart
  4. 13
      lib/core/routers/my_routes.dart
  5. 4
      lib/core/utils/local_storage.dart
  6. 116
      lib/features/download/data/datasource/download_datasource.dart
  7. 50
      lib/features/download/data/repository_impl/download_repository_impl.dart
  8. 0
      lib/features/download/domain/entities/download_entity.dart
  9. 10
      lib/features/download/domain/repository/download_repository.dart
  10. 16
      lib/features/download/domain/usecases/get_audios_usecase.dart
  11. 12
      lib/features/download/domain/usecases/loading_stream_audio_usecase.dart
  12. 4
      lib/features/download/domain/usecases/save_levels_usecase.dart
  13. 74
      lib/features/download/presentation/bloc/download_bloc.dart
  14. 5
      lib/features/download/presentation/bloc/download_event.dart
  15. 15
      lib/features/download/presentation/bloc/download_state.dart
  16. 130
      lib/features/download/presentation/ui/download_page.dart
  17. 136
      lib/features/download/presentation/ui/widgets/download_loading_widget.dart
  18. 60
      lib/features/intro/data/datasource/intro_datasource.dart
  19. 22
      lib/features/intro/data/repository_impl/intro_repository_impl.dart
  20. 5
      lib/features/intro/domain/repository/intro_repository.dart
  21. 6
      lib/features/intro/domain/usecases/get_images_usecase.dart
  22. 2
      lib/features/intro/domain/usecases/loading_stream_usecase.dart
  23. 52
      lib/features/intro/presentation/bloc/intro_bloc.dart
  24. 3
      lib/features/intro/presentation/bloc/intro_event.dart
  25. 6
      lib/features/intro/presentation/ui/intro_page.dart
  26. 2
      lib/features/intro/presentation/ui/widgets/intro_loading_widget.dart
  27. 27
      lib/features/language/presentation/bloc/language_bloc.dart
  28. 2
      lib/features/level/data/datasource/level_datasource.dart
  29. 11
      lib/features/level/presentation/bloc/level_bloc.dart
  30. 2
      lib/features/question/data/datasource/question_datasource.dart
  31. 21
      lib/init_bindings.dart
  32. 12
      lib/main.dart

2
lib/core/auth_storage/auth_storage.dart

@ -19,7 +19,7 @@ class AuthStorage {
} }
static void loadData() { static void loadData() {
token = LocalStorage.readData(key: MyConstants.token);
token = LocalStorage.readData(key: MyConstants.token) ?? '';
} }
static bool isLogin() { static bool isLogin() {

3
lib/core/constants/my_api.dart

@ -11,5 +11,6 @@ class MyApi {
static const String baseUrl = 'https://hadihoda.newhorizonco.uk/api'; static const String baseUrl = 'https://hadihoda.newhorizonco.uk/api';
static const String levels = '/quiz/optimized/levels/'; static const String levels = '/quiz/optimized/levels/';
static const String files = '/quiz/optimized/download-all-files/';
static const String images = '/quiz/optimized/download-all-files/images/';
static const String audios = '/quiz/optimized/download-all-files/audio/';
} }

6
lib/core/constants/my_constants.dart

@ -6,8 +6,10 @@ class MyConstants {
static const String token = 'TOKEN'; static const String token = 'TOKEN';
static const String theme = 'THEME'; static const String theme = 'THEME';
static const String levelBox = 'LEVEL_BOX'; static const String levelBox = 'LEVEL_BOX';
static const String downloadCompleted = 'DOWNLOAD_COMPLETED';
static const String extractCompleted = 'EXTRACT_COMPLETED';
static const String downloadedImage = 'DOWNLOADED_IMAGE';
static const String extractedImage = 'EXTRACTED_IMAGE';
static const String downloadedAudio = 'DOWNLOADED_AUDIO';
static const String extractedAudio = 'EXTRACTED_AUDIO';
static const String selectLanguage = 'SELECT_LANGUAGE'; static const String selectLanguage = 'SELECT_LANGUAGE';
static const String firstLanguagePage = 'FIRST_LANGUAGE_PAGE'; static const String firstLanguagePage = 'FIRST_LANGUAGE_PAGE';
static const String currentLevel = 'CURRENT_LEVEL'; static const String currentLevel = 'CURRENT_LEVEL';

13
lib/core/routers/my_routes.dart

@ -1,6 +1,8 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; import 'package:hadi_hoda_flutter/core/utils/context_provider.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_bloc.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/ui/download_page.dart';
import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_bloc.dart'; import 'package:hadi_hoda_flutter/features/home/presentation/bloc/home_bloc.dart';
import 'package:hadi_hoda_flutter/features/home/presentation/ui/home_page.dart'; import 'package:hadi_hoda_flutter/features/home/presentation/ui/home_page.dart';
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_bloc.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_bloc.dart';
@ -22,6 +24,7 @@ class Routes {
factory Routes() => _i; factory Routes() => _i;
static const String introPage = '/intro_page'; static const String introPage = '/intro_page';
static const String downloadPage = '/download_page';
static const String languagePage = '/language_page'; static const String languagePage = '/language_page';
static const String homePage = '/home_page'; static const String homePage = '/home_page';
static const String questionPage = '/question_page'; static const String questionPage = '/question_page';
@ -36,10 +39,18 @@ GoRouter get appPages => GoRouter(
name: Routes.introPage, name: Routes.introPage,
path: Routes.introPage, path: Routes.introPage,
builder: (context, state) => BlocProvider( builder: (context, state) => BlocProvider(
create: (context) => IntroBloc(locator(), locator(), locator()),
create: (context) => IntroBloc(locator(), locator()),
child: const IntroPage(), child: const IntroPage(),
), ),
), ),
GoRoute(
name: Routes.downloadPage,
path: Routes.downloadPage,
builder: (context, state) => BlocProvider(
create: (context) => DownloadBloc(locator(), locator(), locator()),
child: const DownloadPage(),
),
),
GoRoute( GoRoute(
name: Routes.languagePage, name: Routes.languagePage,
path: Routes.languagePage, path: Routes.languagePage,

4
lib/core/utils/local_storage.dart

@ -15,8 +15,8 @@ class LocalStorage {
await _box.setString(key, value); await _box.setString(key, value);
} }
static String readData({required String key}) {
return _box.getString(key) ?? '';
static String? readData({required String key}) {
return _box.getString(key);
} }
static Future<void> deleteData({required String key}) async { static Future<void> deleteData({required String key}) async {

116
lib/features/download/data/datasource/download_datasource.dart

@ -0,0 +1,116 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter_archive/flutter_archive.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/response/base_response.dart';
import 'package:hadi_hoda_flutter/core/utils/local_storage.dart';
import 'package:hadi_hoda_flutter/core/utils/storage_path.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_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:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart';
import 'package:hive/hive.dart';
abstract class IDownloadDatasource {
Future<void> getAudios();
Future<void> saveLevels();
Stream<DownloadEntity> loadingStream();
}
class DownloadDatasourceImpl implements IDownloadDatasource {
final IHttpRequest httpRequest;
final StreamController<DownloadEntity> streamController = StreamController<DownloadEntity>.broadcast();
DownloadDatasourceImpl(this.httpRequest);
@override
Future<void> getAudios() async {
final String filePath = '${StoragePath.documentDir.path}/audios.zip';
final String selectedLanguage =
LocalStorage.readData(key: MyConstants.selectLanguage) ?? 'fa';
if(LocalStorage.readData(key: MyConstants.downloadedAudio) != 'true'){
await httpRequest.download(
urlPath: MyApi.audios,
savePath: filePath,
queryParameters: {
'lang': selectedLanguage,
},
onReceive: (count, total) {
streamController.add(DownloadEntity(
count: count / 1,
total: total / 1,
percent: (count / total) * 100,
));
},
).then((value) async {
await LocalStorage.saveData(
key: MyConstants.downloadedAudio,
value: 'true',
);
},);
}
try{
if (LocalStorage.readData(key: MyConstants.extractedAudio) != 'true') {
final File file = File(filePath);
final Directory directory = Directory(
'${StoragePath.documentDir.path}/$selectedLanguage/',
);
await ZipFile.extractToDirectory(
zipFile: file,
destinationDir: directory,
onExtracting: (zipEntry, progress) {
return ZipFileOperation.includeItem;
},
).then((value) async {
await Future.wait([
LocalStorage.saveData(
key: MyConstants.extractedAudio,
value: 'true',
),
file.delete(recursive: true),
]);
});
} else {
streamController.add(DownloadEntity(percent: 50));
await Future.delayed(Duration(milliseconds: 150));
streamController.add(DownloadEntity(percent: 100));
}
} catch (e){
throw MyException(errorMessage: '$e');
}
}
@override
Future<void> saveLevels() async {
final String selectedLanguage =
LocalStorage.readData(key: MyConstants.selectLanguage) ?? 'fa';
final Box<TotalDataEntity> data = Hive.box(MyConstants.levelBox);
final TotalDataEntity findData = data.values.singleWhere(
(e) => e.code == selectedLanguage,
orElse: () => TotalDataEntity(),
);
if (findData.code != selectedLanguage) {
final response = await httpRequest.get(
path: MyApi.levels,
queryParameters: {'lang': selectedLanguage},
);
final List<LevelEntity> levels = BaseResponse.getDataList<LevelEntity>(
response?['result'],
(json) => LevelModel.fromJson(json),
);
await Future.wait([
data.add(TotalDataEntity(code: selectedLanguage, levels: levels)),
]);
}
}
@override
Stream<DownloadEntity> loadingStream() => streamController.stream;
}

50
lib/features/download/data/repository_impl/download_repository_impl.dart

@ -0,0 +1,50 @@
import 'package:flutter/foundation.dart';
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/utils/data_state.dart';
import 'package:hadi_hoda_flutter/features/download/data/datasource/download_datasource.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/domain/repository/download_repository.dart';
class DownloadRepositoryImpl implements IDownloadRepository {
final IDownloadDatasource datasource;
const DownloadRepositoryImpl(this.datasource);
@override
Future<DataState<NoParams, MyException>> getAudios() async {
try {
await datasource.getAudios();
return DataState.success(NoParams());
} on MyException catch (e) {
return DataState.error(e);
} catch (e) {
if (kDebugMode) {
rethrow;
} else {
return DataState.error(MyException(errorMessage: '$e'));
}
}
}
@override
Future<DataState<NoParams, MyException>> saveLevels() async {
try {
await datasource.saveLevels();
return DataState.success(NoParams());
} on MyException catch (e) {
return DataState.error(e);
} catch (e) {
if (kDebugMode) {
rethrow;
} else {
return DataState.error(MyException(errorMessage: '$e'));
}
}
}
@override
Stream<DownloadEntity> loadingStream() {
return datasource.loadingStream();
}
}

0
lib/features/intro/domain/entities/download_entity.dart → lib/features/download/domain/entities/download_entity.dart

10
lib/features/download/domain/repository/download_repository.dart

@ -0,0 +1,10 @@
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/utils/data_state.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
abstract class IDownloadRepository {
Future<DataState<NoParams, MyException>> getAudios();
Future<DataState<NoParams, MyException>> saveLevels();
Stream<DownloadEntity> loadingStream();
}

16
lib/features/download/domain/usecases/get_audios_usecase.dart

@ -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/download/domain/repository/download_repository.dart';
class GetAudiosUseCase implements UseCase<NoParams, NoParams> {
final IDownloadRepository repository;
const GetAudiosUseCase(this.repository);
@override
Future<DataState<NoParams, MyException>> call(NoParams params) {
return repository.getAudios();
}
}

12
lib/features/download/domain/usecases/loading_stream_audio_usecase.dart

@ -0,0 +1,12 @@
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/domain/repository/download_repository.dart';
class LoadingStreamAudioUseCase {
final IDownloadRepository repository;
const LoadingStreamAudioUseCase(this.repository);
Stream<DownloadEntity> call() {
return repository.loadingStream();
}
}

4
lib/features/intro/domain/usecases/save_levels_usecase.dart → lib/features/download/domain/usecases/save_levels_usecase.dart

@ -2,10 +2,10 @@ 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/params/no_params.dart';
import 'package:hadi_hoda_flutter/core/usecase/usecase.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/core/utils/data_state.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart';
import 'package:hadi_hoda_flutter/features/download/domain/repository/download_repository.dart';
class SaveLevelsUseCase implements UseCase<NoParams, NoParams> { class SaveLevelsUseCase implements UseCase<NoParams, NoParams> {
final IIntroRepository repository;
final IDownloadRepository repository;
const SaveLevelsUseCase(this.repository); const SaveLevelsUseCase(this.repository);

74
lib/features/download/presentation/bloc/download_bloc.dart

@ -0,0 +1,74 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:hadi_hoda_flutter/core/params/no_params.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/core/utils/context_provider.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/domain/usecases/get_audios_usecase.dart';
import 'package:hadi_hoda_flutter/features/download/domain/usecases/loading_stream_audio_usecase.dart';
import 'package:hadi_hoda_flutter/features/download/domain/usecases/save_levels_usecase.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_event.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_state.dart';
class DownloadBloc extends Bloc<DownloadEvent, DownloadState> {
/// ------------constructor------------
DownloadBloc(
this._getAudiosUseCase,
this._loadingStreamUseCase,
this._saveLevelsUseCase,
)
: super(const DownloadState()) {
on<GetAudiosEvent>(_getAudiosEvent);
on<SaveLevelsEvent>(_saveLevelsEvent);
loadingStream = _loadingStreamUseCase();
}
/// ------------UseCases------------
final GetAudiosUseCase _getAudiosUseCase;
final SaveLevelsUseCase _saveLevelsUseCase;
final LoadingStreamAudioUseCase _loadingStreamUseCase;
/// ------------Variables------------
Stream<DownloadEntity> loadingStream = Stream.empty();
/// ------------Controllers------------
/// ------------Functions------------
/// ------------Api Calls------------
FutureOr<void> _getAudiosEvent(
GetAudiosEvent event,
Emitter<DownloadState> emit,
) async {
emit(state.copyWith(getFilesStatus: BaseInit()));
await _getAudiosUseCase(NoParams()).then((value) {
value.fold(
(data) async {
add(SaveLevelsEvent());
},
(error) async {
emit(state.copyWith(getFilesStatus: BaseError(error.errorMessage)));
},
);
});
}
FutureOr<void> _saveLevelsEvent(
SaveLevelsEvent event,
Emitter<DownloadState> emit,
) async {
await _saveLevelsUseCase(NoParams()).then((value) =>
value.fold(
(data) async {
ContextProvider.context.goNamed(Routes.homePage);
},
(error) {
emit(state.copyWith(getFilesStatus: BaseError(error.errorMessage)));
},
),
);
}
}

5
lib/features/download/presentation/bloc/download_event.dart

@ -0,0 +1,5 @@
sealed class DownloadEvent {
const DownloadEvent();
}
class GetAudiosEvent extends DownloadEvent {}
class SaveLevelsEvent extends DownloadEvent {}

15
lib/features/download/presentation/bloc/download_state.dart

@ -0,0 +1,15 @@
import 'package:hadi_hoda_flutter/core/status/base_status.dart';
class DownloadState {
final BaseStatus getFilesStatus;
const DownloadState({this.getFilesStatus = const BaseInit()});
DownloadState copyWith({
BaseStatus? getFilesStatus,
}) {
return DownloadState(
getFilesStatus: getFilesStatus ?? this.getFilesStatus,
);
}
}

130
lib/features/download/presentation/ui/download_page.dart

@ -0,0 +1,130 @@
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/resources/my_colors.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_spaces.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart';
import 'package:hadi_hoda_flutter/core/status/base_status.dart';
import 'package:hadi_hoda_flutter/core/utils/convert_size.dart';
import 'package:hadi_hoda_flutter/core/utils/my_image.dart';
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart';
import 'package:hadi_hoda_flutter/core/utils/screen_size.dart';
import 'package:hadi_hoda_flutter/core/widgets/error/error_state.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_bloc.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_event.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/bloc/download_state.dart';
import 'package:hadi_hoda_flutter/features/download/presentation/ui/widgets/download_loading_widget.dart';
class DownloadPage extends StatefulWidget {
const DownloadPage({super.key});
@override
State<DownloadPage> createState() => _DownloadPageState();
}
class _DownloadPageState extends State<DownloadPage> {
@override
void initState() {
super.initState();
context.read<DownloadBloc>().add(GetAudiosEvent());
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: context.heightScreen,
width: context.widthScreen,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0XFF00154C),
Color(0XFF150532),
],
),
image: DecorationImage(
image: AssetImage(MyAssets.pattern),
scale: 3,
repeat: ImageRepeat.repeat,
colorFilter: ColorFilter.mode(
Colors.white.withValues(alpha: 0.2),
BlendMode.srcIn,
),
),
),
child: BlocBuilder<DownloadBloc, DownloadState>(
buildWhen: (previous, current) =>
previous.getFilesStatus != current.getFilesStatus,
builder: (context, state) {
if (state.getFilesStatus is BaseError) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: MediaQuery.viewPaddingOf(context).bottom + MySpaces.s16,
horizontal: 60,
),
child: ErrorState(
onTap: () => context.read<DownloadBloc>().add(GetAudiosEvent()),
),
);
} else {
return Stack(
alignment: Alignment.center,
children: [
_image(),
_text(context),
_loading(context),
],
);
}
}
),
),
);
}
MyImage _image() {
return MyImage(
image: MyAssets.hadiHoda,
size: 200,
);
}
Widget _text(BuildContext context) {
return PositionedDirectional(
bottom: 130,
child: Column(
spacing: MySpaces.s6,
children: [
Text(
context.translate.please_wait,
style: Marhey.medium22.copyWith(
color: MyColors.white,
),
),
StreamBuilder<DownloadEntity>(
initialData: DownloadEntity(),
stream: context.read<DownloadBloc>().loadingStream,
builder: (context, snapshot) => Text(
'${context.translate.downloading_data} (${snapshot.data?.count.toMB ?? 0.0}mb / ${snapshot.data?.total.toMB ?? 0.0}mb)',
style: Marhey.medium12.copyWith(
color: MyColors.white,
),
),
),
],
),
);
}
Positioned _loading(BuildContext context) {
return Positioned(
bottom: MediaQuery.viewPaddingOf(context).bottom + MySpaces.s16,
child: DownloadLoadingWidget(
loadingStream: context.read<DownloadBloc>().loadingStream,
),
);
}
}

136
lib/features/download/presentation/ui/widgets/download_loading_widget.dart

@ -0,0 +1,136 @@
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';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
class DownloadLoadingWidget extends StatelessWidget {
const DownloadLoadingWidget({
super.key,
this.loadingStream,
});
final Stream<DownloadEntity>? 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<DownloadEntity>(
initialData: DownloadEntity(),
stream: loadingStream,
builder: (context, snapshot) {
return Row(
children: [
Expanded(
flex: 85,
child: ClipPath(
clipper: BubbleClip(),
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: EdgeInsetsDirectional.only(
end: 260 - ((snapshot.data?.percent ?? 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?.percent?.toInt() ?? 0}%',
style: DinoKids.regular17.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;
}

60
lib/features/intro/data/datasource/intro_datasource.dart

@ -6,18 +6,12 @@ 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/constants/my_constants.dart';
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/network/http_request.dart'; import 'package:hadi_hoda_flutter/core/network/http_request.dart';
import 'package:hadi_hoda_flutter/core/response/base_response.dart';
import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart';
import 'package:hadi_hoda_flutter/core/utils/storage_path.dart'; import 'package:hadi_hoda_flutter/core/utils/storage_path.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/entities/download_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:hadi_hoda_flutter/features/level/domain/entity/total_data_entity.dart';
import 'package:hive/hive.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
abstract class IIntroDatasource { abstract class IIntroDatasource {
Future<void> getFiles();
Future<void> saveLevels();
Future<void> getImages();
Stream<DownloadEntity> loadingStream(); Stream<DownloadEntity> loadingStream();
} }
@ -28,20 +22,13 @@ class IntroDatasourceImpl implements IIntroDatasource {
IntroDatasourceImpl(this.httpRequest); IntroDatasourceImpl(this.httpRequest);
@override @override
Future<void> getFiles() async {
final String filePath = '${StoragePath.documentDir.path}/files.zip';
final String selectedLanguage =
LocalStorage.readData(key: MyConstants.selectLanguage).isEmpty
? 'fa'
: LocalStorage.readData(key: MyConstants.selectLanguage);
Future<void> getImages() async {
final String filePath = '${StoragePath.documentDir.path}/images.zip';
if (LocalStorage.readData(key: MyConstants.downloadCompleted) != 'true') {
if (LocalStorage.readData(key: MyConstants.downloadedImage) != 'true') {
await httpRequest.download( await httpRequest.download(
urlPath: MyApi.files,
urlPath: MyApi.images,
savePath: filePath, savePath: filePath,
queryParameters: {
'lang': selectedLanguage,
},
onReceive: (count, total) { onReceive: (count, total) {
streamController.add(DownloadEntity( streamController.add(DownloadEntity(
count: count / 1, count: count / 1,
@ -51,16 +38,16 @@ class IntroDatasourceImpl implements IIntroDatasource {
}, },
).then((value) async { ).then((value) async {
await LocalStorage.saveData( await LocalStorage.saveData(
key: MyConstants.downloadCompleted,
key: MyConstants.downloadedImage,
value: 'true', value: 'true',
); );
}); });
} }
try{ try{
if (LocalStorage.readData(key: MyConstants.extractCompleted) != 'true') {
if (LocalStorage.readData(key: MyConstants.extractedImage) != 'true') {
final File file = File(filePath); final File file = File(filePath);
final Directory directory = Directory('${StoragePath.documentDir.path}/$selectedLanguage/files/');
final Directory directory = Directory('${StoragePath.documentDir.path}/');
await ZipFile.extractToDirectory( await ZipFile.extractToDirectory(
zipFile: file, zipFile: file,
destinationDir: directory, destinationDir: directory,
@ -70,7 +57,7 @@ class IntroDatasourceImpl implements IIntroDatasource {
).then((value) async { ).then((value) async {
await Future.wait([ await Future.wait([
LocalStorage.saveData( LocalStorage.saveData(
key: MyConstants.extractCompleted,
key: MyConstants.extractedImage,
value: 'true', value: 'true',
), ),
file.delete(recursive: true), file.delete(recursive: true),
@ -86,33 +73,6 @@ class IntroDatasourceImpl implements IIntroDatasource {
} }
} }
@override
Future<void> saveLevels() async {
final String selectedLanguage =
LocalStorage.readData(key: MyConstants.selectLanguage).isEmpty
? 'fa'
: LocalStorage.readData(key: MyConstants.selectLanguage);
final Box<TotalDataEntity> data = Hive.box(MyConstants.levelBox);
final TotalDataEntity findData = data.values.singleWhere(
(e) => e.code == selectedLanguage,
orElse: () => TotalDataEntity(),
);
if (findData.code != selectedLanguage) {
final response = await httpRequest.get(
path: MyApi.levels,
queryParameters: {'lang': selectedLanguage},
);
final List<LevelEntity> levels = BaseResponse.getDataList<LevelEntity>(
response?['result'],
(json) => LevelModel.fromJson(json),
);
await Future.wait([
data.add(TotalDataEntity(code: selectedLanguage, levels: levels)),
]);
}
}
@override @override
Stream<DownloadEntity> loadingStream() => streamController.stream; Stream<DownloadEntity> loadingStream() => streamController.stream;
} }

22
lib/features/intro/data/repository_impl/intro_repository_impl.dart

@ -2,8 +2,8 @@ import 'package:flutter/foundation.dart';
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/no_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/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/intro/data/datasource/intro_datasource.dart'; import 'package:hadi_hoda_flutter/features/intro/data/datasource/intro_datasource.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart';
class IntroRepositoryImpl implements IIntroRepository { class IntroRepositoryImpl implements IIntroRepository {
@ -12,25 +12,9 @@ class IntroRepositoryImpl implements IIntroRepository {
const IntroRepositoryImpl(this.datasource); const IntroRepositoryImpl(this.datasource);
@override @override
Future<DataState<NoParams, MyException>> getFiles() async {
Future<DataState<NoParams, MyException>> getImages() async {
try { try {
await datasource.getFiles();
return DataState.success(NoParams());
} on MyException catch (e) {
return DataState.error(e);
} catch (e) {
if (kDebugMode) {
rethrow;
} else {
return DataState.error(MyException(errorMessage: '$e'));
}
}
}
@override
Future<DataState<NoParams, MyException>> saveLevels() async {
try {
await datasource.saveLevels();
await datasource.getImages();
return DataState.success(NoParams()); return DataState.success(NoParams());
} on MyException catch (e) { } on MyException catch (e) {
return DataState.error(e); return DataState.error(e);

5
lib/features/intro/domain/repository/intro_repository.dart

@ -1,10 +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/no_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/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
abstract class IIntroRepository { abstract class IIntroRepository {
Future<DataState<NoParams, MyException>> getFiles();
Future<DataState<NoParams, MyException>> saveLevels();
Future<DataState<NoParams, MyException>> getImages();
Stream<DownloadEntity> loadingStream(); Stream<DownloadEntity> loadingStream();
} }

6
lib/features/intro/domain/usecases/get_files_usecase.dart → lib/features/intro/domain/usecases/get_images_usecase.dart

@ -4,13 +4,13 @@ import 'package:hadi_hoda_flutter/core/usecase/usecase.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/repository/intro_repository.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart';
class GetFilesUseCase implements UseCase<NoParams, NoParams> {
class GetImagesUseCase implements UseCase<NoParams, NoParams> {
final IIntroRepository repository; final IIntroRepository repository;
const GetFilesUseCase(this.repository);
const GetImagesUseCase(this.repository);
@override @override
Future<DataState<NoParams, MyException>> call(NoParams params) { Future<DataState<NoParams, MyException>> call(NoParams params) {
return repository.getFiles();
return repository.getImages();
} }
} }

2
lib/features/intro/domain/usecases/loading_stream_usecase.dart

@ -1,4 +1,4 @@
import 'package:hadi_hoda_flutter/features/intro/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart';
class LoadingStreamUseCase { class LoadingStreamUseCase {

52
lib/features/intro/presentation/bloc/intro_bloc.dart

@ -8,29 +8,25 @@ 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/core/status/base_status.dart';
import 'package:hadi_hoda_flutter/core/utils/context_provider.dart'; import 'package:hadi_hoda_flutter/core/utils/context_provider.dart';
import 'package:hadi_hoda_flutter/core/utils/local_storage.dart'; import 'package:hadi_hoda_flutter/core/utils/local_storage.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/get_files_usecase.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/get_images_usecase.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/loading_stream_usecase.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/usecases/loading_stream_usecase.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/save_levels_usecase.dart';
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_event.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_event.dart';
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart';
class IntroBloc extends Bloc<IntroEvent, IntroState> { class IntroBloc extends Bloc<IntroEvent, IntroState> {
/// ------------constructor------------ /// ------------constructor------------
IntroBloc( IntroBloc(
this._getFilesUseCase,
this._getImagesUseCase,
this._loadingStreamUseCase, this._loadingStreamUseCase,
this._saveLevelsUseCase,
) )
: super(const IntroState()) { : super(const IntroState()) {
on<GetFilesEvent>(_getFilesEvent);
on<SaveLevelsEvent>(_saveLevelsEvent);
on<GetImagesEvent>(_getImagesEvent);
loadingStream = _loadingStreamUseCase(); loadingStream = _loadingStreamUseCase();
} }
/// ------------UseCases------------ /// ------------UseCases------------
final GetFilesUseCase _getFilesUseCase;
final SaveLevelsUseCase _saveLevelsUseCase;
final GetImagesUseCase _getImagesUseCase;
final LoadingStreamUseCase _loadingStreamUseCase; final LoadingStreamUseCase _loadingStreamUseCase;
/// ------------Variables------------ /// ------------Variables------------
@ -41,15 +37,23 @@ class IntroBloc extends Bloc<IntroEvent, IntroState> {
/// ------------Functions------------ /// ------------Functions------------
/// ------------Api Calls------------ /// ------------Api Calls------------
FutureOr<void> _getFilesEvent(
GetFilesEvent event,
FutureOr<void> _getImagesEvent(
GetImagesEvent event,
Emitter<IntroState> emit, Emitter<IntroState> emit,
) async { ) async {
emit(state.copyWith(getFilesStatus: BaseInit())); emit(state.copyWith(getFilesStatus: BaseInit()));
await _getFilesUseCase(NoParams()).then((value) {
await _getImagesUseCase(NoParams()).then((value) {
value.fold( value.fold(
(data) async { (data) async {
add(SaveLevelsEvent());
if(LocalStorage.readData(key: MyConstants.firstLanguagePage) != 'true'){
ContextProvider.context.goNamed(Routes.languagePage);
} else {
await Future.delayed(Duration(milliseconds: 500), () {
if (ContextProvider.context.mounted) {
ContextProvider.context.goNamed(Routes.homePage);
}
});
}
}, },
(error) async { (error) async {
emit(state.copyWith(getFilesStatus: BaseError(error.errorMessage))); emit(state.copyWith(getFilesStatus: BaseError(error.errorMessage)));
@ -57,26 +61,4 @@ class IntroBloc extends Bloc<IntroEvent, IntroState> {
); );
}); });
} }
FutureOr<void> _saveLevelsEvent(SaveLevelsEvent event,
Emitter<IntroState> emit) async {
await _saveLevelsUseCase(NoParams()).then((value) =>
value.fold(
(data) async {
if(LocalStorage.readData(key: MyConstants.firstLanguagePage) != 'true'){
ContextProvider.context.goNamed(Routes.languagePage);
} else {
await Future.delayed(Duration(milliseconds: 500), () {
if (ContextProvider.context.mounted) {
ContextProvider.context.goNamed(Routes.homePage);
}
});
}
},
(error) {
emit(state.copyWith(getFilesStatus: BaseError(error.errorMessage)));
},
),
);
}
} }

3
lib/features/intro/presentation/bloc/intro_event.dart

@ -1,5 +1,4 @@
sealed class IntroEvent { sealed class IntroEvent {
const IntroEvent(); const IntroEvent();
} }
class GetFilesEvent extends IntroEvent {}
class SaveLevelsEvent extends IntroEvent {}
class GetImagesEvent extends IntroEvent {}

6
lib/features/intro/presentation/ui/intro_page.dart

@ -10,7 +10,7 @@ import 'package:hadi_hoda_flutter/core/utils/my_image.dart';
import 'package:hadi_hoda_flutter/core/utils/my_localization.dart'; import 'package:hadi_hoda_flutter/core/utils/my_localization.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/core/widgets/error/error_state.dart'; import 'package:hadi_hoda_flutter/core/widgets/error/error_state.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_bloc.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/bloc/intro_event.dart';
import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart'; import 'package:hadi_hoda_flutter/features/intro/presentation/bloc/intro_state.dart';
@ -27,7 +27,7 @@ class _IntroPageState extends State<IntroPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
context.read<IntroBloc>().add(GetFilesEvent());
context.read<IntroBloc>().add(GetImagesEvent());
} }
@override @override
@ -66,7 +66,7 @@ class _IntroPageState extends State<IntroPage> {
horizontal: 60, horizontal: 60,
), ),
child: ErrorState( child: ErrorState(
onTap: () => context.read<IntroBloc>().add(GetFilesEvent()),
onTap: () => context.read<IntroBloc>().add(GetImagesEvent()),
), ),
); );
} else { } else {

2
lib/features/intro/presentation/ui/widgets/intro_loading_widget.dart

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; 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_spaces.dart';
import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart'; import 'package:hadi_hoda_flutter/common_ui/resources/my_text_style.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/entities/download_entity.dart';
import 'package:hadi_hoda_flutter/features/download/domain/entities/download_entity.dart';
class IntroLoadingWidget extends StatelessWidget { class IntroLoadingWidget extends StatelessWidget {

27
lib/features/language/presentation/bloc/language_bloc.dart

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.dart';
@ -14,7 +15,6 @@ import 'package:hadi_hoda_flutter/features/language/presentation/bloc/language_s
class LanguageBloc extends Bloc<LanguageEvent, LanguageState> { class LanguageBloc extends Bloc<LanguageEvent, LanguageState> {
/// ------------constructor------------ /// ------------constructor------------
LanguageBloc() : super(const LanguageState()) { LanguageBloc() : super(const LanguageState()) {
LocalStorage.saveData(key: MyConstants.firstLanguagePage, value: 'true');
on<ChangeLanguageEvent>(_changeLanguageEvent); on<ChangeLanguageEvent>(_changeLanguageEvent);
on<SaveLevelsEvent>(_saveLevelsEvent); on<SaveLevelsEvent>(_saveLevelsEvent);
on<InitLanguageEvent>(_initLanguageEvent); on<InitLanguageEvent>(_initLanguageEvent);
@ -44,31 +44,34 @@ class LanguageBloc extends Bloc<LanguageEvent, LanguageState> {
SaveLevelsEvent event, SaveLevelsEvent event,
Emitter<LanguageState> emit, Emitter<LanguageState> emit,
) async { ) async {
await LocalStorage.saveData(
key: MyConstants.selectLanguage,
value: state.selectedLang.code ?? 'fa',
);
await Future.wait([
LocalStorage.saveData(
key: MyConstants.selectLanguage,
value: state.selectedLang.code ?? 'fa',
),
LocalStorage.saveData(key: MyConstants.firstLanguagePage, value: 'true')
]);
if (Directory( if (Directory(
'${StoragePath.documentDir.path}/${state.selectedLang.code}/files')
'${StoragePath.documentDir.path}/${state.selectedLang.code}/audio')
.existsSync()) { .existsSync()) {
if (ContextProvider.context.mounted) { if (ContextProvider.context.mounted) {
ContextProvider.context.goNamed(Routes.homePage); ContextProvider.context.goNamed(Routes.homePage);
} }
} else { } else {
await Future.wait([ await Future.wait([
LocalStorage.deleteData(key: MyConstants.downloadCompleted),
LocalStorage.deleteData(key: MyConstants.extractCompleted),
LocalStorage.deleteData(key: MyConstants.downloadedAudio),
LocalStorage.deleteData(key: MyConstants.extractedAudio),
]); ]);
if (ContextProvider.context.mounted) { if (ContextProvider.context.mounted) {
ContextProvider.context.goNamed(Routes.introPage);
ContextProvider.context.goNamed(Routes.downloadPage);
} }
} }
} }
FutureOr<void> _initLanguageEvent(InitLanguageEvent event, Emitter<LanguageState> emit) { FutureOr<void> _initLanguageEvent(InitLanguageEvent event, Emitter<LanguageState> emit) {
final String selectedLanguage = LocalStorage.readData(key: MyConstants.selectLanguage).isEmpty
? 'fa'
: LocalStorage.readData(key: MyConstants.selectLanguage);
final String selectedLanguage = LocalStorage.readData(
key: MyConstants.selectLanguage) ?? 'fa';
emit(state.copyWith(selectedLang: LanguageEntity(code: selectedLanguage))); emit(state.copyWith(selectedLang: LanguageEntity(code: selectedLanguage)));
} }
} }

2
lib/features/level/data/datasource/level_datasource.dart

@ -18,7 +18,7 @@ class LocalLevelDatasourceImpl implements ILevelDatasource {
Future<List<LevelEntity>> getLevels({required LevelParams params}) async { Future<List<LevelEntity>> getLevels({required LevelParams params}) async {
try { try {
final String selectedLanguage = LocalStorage.readData( final String selectedLanguage = LocalStorage.readData(
key: MyConstants.selectLanguage);
key: MyConstants.selectLanguage) ?? 'fa';
final Box<TotalDataEntity> levelBox = Hive.box(MyConstants.levelBox); final Box<TotalDataEntity> levelBox = Hive.box(MyConstants.levelBox);
final TotalDataEntity findData = levelBox.values.singleWhere( final TotalDataEntity findData = levelBox.values.singleWhere(
(e) => e.code == selectedLanguage, (e) => e.code == selectedLanguage,

11
lib/features/level/presentation/bloc/level_bloc.dart

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -83,7 +84,7 @@ class LevelBloc extends Bloc<LevelEvent, LevelState> {
LevelType getLevelType(int index) { LevelType getLevelType(int index) {
final int currentLevel = int.parse( final int currentLevel = int.parse(
LocalStorage.readData(key: MyConstants.currentLevel),
LocalStorage.readData(key: MyConstants.currentLevel) ?? '1',
); );
if (index < currentLevel) { if (index < currentLevel) {
@ -99,7 +100,7 @@ class LevelBloc extends Bloc<LevelEvent, LevelState> {
FutureOr<void> _getLevelListEvent(GetLevelListEvent event, FutureOr<void> _getLevelListEvent(GetLevelListEvent event,
Emitter<LevelState> emit) async { Emitter<LevelState> emit) async {
final int currentLevel = int.parse( final int currentLevel = int.parse(
LocalStorage.readData(key: MyConstants.currentLevel),
LocalStorage.readData(key: MyConstants.currentLevel) ?? '1',
); );
await _getLeveslUseCase(LevelParams()).then((value) { await _getLeveslUseCase(LevelParams()).then((value) {
value.fold( value.fold(
@ -124,7 +125,7 @@ class LevelBloc extends Bloc<LevelEvent, LevelState> {
Emitter<LevelState> emit, Emitter<LevelState> emit,
) async { ) async {
final int currentLevel = int.parse( final int currentLevel = int.parse(
LocalStorage.readData(key: MyConstants.currentLevel),
LocalStorage.readData(key: MyConstants.currentLevel) ?? '1',
); );
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
@ -147,9 +148,9 @@ class LevelBloc extends Bloc<LevelEvent, LevelState> {
FutureOr<void> _setCurrentLevelEvent(SetCurrentLevelEvent event, FutureOr<void> _setCurrentLevelEvent(SetCurrentLevelEvent event,
Emitter<LevelState> emit) async { Emitter<LevelState> emit) async {
final String currentLevel = LocalStorage.readData(
final String? currentLevel = LocalStorage.readData(
key: MyConstants.currentLevel); key: MyConstants.currentLevel);
if (currentLevel.isEmpty) {
if (currentLevel == null || currentLevel.isEmpty) {
await LocalStorage.saveData(key: MyConstants.currentLevel, value: '1'); await LocalStorage.saveData(key: MyConstants.currentLevel, value: '1');
} }
add(GetLevelListEvent()); add(GetLevelListEvent());

2
lib/features/question/data/datasource/question_datasource.dart

@ -18,7 +18,7 @@ class QuestionDatasourceImpl implements IQuestionDatasource {
Future<LevelEntity> getLevel({required QuestionParams params}) async { Future<LevelEntity> getLevel({required QuestionParams params}) async {
try { try {
final String selectedLanguage = LocalStorage.readData( final String selectedLanguage = LocalStorage.readData(
key: MyConstants.selectLanguage);
key: MyConstants.selectLanguage) ?? 'fa';
final Box<TotalDataEntity> levelBox = Hive.box(MyConstants.levelBox); final Box<TotalDataEntity> levelBox = Hive.box(MyConstants.levelBox);
final TotalDataEntity findData = levelBox.values.singleWhere( final TotalDataEntity findData = levelBox.values.singleWhere(
(e) => e.code == selectedLanguage, (e) => e.code == selectedLanguage,

21
lib/init_bindings.dart

@ -1,14 +1,20 @@
import 'dart:io'; import 'dart:io';
import 'package:get_it/get_it.dart';
import 'package:hadi_hoda_flutter/core/constants/my_constants.dart'; import 'package:hadi_hoda_flutter/core/constants/my_constants.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/network/http_request_impl.dart'; import 'package:hadi_hoda_flutter/core/network/http_request_impl.dart';
import 'package:hadi_hoda_flutter/features/download/data/datasource/download_datasource.dart';
import 'package:hadi_hoda_flutter/features/download/data/repository_impl/download_repository_impl.dart';
import 'package:hadi_hoda_flutter/features/download/domain/repository/download_repository.dart';
import 'package:hadi_hoda_flutter/features/download/domain/usecases/get_audios_usecase.dart';
import 'package:hadi_hoda_flutter/features/download/domain/usecases/loading_stream_audio_usecase.dart';
import 'package:hadi_hoda_flutter/features/download/domain/usecases/save_levels_usecase.dart';
import 'package:hadi_hoda_flutter/features/intro/data/datasource/intro_datasource.dart'; import 'package:hadi_hoda_flutter/features/intro/data/datasource/intro_datasource.dart';
import 'package:hadi_hoda_flutter/features/intro/data/repository_impl/intro_repository_impl.dart'; import 'package:hadi_hoda_flutter/features/intro/data/repository_impl/intro_repository_impl.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/repository/intro_repository.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/get_files_usecase.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/get_images_usecase.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/loading_stream_usecase.dart'; import 'package:hadi_hoda_flutter/features/intro/domain/usecases/loading_stream_usecase.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/save_levels_usecase.dart';
import 'package:hadi_hoda_flutter/features/level/data/datasource/level_datasource.dart'; import 'package:hadi_hoda_flutter/features/level/data/datasource/level_datasource.dart';
import 'package:hadi_hoda_flutter/features/level/data/repository_impl/level_repository_impl.dart'; import 'package:hadi_hoda_flutter/features/level/data/repository_impl/level_repository_impl.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';
@ -26,7 +32,6 @@ import 'package:hadi_hoda_flutter/features/sample/data/datasource/sample_datasou
import 'package:hadi_hoda_flutter/features/sample/data/repository_impl/sample_repository_impl.dart'; import 'package:hadi_hoda_flutter/features/sample/data/repository_impl/sample_repository_impl.dart';
import 'package:hadi_hoda_flutter/features/sample/domain/repository/sample_repository.dart'; import 'package:hadi_hoda_flutter/features/sample/domain/repository/sample_repository.dart';
import 'package:hadi_hoda_flutter/features/sample/domain/usecases/get_sample_usecase.dart'; import 'package:hadi_hoda_flutter/features/sample/domain/usecases/get_sample_usecase.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
@ -44,10 +49,16 @@ void initBindings() {
/// Intro Feature /// Intro Feature
locator.registerLazySingleton<IIntroDatasource>(() => IntroDatasourceImpl(locator())); locator.registerLazySingleton<IIntroDatasource>(() => IntroDatasourceImpl(locator()));
locator.registerLazySingleton<IIntroRepository>(() => IntroRepositoryImpl(locator())); locator.registerLazySingleton<IIntroRepository>(() => IntroRepositoryImpl(locator()));
locator.registerLazySingleton<GetFilesUseCase>(() => GetFilesUseCase(locator()));
locator.registerLazySingleton<SaveLevelsUseCase>(() => SaveLevelsUseCase(locator()));
locator.registerLazySingleton<GetImagesUseCase>(() => GetImagesUseCase(locator()));
locator.registerLazySingleton<LoadingStreamUseCase>(() => LoadingStreamUseCase(locator())); locator.registerLazySingleton<LoadingStreamUseCase>(() => LoadingStreamUseCase(locator()));
/// Download Feature
locator.registerLazySingleton<IDownloadDatasource>(() => DownloadDatasourceImpl(locator()));
locator.registerLazySingleton<IDownloadRepository>(() => DownloadRepositoryImpl(locator()));
locator.registerLazySingleton<GetAudiosUseCase>(() => GetAudiosUseCase(locator()));
locator.registerLazySingleton<SaveLevelsUseCase>(() => SaveLevelsUseCase(locator()));
locator.registerLazySingleton<LoadingStreamAudioUseCase>(() => LoadingStreamAudioUseCase(locator()));
/// Language Feature /// Language Feature
/// Home Feature /// Home Feature

12
lib/main.dart

@ -1,13 +1,12 @@
import 'package:hadi_hoda_flutter/common_ui/theme/theme_service.dart';
import 'package:hadi_hoda_flutter/core/utils/local_storage.dart';
import 'package:hadi_hoda_flutter/core/utils/storage_path.dart';
import 'package:hadi_hoda_flutter/l10n/app_localizations.dart';
import 'package:hadi_hoda_flutter/init_bindings.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart'; import 'package:hadi_hoda_flutter/common_ui/theme/my_theme.dart';
import 'package:hadi_hoda_flutter/core/auth_storage/auth_storage.dart';
import 'package:hadi_hoda_flutter/common_ui/theme/theme_service.dart';
import 'package:hadi_hoda_flutter/core/routers/my_routes.dart'; import 'package:hadi_hoda_flutter/core/routers/my_routes.dart';
import 'package:hadi_hoda_flutter/core/utils/local_storage.dart';
import 'package:hadi_hoda_flutter/core/utils/storage_path.dart';
import 'package:hadi_hoda_flutter/init_bindings.dart';
import 'package:hadi_hoda_flutter/l10n/app_localizations.dart';
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -17,7 +16,6 @@ Future<void> main() async {
StoragePath.getDocumentDir(), StoragePath.getDocumentDir(),
initDataBase(), initDataBase(),
]); ]);
AuthStorage.loadData();
runApp(const MainApp()); runApp(const MainApp());
} }

Loading…
Cancel
Save