Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change home architecture #190

Merged
merged 7 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ linter:
sort_pub_dependencies: false
lines_longer_than_80_chars: false
directives_ordering: false
one_member_abstracts: false

analyzer:
exclude:
Expand Down
8 changes: 5 additions & 3 deletions app/lib/app/view/app_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ class MyApp extends StatelessWidget {
),
BlocProvider(
create: (context) => HomeCubit(
HomeService(
context.read<PreferencesStorage>(),
context.read<RemoteClient>(),
GetHomeDataUseCase(
HomeRepositoryImpl(
HomeLocalDataSource(context.read<PreferencesStorage>()),
HomeRemoteDataSource(context.read<RemoteClient>()),
),
Comment on lines +34 to +38
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow 🤩

),
),
),
Expand Down
19 changes: 0 additions & 19 deletions app/lib/models/home/home_model.dart

This file was deleted.

3 changes: 1 addition & 2 deletions app/lib/models/models.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export 'hatim/hatim_juz.dart';
export 'home/home_model.dart';
export 'home/hatim_read_model.dart';
export 'hatim/hatim_page.dart';
export 'hatim/hatim_read_model.dart';
export 'juz/juz_data.dart';
export 'juz/juz_model.dart';
export 'juz/juz_surah_model.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'package:my_quran/core/core.dart';
import 'package:my_quran/models/models.dart';
import 'package:my_quran/modules/modules.dart';
Expand Down
4 changes: 4 additions & 0 deletions app/lib/modules/home/data/data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export 'model/home_model_response.dart';
export 'repository/home_repository.dart';
export 'source/home_local_data_source.dart';
export 'source/home_remote_data_source.dart';
19 changes: 19 additions & 0 deletions app/lib/modules/home/data/model/home_model_response.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:json_annotation/json_annotation.dart';

part 'home_model_response.g.dart';

@JsonSerializable()
class HomeModelResponse {
const HomeModelResponse({
required this.allDoneHatims,
required this.allDonePages,
required this.donePages,
});

factory HomeModelResponse.fromJson(Map<String, dynamic> json) => _$HomeModelResponseFromJson(json);
Map<String, dynamic> toJson() => _$HomeModelResponseToJson(this);

final int allDoneHatims;
final int allDonePages;
final int donePages;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions app/lib/modules/home/data/repository/home_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'dart:developer';

import 'package:my_quran/modules/modules.dart';

class HomeRepositoryImpl implements HomeRepository {
const HomeRepositoryImpl(
this.localDataSource,
this.remoteDataSource,
);

final HomeLocalDataSource localDataSource;
final HomeRemoteDataSource remoteDataSource;

@override
Future<HomeModel> getData(String token) async {
try {
final remoteData = await remoteDataSource.getRemoteData(token);
await localDataSource.saveLocalData(remoteData);
return _convertData(remoteData);
} catch (e) {
log('HomeRepositoryImpl, getData error: $e');
return _convertData(localDataSource.getLocalData());
}
}

HomeModel _convertData(HomeModelResponse response) {
return HomeModel(
allDoneHatims: response.allDoneHatims,
allDonePages: response.allDonePages,
donePages: response.donePages,
);
}
}
25 changes: 25 additions & 0 deletions app/lib/modules/home/data/source/home_local_data_source.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'dart:convert';
import 'package:mq_storage/mq_storage.dart';
import 'package:my_quran/modules/modules.dart';

class HomeLocalDataSource {
const HomeLocalDataSource(this.storage);

final PreferencesStorage storage;

static const _homeDataCacheKey = 'home-model';

HomeModelResponse getLocalData() {
final localValue = storage.readString(key: _homeDataCacheKey);
if (localValue != null) {
final data = jsonDecode(localValue);
return HomeModelResponse.fromJson(data as Map<String, dynamic>);
} else {
return const HomeModelResponse(allDoneHatims: 0, allDonePages: 0, donePages: 0);
}
}

Future<void> saveLocalData(HomeModelResponse data) async {
await storage.writeString(key: _homeDataCacheKey, value: jsonEncode(data.toJson()));
}
}
22 changes: 22 additions & 0 deletions app/lib/modules/home/data/source/home_remote_data_source.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:my_quran/config/config.dart';
import 'package:my_quran/core/core.dart';
import 'package:my_quran/modules/modules.dart';

class HomeRemoteDataSource {
const HomeRemoteDataSource(this.remoteClient);

final RemoteClient remoteClient;

Future<HomeModelResponse> getRemoteData(String token) async {
final remoteValue = await remoteClient.get<HomeModelResponse>(
apiConst.home,
fromJson: HomeModelResponse.fromJson,
token: token,
);

return remoteValue.fold(
(left) => throw Exception('Failed to fetch remote data $left'),
(right) => right,
);
}
}
3 changes: 3 additions & 0 deletions app/lib/modules/home/domain/domain.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export 'entity/home_model.dart';
export 'repository/home_repository.dart';
export 'usecase/get_data_usecase.dart';
11 changes: 11 additions & 0 deletions app/lib/modules/home/domain/entity/home_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class HomeModel {
const HomeModel({
required this.allDoneHatims,
required this.allDonePages,
required this.donePages,
});

final int allDoneHatims;
final int allDonePages;
final int donePages;
}
5 changes: 5 additions & 0 deletions app/lib/modules/home/domain/repository/home_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'package:my_quran/modules/modules.dart';

abstract class HomeRepository {
Future<HomeModel> getData(String token);
}
11 changes: 11 additions & 0 deletions app/lib/modules/home/domain/usecase/get_data_usecase.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:my_quran/modules/modules.dart';

class GetHomeDataUseCase {
const GetHomeDataUseCase(this.repository);

final HomeRepository repository;

Future<HomeModel> execute(String token) {
return repository.getData(token);
}
}
7 changes: 3 additions & 4 deletions app/lib/modules/home/home.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export 'logic/home_cubit.dart';
export 'view/home_view.dart';
export 'widgets/home_card.dart';
export 'service/home_service.dart';
export 'data/data.dart';
export 'domain/domain.dart';
export 'presentation/presentation.dart';
19 changes: 0 additions & 19 deletions app/lib/modules/home/logic/home_cubit.dart

This file was deleted.

21 changes: 21 additions & 0 deletions app/lib/modules/home/presentation/cubit/home_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:my_quran/core/core.dart';
import 'package:my_quran/modules/modules.dart';

part 'home_state.dart';

class HomeCubit extends Cubit<HomeState> {
HomeCubit(this.getHomeDataUseCase) : super(const HomeState());

final GetHomeDataUseCase getHomeDataUseCase;

Future<void> getData(String token) async {
try {
final homeModel = await getHomeDataUseCase.execute(token);
emit(HomeState(status: FetchStatus.success, homeModel: homeModel));
} catch (_) {
emit(const HomeState(status: FetchStatus.error));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
part of 'home_cubit.dart';

class HomeState extends Equatable {
const HomeState(this.status, {this.homeModel});
const HomeState({
this.status = FetchStatus.loading,
this.homeModel,
});

final HomeModel? homeModel;
final FetchStatus status;

@override
List<Object?> get props => [homeModel];
List<Object?> get props => [homeModel, status];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

}
3 changes: 3 additions & 0 deletions app/lib/modules/home/presentation/presentation.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export 'cubit/home_cubit.dart';
export 'view/home_view.dart';
export 'widgets/home_card.dart';
37 changes: 0 additions & 37 deletions app/lib/modules/home/service/home_service.dart

This file was deleted.

4 changes: 2 additions & 2 deletions app/test/helpers/pump_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extension PumpApp on WidgetTester {
AppService appService,
ThemeService themeService,
AuthService authStorage,
HomeService homeService,
HomeRepository homeRepo,
) {
return pumpWidget(
RepositoryProvider(
Expand All @@ -19,7 +19,7 @@ extension PumpApp on WidgetTester {
providers: [
BlocProvider(create: (context) => AppCubit(appService, themeService)),
BlocProvider(create: (context) => AuthCubit(authStorage)),
BlocProvider(create: (context) => HomeCubit(homeService)),
BlocProvider(create: (context) => HomeCubit(GetHomeDataUseCase(homeRepo))),
],
child: const QuranApp(),
),
Expand Down
15 changes: 10 additions & 5 deletions app/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,30 @@ import 'package:mq_storage/mq_storage.dart';
import 'package:my_quran/app/app.dart';
import 'package:my_quran/constants/contants.dart';
import 'package:my_quran/core/core.dart';
import 'package:my_quran/modules/home/home.dart';
import 'package:my_quran/modules/modules.dart';

import 'helpers/helpers.dart';

final class MockPreferencesStorage extends Mock implements PreferencesStorage {}

final class MockRemoteClient extends Mock implements RemoteClient {}

final class MockHomeRepositoryImpl implements HomeRepository {
@override
Future<HomeModel> getData(String token) async {
return const HomeModel(allDoneHatims: 8, allDonePages: 5325, donePages: 634);
}
}

// flutter test

void main() {
testWidgets('Punmp app', (WidgetTester tester) async {
final storage = MockPreferencesStorage();
final remoteClient = MockRemoteClient();

final appService = AppService(storage);
final authStorage = AuthService(storage, remoteClient);
final homeService = HomeService(storage, remoteClient);
final homeRepo = MockHomeRepositoryImpl();
final themeService = ThemeService(storage);

when(() => storage.readString(key: AppConst.tokenKey)).thenReturn(null);
Expand All @@ -32,8 +38,7 @@ void main() {
when(() => storage.readString(key: AppConst.modeKey)).thenReturn(null);
when(() => storage.readString(key: AppConst.colorKey)).thenReturn(null);

// // Build our app and trigger a frame.
await tester.pumpApp(appService, themeService, authStorage, homeService);
await tester.pumpApp(appService, themeService, authStorage, homeRepo);
await tester.pumpAndSettle();
expect(find.byType(MaterialApp), findsOneWidget);
});
Expand Down
Loading