Browse Source

add: loading logic and extract data

pull/9/head
AmirrezaChegini 7 days ago
parent
commit
2fbbddb8a5
  1. 2
      lib/core/routers/my_routes.dart
  2. 54
      lib/features/intro/data/datasource/intro_datasource.dart
  3. 21
      lib/features/intro/data/repository_impl/intro_repository_impl.dart
  4. 2
      lib/features/intro/domain/repository/intro_repository.dart
  5. 16
      lib/features/intro/domain/usecases/extract_data_usecase.dart
  6. 11
      lib/features/intro/domain/usecases/loading_stream_usecase.dart
  7. 28
      lib/features/intro/presentation/bloc/intro_bloc.dart
  8. 1
      lib/features/intro/presentation/bloc/intro_event.dart
  9. 5
      lib/features/intro/presentation/ui/intro_page.dart
  10. 15
      lib/features/intro/presentation/ui/widgets/intro_loading_widget.dart
  11. 4
      lib/init_bindings.dart
  12. 8
      pubspec.lock
  13. 1
      pubspec.yaml

2
lib/core/routers/my_routes.dart

@ -31,7 +31,7 @@ GoRouter get appPages => GoRouter(
name: Routes.introPage,
path: Routes.introPage,
builder: (context, state) => BlocProvider(
create: (context) => IntroBloc(locator()),
create: (context) => IntroBloc(locator(), locator(), locator()),
child: const IntroPage(),
),
),

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

@ -1,6 +1,9 @@
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';
@ -8,15 +11,19 @@ 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/domain/entity/level_entity.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
abstract class IIntroDatasource {
Future<void> saveLevels();
Future<void> extractData();
Stream<double> loadingStream();
}
class IntroDatasourceImpl implements IIntroDatasource {
final IHttpRequest httpRequest;
final StreamController<double> streamController = StreamController<double>.broadcast();
const IntroDatasourceImpl(this.httpRequest);
IntroDatasourceImpl(this.httpRequest);
@override
Future<void> saveLevels() async {
@ -38,4 +45,49 @@ class IntroDatasourceImpl implements IIntroDatasource {
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;
}

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

@ -25,4 +25,25 @@ class IntroRepositoryImpl implements IIntroRepository {
}
}
}
@override
Future<DataState<NoParams, MyException>> extractData() async {
try {
await datasource.extractData();
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<double> loadingStream() {
return datasource.loadingStream();
}
}

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

@ -4,4 +4,6 @@ import 'package:hadi_hoda_flutter/core/utils/data_state.dart';
abstract class IIntroRepository {
Future<DataState<NoParams, MyException>> saveLevels();
Future<DataState<NoParams, MyException>> extractData();
Stream<double> loadingStream();
}

16
lib/features/intro/domain/usecases/extract_data_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/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();
}
}

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

@ -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();
}
}

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

