diff --git a/app/lib/models/models.dart b/app/lib/models/models.dart index 83372aaa..99040c0b 100644 --- a/app/lib/models/models.dart +++ b/app/lib/models/models.dart @@ -4,10 +4,6 @@ export 'hatim/hatim_read_model.dart'; export 'juz/juz_data.dart'; export 'juz/juz_model.dart'; export 'juz/juz_surah_model.dart'; -export 'quran_page/filters.dart'; -export 'quran_page/meta.dart'; -export 'quran_page/quran_page.dart'; -export 'quran_page/verse.dart'; export 'surah/surah_data.dart'; export 'surah/surah_model.dart'; export 'user/user_model.dart'; diff --git a/app/lib/modules/read/data/data.dart b/app/lib/modules/read/data/data.dart new file mode 100644 index 00000000..2bf8e1eb --- /dev/null +++ b/app/lib/modules/read/data/data.dart @@ -0,0 +1,4 @@ +export 'repository/read_repository_impl.dart'; +export 'repository/read_theme_repository_impl.dart'; +export 'source/source.dart'; +export 'model/quran_page.dart'; diff --git a/app/lib/models/quran_page/quran_page.dart b/app/lib/modules/read/data/model/quran_page.dart similarity index 96% rename from app/lib/models/quran_page/quran_page.dart rename to app/lib/modules/read/data/model/quran_page.dart index 734b2876..f3ddd528 100644 --- a/app/lib/models/quran_page/quran_page.dart +++ b/app/lib/modules/read/data/model/quran_page.dart @@ -2,8 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:my_quran/constants/contants.dart'; -import 'package:my_quran/models/models.dart'; - +import 'package:my_quran/modules/modules.dart'; part 'quran_page.g.dart'; @immutable diff --git a/app/lib/models/quran_page/quran_page.g.dart b/app/lib/modules/read/data/model/quran_page.g.dart similarity index 100% rename from app/lib/models/quran_page/quran_page.g.dart rename to app/lib/modules/read/data/model/quran_page.g.dart diff --git a/app/lib/modules/read/data/repository/read_repository_impl.dart b/app/lib/modules/read/data/repository/read_repository_impl.dart new file mode 100644 index 00000000..a253bf45 --- /dev/null +++ b/app/lib/modules/read/data/repository/read_repository_impl.dart @@ -0,0 +1,28 @@ +import 'dart:developer'; + +import 'package:my_quran/modules/modules.dart'; + +class ReadRepositoryImpl implements ReadRepository { + const ReadRepositoryImpl(this.remoteDataSource, this.localDataSource); + + final ReadRemoteDataSource remoteDataSource; + final ReadLocalDataSource localDataSource; + + @override + Future getPage(int page, String quranFmt) async { + try { + final localPage = await localDataSource.getPage(page, quranFmt); + final remotePage = await remoteDataSource.fetchPage(page, quranFmt); + if (remotePage != null) { + await localDataSource.cachePage(page, quranFmt, remotePage); + return remotePage; + } + if (localPage != null) { + return localPage; + } + } catch (e) { + log('Error fetching page locally and remotely: $e'); + } + return null; + } +} diff --git a/app/lib/modules/read/data/repository/read_theme_repository_impl.dart b/app/lib/modules/read/data/repository/read_theme_repository_impl.dart new file mode 100644 index 00000000..137a9169 --- /dev/null +++ b/app/lib/modules/read/data/repository/read_theme_repository_impl.dart @@ -0,0 +1,16 @@ +import 'package:my_quran/modules/modules.dart'; + +class ReadThemeRepositoryImpl implements ReadThemeRepository { + const ReadThemeRepositoryImpl({required this.localDataSource}); + final LocalThemeDataSource localDataSource; + + @override + Future getInitialThemeState() async { + return localDataSource.getInitialThemeState(); + } + + @override + Future saveThemeState(ReadThemeState themeState) async { + return localDataSource.saveThemeState(themeState); + } +} diff --git a/app/lib/modules/read/services/read_theme_service.dart b/app/lib/modules/read/data/source/local_theme_data_source.dart similarity index 60% rename from app/lib/modules/read/services/read_theme_service.dart rename to app/lib/modules/read/data/source/local_theme_data_source.dart index c1c499d9..a376e6ae 100644 --- a/app/lib/modules/read/services/read_theme_service.dart +++ b/app/lib/modules/read/data/source/local_theme_data_source.dart @@ -1,21 +1,20 @@ +import 'package:my_quran/constants/contants.dart'; +import 'package:my_quran/modules/modules.dart'; import 'dart:convert'; - import 'package:mq_storage/mq_storage.dart'; -import 'package:my_quran/constants/contants.dart'; -import 'package:my_quran/modules/read/logic/read_theme_cubit.dart'; -class ReadThemeService { - const ReadThemeService(this.storage); +class LocalThemeDataSource { + const LocalThemeDataSource(this.storage); final PreferencesStorage storage; - ReadThemeState get init { + ReadThemeState getInitialThemeState() { final value = storage.readString(key: AppConst.readThemeKey); return value != null ? ReadThemeState.fromJson(json.decode(value) as Map) : const ReadThemeState(); } - Future saveChanges(ReadThemeState theme) async { - final value = json.encode(theme.toJson()); + Future saveThemeState(ReadThemeState themeState) async { + final value = json.encode(themeState.toJson()); await storage.writeString(key: AppConst.readThemeKey, value: value); } } diff --git a/app/lib/modules/read/data/source/read_local_data_source.dart b/app/lib/modules/read/data/source/read_local_data_source.dart new file mode 100644 index 00000000..10e8ea06 --- /dev/null +++ b/app/lib/modules/read/data/source/read_local_data_source.dart @@ -0,0 +1,26 @@ +import 'dart:convert'; + +import 'package:mq_storage/mq_storage.dart'; +import 'package:my_quran/modules/modules.dart'; + +class ReadLocalDataSource { + const ReadLocalDataSource(this.storage); + + final PreferencesStorage storage; + + Future getPage(int page, String quranFmt) async { + final key = 'quran-$quranFmt-$page'; + final localValue = storage.readString(key: key); + + if (localValue != null) { + final data = jsonDecode(localValue); + return QuranPage.fromJson(data as Map); + } + return null; + } + + Future cachePage(int page, String quranFmt, QuranPage pageData) async { + final key = 'quran-$quranFmt-$page'; + await storage.writeString(key: key, value: jsonEncode(pageData.toJson())); + } +} diff --git a/app/lib/modules/read/data/source/read_remote_data_source.dart b/app/lib/modules/read/data/source/read_remote_data_source.dart new file mode 100644 index 00000000..36e0912a --- /dev/null +++ b/app/lib/modules/read/data/source/read_remote_data_source.dart @@ -0,0 +1,21 @@ +import 'package:my_quran/config/config.dart'; +import 'package:my_quran/core/core.dart'; +import 'package:my_quran/modules/modules.dart'; + +class ReadRemoteDataSource { + const ReadRemoteDataSource(this.remoteClient); + + final RemoteClient remoteClient; + + Future fetchPage(int page, String quranFmt) async { + final remoteValue = await remoteClient.get( + apiConst.verse(page, quranFmt), + fromJson: QuranPage.fromJson, + ); + + return remoteValue.fold( + (l) => throw Exception('Failed to fetch remote data $l'), + (r) => r, + ); + } +} diff --git a/app/lib/modules/read/data/source/source.dart b/app/lib/modules/read/data/source/source.dart new file mode 100644 index 00000000..9a7cb583 --- /dev/null +++ b/app/lib/modules/read/data/source/source.dart @@ -0,0 +1,3 @@ +export 'read_local_data_source.dart'; +export 'read_remote_data_source.dart'; +export 'local_theme_data_source.dart'; diff --git a/app/lib/modules/read/domain/domain.dart b/app/lib/modules/read/domain/domain.dart new file mode 100644 index 00000000..d252b8bf --- /dev/null +++ b/app/lib/modules/read/domain/domain.dart @@ -0,0 +1,4 @@ +export 'repository/read_repository.dart'; +export 'repository/read_theme_repository.dart'; +export 'usecase/usecase.dart'; +export 'entity/entity.dart'; diff --git a/app/lib/modules/read/domain/entity/entity.dart b/app/lib/modules/read/domain/entity/entity.dart new file mode 100644 index 00000000..0a44bd49 --- /dev/null +++ b/app/lib/modules/read/domain/entity/entity.dart @@ -0,0 +1,3 @@ +export 'filters.dart'; +export 'meta.dart'; +export 'verse.dart'; diff --git a/app/lib/models/quran_page/filters.dart b/app/lib/modules/read/domain/entity/filters.dart similarity index 100% rename from app/lib/models/quran_page/filters.dart rename to app/lib/modules/read/domain/entity/filters.dart diff --git a/app/lib/models/quran_page/filters.g.dart b/app/lib/modules/read/domain/entity/filters.g.dart similarity index 100% rename from app/lib/models/quran_page/filters.g.dart rename to app/lib/modules/read/domain/entity/filters.g.dart diff --git a/app/lib/models/quran_page/meta.dart b/app/lib/modules/read/domain/entity/meta.dart similarity index 88% rename from app/lib/models/quran_page/meta.dart rename to app/lib/modules/read/domain/entity/meta.dart index 40adba46..0172e44f 100644 --- a/app/lib/models/quran_page/meta.dart +++ b/app/lib/modules/read/domain/entity/meta.dart @@ -1,7 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; - -import 'package:my_quran/models/models.dart'; +import 'package:my_quran/modules/modules.dart'; part 'meta.g.dart'; diff --git a/app/lib/models/quran_page/meta.g.dart b/app/lib/modules/read/domain/entity/meta.g.dart similarity index 100% rename from app/lib/models/quran_page/meta.g.dart rename to app/lib/modules/read/domain/entity/meta.g.dart diff --git a/app/lib/models/quran_page/verse.dart b/app/lib/modules/read/domain/entity/verse.dart similarity index 100% rename from app/lib/models/quran_page/verse.dart rename to app/lib/modules/read/domain/entity/verse.dart diff --git a/app/lib/models/quran_page/verse.g.dart b/app/lib/modules/read/domain/entity/verse.g.dart similarity index 100% rename from app/lib/models/quran_page/verse.g.dart rename to app/lib/modules/read/domain/entity/verse.g.dart diff --git a/app/lib/modules/read/domain/repository/read_repository.dart b/app/lib/modules/read/domain/repository/read_repository.dart new file mode 100644 index 00000000..16f315c7 --- /dev/null +++ b/app/lib/modules/read/domain/repository/read_repository.dart @@ -0,0 +1,5 @@ +import 'package:my_quran/modules/modules.dart'; + +abstract class ReadRepository { + Future getPage(int page, String quranFmt); +} diff --git a/app/lib/modules/read/domain/repository/read_theme_repository.dart b/app/lib/modules/read/domain/repository/read_theme_repository.dart new file mode 100644 index 00000000..6653f133 --- /dev/null +++ b/app/lib/modules/read/domain/repository/read_theme_repository.dart @@ -0,0 +1,6 @@ +import 'package:my_quran/modules/modules.dart'; + +abstract class ReadThemeRepository { + Future getInitialThemeState(); + Future saveThemeState(ReadThemeState themeState); +} diff --git a/app/lib/modules/read/domain/usecase/get_initial_theme_usecase.dart b/app/lib/modules/read/domain/usecase/get_initial_theme_usecase.dart new file mode 100644 index 00000000..c49cd6f8 --- /dev/null +++ b/app/lib/modules/read/domain/usecase/get_initial_theme_usecase.dart @@ -0,0 +1,10 @@ +import 'package:my_quran/modules/modules.dart'; + +class GetInitialThemeUseCase { + const GetInitialThemeUseCase(this.repository); + final ReadThemeRepository repository; + + Future execute() { + return repository.getInitialThemeState(); + } +} diff --git a/app/lib/modules/read/domain/usecase/get_read_page.dart b/app/lib/modules/read/domain/usecase/get_read_page.dart new file mode 100644 index 00000000..2af1881f --- /dev/null +++ b/app/lib/modules/read/domain/usecase/get_read_page.dart @@ -0,0 +1,11 @@ +import 'package:my_quran/modules/modules.dart'; + +class GetReadPageUseCase { + const GetReadPageUseCase(this.repository); + + final ReadRepository repository; + + Future getPage(int page, String quranFmt) { + return repository.getPage(page, quranFmt); + } +} diff --git a/app/lib/modules/read/domain/usecase/save_theme_changes_usecase.dart b/app/lib/modules/read/domain/usecase/save_theme_changes_usecase.dart new file mode 100644 index 00000000..a07d7ece --- /dev/null +++ b/app/lib/modules/read/domain/usecase/save_theme_changes_usecase.dart @@ -0,0 +1,10 @@ +import 'package:my_quran/modules/modules.dart'; + +class SaveThemeChangesUseCase { + const SaveThemeChangesUseCase(this.repository); + final ReadThemeRepository repository; + + Future execute(ReadThemeState themeState) { + return repository.saveThemeState(themeState); + } +} diff --git a/app/lib/modules/read/domain/usecase/usecase.dart b/app/lib/modules/read/domain/usecase/usecase.dart new file mode 100644 index 00000000..10455866 --- /dev/null +++ b/app/lib/modules/read/domain/usecase/usecase.dart @@ -0,0 +1,3 @@ +export 'get_read_page.dart'; +export 'get_initial_theme_usecase.dart'; +export 'save_theme_changes_usecase.dart'; diff --git a/app/lib/modules/read/logic/read_cubit.dart b/app/lib/modules/read/logic/read_cubit.dart deleted file mode 100644 index 88d74eac..00000000 --- a/app/lib/modules/read/logic/read_cubit.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'package:my_quran/models/models.dart'; -import 'package:my_quran/modules/read/read.dart'; - -part 'read_state.dart'; - -class ReadCubit extends Cubit { - ReadCubit(this.repo, this.pages) : super(const ReadState()); - - final ReadService repo; - final List pages; - - Future getPage(int page) async { - return repo.gerVerses(page, state.fmt.name); - } -} diff --git a/app/lib/modules/read/presentation/logic/read_cubit.dart b/app/lib/modules/read/presentation/logic/read_cubit.dart new file mode 100644 index 00000000..7e5bc372 --- /dev/null +++ b/app/lib/modules/read/presentation/logic/read_cubit.dart @@ -0,0 +1,15 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:my_quran/modules/modules.dart'; + +part 'read_state.dart'; + +class ReadCubit extends Cubit { + ReadCubit(this.getQuranPageUseCase) : super(const ReadState()); + + final GetReadPageUseCase getQuranPageUseCase; + + Future fetchQuranPage(int page) async { + return getQuranPageUseCase.getPage(page, state.fmt.name); + } +} diff --git a/app/lib/modules/read/logic/read_state.dart b/app/lib/modules/read/presentation/logic/read_state.dart similarity index 100% rename from app/lib/modules/read/logic/read_state.dart rename to app/lib/modules/read/presentation/logic/read_state.dart diff --git a/app/lib/modules/read/logic/read_theme_cubit.dart b/app/lib/modules/read/presentation/logic/read_theme_cubit.dart similarity index 59% rename from app/lib/modules/read/logic/read_theme_cubit.dart rename to app/lib/modules/read/presentation/logic/read_theme_cubit.dart index bf1e118c..bdae4643 100644 --- a/app/lib/modules/read/logic/read_theme_cubit.dart +++ b/app/lib/modules/read/presentation/logic/read_theme_cubit.dart @@ -1,14 +1,20 @@ import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; - import 'package:my_quran/modules/modules.dart'; part 'read_theme_state.dart'; class ReadThemeCubit extends Cubit { - ReadThemeCubit(this.service) : super(service.init); + ReadThemeCubit({required this.getInitialThemeUseCase, required this.saveThemeChangesUseCase}) + : super(const ReadThemeState()); + + final GetInitialThemeUseCase getInitialThemeUseCase; + final SaveThemeChangesUseCase saveThemeChangesUseCase; - final ReadThemeService service; + Future initializeTheme() async { + final themeState = await getInitialThemeUseCase.execute(); + emit(themeState); + } void changeMode(int index) { emit(state.copyWith(modeIndex: index)); @@ -27,6 +33,6 @@ class ReadThemeCubit extends Cubit { } Future saveChanges() async { - await service.saveChanges(state); + await saveThemeChangesUseCase.execute(state); } } diff --git a/app/lib/modules/read/logic/read_theme_state.dart b/app/lib/modules/read/presentation/logic/read_theme_state.dart similarity index 100% rename from app/lib/modules/read/logic/read_theme_state.dart rename to app/lib/modules/read/presentation/logic/read_theme_state.dart diff --git a/app/lib/modules/read/presentation/presentation.dart b/app/lib/modules/read/presentation/presentation.dart new file mode 100644 index 00000000..56a31db8 --- /dev/null +++ b/app/lib/modules/read/presentation/presentation.dart @@ -0,0 +1,4 @@ +export 'logic/read_cubit.dart'; +export 'logic/read_theme_cubit.dart'; +export 'view/read_view.dart'; +export 'view/pagination_view.dart'; diff --git a/app/lib/modules/read/view/pagination_view.dart b/app/lib/modules/read/presentation/view/pagination_view.dart similarity index 98% rename from app/lib/modules/read/view/pagination_view.dart rename to app/lib/modules/read/presentation/view/pagination_view.dart index 7271b41b..0ff793d5 100644 --- a/app/lib/modules/read/view/pagination_view.dart +++ b/app/lib/modules/read/presentation/view/pagination_view.dart @@ -36,7 +36,7 @@ class _PaginationViewState extends State { Future _fetchPage(int i) async { try { final page = widget.pages[_index]; - final newItems = await context.read().getPage(page); + final newItems = await context.read().fetchQuranPage(page); _index++; if (page == widget.pages.last && newItems != null) { _pagingController.appendLastPage([newItems]); diff --git a/app/lib/modules/read/view/read_view.dart b/app/lib/modules/read/presentation/view/read_view.dart similarity index 89% rename from app/lib/modules/read/view/read_view.dart rename to app/lib/modules/read/presentation/view/read_view.dart index 3e84f4ca..f8ab9e03 100644 --- a/app/lib/modules/read/view/read_view.dart +++ b/app/lib/modules/read/presentation/view/read_view.dart @@ -29,11 +29,28 @@ class ReadView extends StatelessWidget { providers: [ BlocProvider( create: (context) => ReadCubit( - ReadService(context.read(), context.read()), - pages, + GetReadPageUseCase( + ReadRepositoryImpl( + ReadRemoteDataSource(context.read()), + ReadLocalDataSource(context.read()), + ), + ), + ), + ), + BlocProvider( + create: (context) => ReadThemeCubit( + getInitialThemeUseCase: GetInitialThemeUseCase( + ReadThemeRepositoryImpl( + localDataSource: LocalThemeDataSource(context.read()), + ), + ), + saveThemeChangesUseCase: SaveThemeChangesUseCase( + ReadThemeRepositoryImpl( + localDataSource: LocalThemeDataSource(context.read()), + ), + ), ), ), - BlocProvider(create: (context) => ReadThemeCubit(ReadThemeService(context.read()))), ], child: ReadUI(pages: pages, isHatim: isHatim), ); diff --git a/app/lib/modules/read/read.dart b/app/lib/modules/read/read.dart index 23851c7a..aeeb7088 100644 --- a/app/lib/modules/read/read.dart +++ b/app/lib/modules/read/read.dart @@ -1,6 +1,3 @@ -export 'logic/read_cubit.dart'; -export 'logic/read_theme_cubit.dart'; -export 'services/read_service.dart'; -export 'services/read_theme_service.dart'; -export 'view/pagination_view.dart'; -export 'view/read_view.dart'; +export 'data/data.dart'; +export 'domain/domain.dart'; +export 'presentation/presentation.dart'; diff --git a/app/lib/modules/read/services/read_service.dart b/app/lib/modules/read/services/read_service.dart deleted file mode 100644 index 66d508a5..00000000 --- a/app/lib/modules/read/services/read_service.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'dart:convert'; - -import 'package:mq_storage/mq_storage.dart'; -import 'package:my_quran/config/config.dart'; -import 'package:my_quran/core/core.dart'; -import 'package:my_quran/models/models.dart'; - -class ReadService { - const ReadService(this.remoteClient, this.storage); - - final RemoteClient remoteClient; - final PreferencesStorage storage; - - Future gerVerses(int page, String quranFmt) async { - final key = 'quran-$quranFmt-$page'; - final localvalue = storage.readString(key: key); - if (localvalue != null) { - final data = jsonDecode(localvalue); - return QuranPage.fromJson(data as Map); - } else { - final remoteValue = await remoteClient.get( - apiConst.verse(page, quranFmt), - fromJson: QuranPage.fromJson, - ); - - return remoteValue.fold( - (l) => null, - (r) async { - await storage.writeString(key: key, value: jsonEncode(r.toJson())); - return r; - }, - ); - } - } -}