@ -4,6 +4,8 @@ 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/utils/context_provider.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/extract_data_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_state.dart';
@ -12,14 +14,21 @@ class IntroBloc extends Bloc<IntroEvent, IntroState> {
/// ------------constructor------------
IntroBloc(
this._saveLevelsUseCase,
this._extractDataUseCase,
this._loadingStreamUseCase,
) : super(const IntroState()) {
on<SaveLevelsEvent>(_saveLevelsEvent);
on<ExtractDataEvent>(_extractDataEvent);
loadingStream = _loadingStreamUseCase();
}
/// ------------UseCases------------
final SaveLevelsUseCase _saveLevelsUseCase;
final ExtractDataUseCase _extractDataUseCase;
final LoadingStreamUseCase _loadingStreamUseCase;
/// ------------Variables------------
Stream<double> loadingStream = Stream.empty();
/// ------------Controllers------------
@ -29,6 +38,21 @@ class IntroBloc extends Bloc<IntroEvent, IntroState> {
FutureOr<void> _saveLevelsEvent(SaveLevelsEvent event,
Emitter<IntroState> emit) async {
await _saveLevelsUseCase(NoParams()).then(
(value) {
value.fold(
(data) async {
add(ExtractDataEvent());
},
(error) {},
);
},
);
}
FutureOr<void> _extractDataEvent(ExtractDataEvent event,
Emitter<IntroState> emit) async {
await _extractDataUseCase(NoParams()).then(
(value) {
value.fold(
(data) async {
@ -38,7 +62,9 @@ class IntroBloc extends Bloc<IntroEvent, IntroState> {
},
);
},
(error) {},
(error) {
print(error.errorMessage);
},
);
},
);

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

@ -3,3 +3,4 @@ sealed class IntroEvent {
}
class SaveLevelsEvent extends IntroEvent {}
class ExtractDataEvent extends IntroEvent {}

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

@ -57,7 +57,10 @@ class _IntroPageState extends State<IntroPage> {
Positioned _loading(BuildContext context) {
return Positioned(
bottom: MediaQuery.viewPaddingOf(context).bottom,
child: IntroLoadingWidget(percent: 80),
child: IntroLoadingWidget(
percent: 80,
loadingStream: context.read<IntroBloc>().loadingStream,
),
);
}
}

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

@ -7,9 +7,11 @@ class IntroLoadingWidget extends StatelessWidget {
const IntroLoadingWidget({
super.key,
this.percent,
this.loadingStream,
});
final double? percent;
final Stream<double>? loadingStream;
@override
Widget build(BuildContext context) {
@ -32,7 +34,12 @@ class IntroLoadingWidget extends StatelessWidget {
],
),
),
child: Row(
child: StreamBuilder<double>(
initialData: 0,
stream: loadingStream,
builder: (context, snapshot) {
print(snapshot.data);
return Row(
children: [
Expanded(
flex: 85,
@ -41,7 +48,7 @@ class IntroLoadingWidget extends StatelessWidget {
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: EdgeInsetsDirectional.only(
end: 260 - ((percent ?? 0) * 260 / 100),
end: 260 - ((snapshot.data ?? 0) * 260 / 100),
),
decoration: BoxDecoration(
color: Color(0xFF1F59BD).withValues(alpha: 0.25),
@ -67,7 +74,7 @@ class IntroLoadingWidget extends StatelessWidget {
flex: 15,
child: Center(
child: Text(
'${percent?.toInt() ?? 0}%',
'${snapshot.data?.toInt() ?? 0}%',
style: MyTextStyle.normal17.copyWith(
color: Color(0XFF6E83A8),
),
@ -75,6 +82,8 @@ class IntroLoadingWidget extends StatelessWidget {
),
),
],
);
}
),
),
);

4
lib/init_bindings.dart

@ -10,6 +10,8 @@ import 'package:hadi_hoda_flutter/features/home/domain/usecases/get_home_usecase
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/domain/repository/intro_repository.dart';
import 'package:hadi_hoda_flutter/features/intro/domain/usecases/extract_data_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/repository_impl/level_repository_impl.dart';
@ -46,6 +48,8 @@ void initBindings() {
locator.registerLazySingleton<IIntroDatasource>(() => IntroDatasourceImpl(locator()));
locator.registerLazySingleton<IIntroRepository>(() => IntroRepositoryImpl(locator()));
locator.registerLazySingleton<SaveLevelsUseCase>(() => SaveLevelsUseCase(locator()));
locator.registerLazySingleton<ExtractDataUseCase>(() => ExtractDataUseCase(locator()));
locator.registerLazySingleton<LoadingStreamUseCase>(() => LoadingStreamUseCase(locator()));
/// Home Feature
locator.registerLazySingleton<IHomeDatasource>(() => HomeDatasourceImpl(locator()));

8
pubspec.lock

@ -254,6 +254,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_archive:
dependency: "direct main"
description:
name: flutter_archive
sha256: "5ca235f304c12bf468979235f400f79846d204169d715939e39197106f5fc970"
url: "https://pub.dev"
source: hosted
version: "6.0.3"
flutter_bloc:
dependency: "direct main"
description:

1
pubspec.yaml

@ -13,6 +13,7 @@ dependencies:
equatable: ^2.0.7
flutter:
sdk: flutter
flutter_archive: ^6.0.3
flutter_bloc: ^9.1.1
flutter_localizations:
sdk: flutter

Loading…
Cancel
Save