diff --git a/app/lib/modules/hatim/data/data.dart b/app/lib/modules/hatim/data/data.dart index 4ed7b786..57e0cfa3 100644 --- a/app/lib/modules/hatim/data/data.dart +++ b/app/lib/modules/hatim/data/data.dart @@ -2,5 +2,7 @@ export 'model/hatim_read_model.dart'; export 'model/hatim_juz.dart'; export 'model/hatim_page.dart'; export 'model/hatim_base_response.dart'; +export 'source/remote/hatim_remote_data_source_impl.dart'; export 'source/hatim_remote_data_source.dart'; +export 'source/mock/hatim_remote_data_source_mock.dart'; export 'repository/hatim_read_repository_impl.dart'; diff --git a/app/lib/modules/hatim/data/source/hatim_remote_data_source.dart b/app/lib/modules/hatim/data/source/hatim_remote_data_source.dart index 8c14b38f..108ae8f2 100644 --- a/app/lib/modules/hatim/data/source/hatim_remote_data_source.dart +++ b/app/lib/modules/hatim/data/source/hatim_remote_data_source.dart @@ -1,102 +1,15 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:my_quran/config/config.dart'; -import 'package:my_quran/core/core.dart'; import 'package:my_quran/modules/modules.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; - -class HatimRemoteDataSource { - HatimRemoteDataSource({ - required this.remoteClient, - }); - - final MqDio remoteClient; - - late final WebSocketChannel channel; - bool isInitilized = false; - - Future getHatim() async { - try { - final res = await remoteClient.postType( - apiConst.joinToHatim, - fromJson: HatimReadModel.fromJson, - ); - - return res.fold((l) => throw l, (r) => r); - } catch (e, s) { - MqCrashlytics.report(e, s); - throw Exception(e); - } - } - - void connectToSocket(String token) { - if (!isInitilized) { - channel = WebSocketChannel.connect( - Uri.parse(apiConst.getSocket(token)), - ); - isInitilized = true; - } - } - - void sinkHatimJuzs(String hatimId) { - final data = { - 'type': 'list_of_juz', - 'hatim_id': hatimId, - }; - channel.sink.add(json.encode(data)); - } - - void sinkHatimUserPages() { - final data = { - 'type': 'user_pages', - }; - channel.sink.add(jsonEncode(data)); - } - - void sinkHatimJuzPages(String juzId) { - final data = { - 'type': 'list_of_page', - 'juz_id': juzId, - }; - channel.sink.add(jsonEncode(data)); - } - - void sinkSelectPage(String pageId) { - final data = { - 'type': 'book', - 'pageId': pageId, - }; - channel.sink.add(jsonEncode(data)); - } - - void sinkUnSelectPage(String pageId) { - final data = { - 'type': 'to_do', - 'pageId': pageId, - }; - channel.sink.add(jsonEncode(data)); - } - - void sinkInProgressPages(List pageIds) { - final data = { - 'type': 'in_progress', - 'pageIds': pageIds, - }; - channel.sink.add(jsonEncode(data)); - } - - void sinkDonePages(List pageIds) { - final data = { - 'type': 'done', - 'pageIds': pageIds, - }; - channel.sink.add(jsonEncode(data)); - } - - Future close() async { - await channel.sink.close(); - } - Stream get stream => channel.stream; +abstract class HatimRemoteDataSource { + Future getHatim(); + void connectToSocket(String token); + void sinkHatimJuzs(String hatimId); + void sinkHatimUserPages(); + void sinkHatimJuzPages(String juzId); + void sinkSelectPage(String pageId); + void sinkUnSelectPage(String pageId); + void sinkInProgressPages(List pageIds); + void sinkDonePages(List pageIds); + Future close(); + Stream get stream; } diff --git a/app/lib/modules/hatim/data/source/mock/hatim_remote_data_source_mock.dart b/app/lib/modules/hatim/data/source/mock/hatim_remote_data_source_mock.dart new file mode 100644 index 00000000..afb3f903 --- /dev/null +++ b/app/lib/modules/hatim/data/source/mock/hatim_remote_data_source_mock.dart @@ -0,0 +1,90 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:my_quran/modules/modules.dart'; + +class HatimRemoteDataSourceMock implements HatimRemoteDataSource { + final StreamController _controller = StreamController(); + + @override + Future getHatim() async { + return const HatimReadModel( + id: '1', + status: 'done', + type: 'user_pages', + ); + } + + @override + void connectToSocket(String token) {} + + @override + void sinkHatimJuzs(String hatimId) { + final data = { + 'type': 'list_of_juz', + 'hatim_id': hatimId, + }; + _controller.add(json.encode(data)); + } + + @override + void sinkHatimUserPages() { + final data = { + 'type': 'user_pages', + }; + _controller.add(jsonEncode(data)); + } + + @override + void sinkHatimJuzPages(String juzId) { + final data = { + 'type': 'list_of_page', + 'juz_id': juzId, + }; + _controller.add(jsonEncode(data)); + } + + @override + void sinkSelectPage(String pageId) { + final data = { + 'type': 'book', + 'pageId': pageId, + }; + _controller.add(jsonEncode(data)); + } + + @override + void sinkUnSelectPage(String pageId) { + final data = { + 'type': 'to_do', + 'pageId': pageId, + }; + _controller.add(jsonEncode(data)); + } + + @override + void sinkInProgressPages(List pageIds) { + final data = { + 'type': 'in_progress', + 'pageIds': pageIds, + }; + _controller.add(jsonEncode(data)); + } + + @override + void sinkDonePages(List pageIds) { + final data = { + 'type': 'done', + 'pageIds': pageIds, + }; + _controller.add(jsonEncode(data)); + } + + @override + Future close() async { + await _controller.close(); + } + + @override + Stream get stream => _controller.stream; +} diff --git a/app/lib/modules/hatim/data/source/remote/hatim_remote_data_source_impl.dart b/app/lib/modules/hatim/data/source/remote/hatim_remote_data_source_impl.dart new file mode 100644 index 00000000..f879c5ae --- /dev/null +++ b/app/lib/modules/hatim/data/source/remote/hatim_remote_data_source_impl.dart @@ -0,0 +1,113 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:my_quran/config/config.dart'; +import 'package:my_quran/core/core.dart'; +import 'package:my_quran/modules/modules.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +class HatimRemoteDataSourceImpl implements HatimRemoteDataSource { + HatimRemoteDataSourceImpl({ + required this.remoteClient, + }); + + final MqDio remoteClient; + + late final WebSocketChannel channel; + bool isInitilized = false; + + @override + Future getHatim() async { + try { + final res = await remoteClient.postType( + apiConst.joinToHatim, + fromJson: HatimReadModel.fromJson, + ); + + return res.fold((l) => throw l, (r) => r); + } catch (e, s) { + MqCrashlytics.report(e, s); + throw Exception(e); + } + } + + @override + void connectToSocket(String token) { + if (!isInitilized) { + channel = WebSocketChannel.connect( + Uri.parse(apiConst.getSocket(token)), + ); + isInitilized = true; + } + } + + @override + void sinkHatimJuzs(String hatimId) { + final data = { + 'type': 'list_of_juz', + 'hatim_id': hatimId, + }; + channel.sink.add(json.encode(data)); + } + + @override + void sinkHatimUserPages() { + final data = { + 'type': 'user_pages', + }; + channel.sink.add(jsonEncode(data)); + } + + @override + void sinkHatimJuzPages(String juzId) { + final data = { + 'type': 'list_of_page', + 'juz_id': juzId, + }; + channel.sink.add(jsonEncode(data)); + } + + @override + void sinkSelectPage(String pageId) { + final data = { + 'type': 'book', + 'pageId': pageId, + }; + channel.sink.add(jsonEncode(data)); + } + + @override + void sinkUnSelectPage(String pageId) { + final data = { + 'type': 'to_do', + 'pageId': pageId, + }; + channel.sink.add(jsonEncode(data)); + } + + @override + void sinkInProgressPages(List pageIds) { + final data = { + 'type': 'in_progress', + 'pageIds': pageIds, + }; + channel.sink.add(jsonEncode(data)); + } + + @override + void sinkDonePages(List pageIds) { + final data = { + 'type': 'done', + 'pageIds': pageIds, + }; + channel.sink.add(jsonEncode(data)); + } + + @override + Future close() async { + await channel.sink.close(); + } + + @override + Stream get stream => channel.stream; +} diff --git a/app/lib/modules/hatim/presentation/view/hatim_view.dart b/app/lib/modules/hatim/presentation/view/hatim_view.dart index 21fb4488..61bed184 100644 --- a/app/lib/modules/hatim/presentation/view/hatim_view.dart +++ b/app/lib/modules/hatim/presentation/view/hatim_view.dart @@ -19,9 +19,9 @@ class HatimView extends StatelessWidget { return BlocProvider( create: (context) => HatimBloc( repo: HatimReadRepositoryImpl( - dataSource: HatimRemoteDataSource( - remoteClient: context.read(), - ), + dataSource: context.read().isMockData + ? HatimRemoteDataSourceMock() + : HatimRemoteDataSourceImpl(remoteClient: context.read()), ), token: context.read().state.user!.accessToken, )..add(const GetInitailDataEvent()), diff --git a/app/lib/modules/read/data/data.dart b/app/lib/modules/read/data/data.dart index edec7ecf..59ee3cef 100644 --- a/app/lib/modules/read/data/data.dart +++ b/app/lib/modules/read/data/data.dart @@ -1,8 +1,14 @@ export 'repository/read_repository_impl.dart'; export 'repository/read_theme_repository_impl.dart'; +export 'source/local/local_theme_data_source_impl.dart'; +export 'source/local/read_local_data_source_impl.dart'; +export 'source/remote/read_remote_data_source_impl.dart'; export 'source/local_theme_data_source.dart'; export 'source/read_local_data_source.dart'; export 'source/read_remote_data_source.dart'; +export 'source/mock/local_theme_data_source_mock.dart'; +export 'source/mock/read_local_data_source_mock.dart'; +export 'source/mock/read_remote_data_source_mock.dart'; export 'model/filters_response.dart'; export 'model/meta_response.dart'; export 'model/quran_page_response.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 index 2319f12f..51f132da 100644 --- a/app/lib/modules/read/data/repository/read_repository_impl.dart +++ b/app/lib/modules/read/data/repository/read_repository_impl.dart @@ -9,7 +9,7 @@ final class ReadRepositoryImpl implements ReadRepository { ); final ReadRemoteDataSource remoteDataSource; - final ReadLocalDataSource localDataSource; + final ReadLocalDataSourceImpl localDataSource; @override Future getPage(int page, String quranFmt) async { 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 index a7aa813f..44688c41 100644 --- a/app/lib/modules/read/data/repository/read_theme_repository_impl.dart +++ b/app/lib/modules/read/data/repository/read_theme_repository_impl.dart @@ -5,7 +5,7 @@ import 'package:my_quran/modules/modules.dart'; final class ReadThemeRepositoryImpl implements ReadThemeRepository { const ReadThemeRepositoryImpl(this.localThemeDataSource); - final LocalThemeDataSource localThemeDataSource; + final LocalThemeDataSourceImpl localThemeDataSource; @override ReadThemeState get getInitialThemeState { diff --git a/app/lib/modules/read/data/source/local/local_theme_data_source_impl.dart b/app/lib/modules/read/data/source/local/local_theme_data_source_impl.dart new file mode 100644 index 00000000..228b1b5c --- /dev/null +++ b/app/lib/modules/read/data/source/local/local_theme_data_source_impl.dart @@ -0,0 +1,24 @@ +import 'dart:convert'; +import 'package:meta/meta.dart'; +import 'package:mq_storage/mq_storage.dart'; +import 'package:my_quran/constants/contants.dart'; +import 'package:my_quran/modules/modules.dart'; + +@immutable +final class LocalThemeDataSourceImpl implements LocalThemeDataSource { + const LocalThemeDataSourceImpl(this.storage); + + final PreferencesStorage storage; + + @override + ReadThemeState get initialTheme { + final value = storage.readString(key: StorageKeys.readThemeKey); + return value != null ? ReadThemeState.fromJson(json.decode(value) as Map) : const ReadThemeState(); + } + + @override + Future saveThemeState(ReadThemeState themeState) async { + final value = json.encode(themeState.toJson()); + await storage.writeString(key: StorageKeys.readThemeKey, value: value); + } +} diff --git a/app/lib/modules/read/data/source/local/read_local_data_source_impl.dart b/app/lib/modules/read/data/source/local/read_local_data_source_impl.dart new file mode 100644 index 00000000..ed148b2a --- /dev/null +++ b/app/lib/modules/read/data/source/local/read_local_data_source_impl.dart @@ -0,0 +1,29 @@ +import 'dart:convert'; +import 'package:meta/meta.dart'; +import 'package:mq_storage/mq_storage.dart'; +import 'package:my_quran/modules/modules.dart'; + +@immutable +final class ReadLocalDataSourceImpl implements ReadLocalDataSource { + const ReadLocalDataSourceImpl(this.storage); + + final PreferencesStorage storage; + + @override + QuranPageResponse? getPage(int page, String quranFmt) { + final key = 'quran-$quranFmt-$page'; + final localValue = storage.readString(key: key); + + if (localValue != null) { + final data = jsonDecode(localValue); + return QuranPageResponse.fromJson(data as Map); + } + return null; + } + + @override + Future cachePage(int page, String quranFmt, QuranPageResponse 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/local_theme_data_source.dart b/app/lib/modules/read/data/source/local_theme_data_source.dart index 26019c2c..b22c5f23 100644 --- a/app/lib/modules/read/data/source/local_theme_data_source.dart +++ b/app/lib/modules/read/data/source/local_theme_data_source.dart @@ -1,22 +1,6 @@ -import 'dart:convert'; -import 'package:meta/meta.dart'; -import 'package:mq_storage/mq_storage.dart'; -import 'package:my_quran/constants/contants.dart'; import 'package:my_quran/modules/modules.dart'; -@immutable -final class LocalThemeDataSource { - const LocalThemeDataSource(this.storage); - - final PreferencesStorage storage; - - ReadThemeState get initialTheme { - final value = storage.readString(key: StorageKeys.readThemeKey); - return value != null ? ReadThemeState.fromJson(json.decode(value) as Map) : const ReadThemeState(); - } - - Future saveThemeState(ReadThemeState themeState) async { - final value = json.encode(themeState.toJson()); - await storage.writeString(key: StorageKeys.readThemeKey, value: value); - } +abstract class LocalThemeDataSource { + ReadThemeState get initialTheme; + Future saveThemeState(ReadThemeState themeState); } diff --git a/app/lib/modules/read/data/source/mock/local_theme_data_source_mock.dart b/app/lib/modules/read/data/source/mock/local_theme_data_source_mock.dart new file mode 100644 index 00000000..fedc18ec --- /dev/null +++ b/app/lib/modules/read/data/source/mock/local_theme_data_source_mock.dart @@ -0,0 +1,16 @@ +import 'package:meta/meta.dart'; + +import 'package:my_quran/modules/modules.dart'; + +@immutable +final class LocalThemeDataSourceMock implements LocalThemeDataSource { + const LocalThemeDataSourceMock(); + + @override + ReadThemeState get initialTheme { + return const ReadThemeState(); + } + + @override + Future saveThemeState(ReadThemeState themeState) => Future.value(); +} diff --git a/app/lib/modules/read/data/source/mock/read_local_data_source_mock.dart b/app/lib/modules/read/data/source/mock/read_local_data_source_mock.dart new file mode 100644 index 00000000..9526eb3e --- /dev/null +++ b/app/lib/modules/read/data/source/mock/read_local_data_source_mock.dart @@ -0,0 +1,13 @@ +import 'package:meta/meta.dart'; +import 'package:my_quran/modules/modules.dart'; + +@immutable +final class ReadLocalDataSourceMock implements ReadLocalDataSource { + const ReadLocalDataSourceMock(); + + @override + QuranPageResponse? getPage(int page, String quranFmt) => null; + + @override + Future cachePage(int page, String quranFmt, QuranPageResponse pageData) => Future.value(); +} diff --git a/app/lib/modules/read/data/source/mock/read_remote_data_source_mock.dart b/app/lib/modules/read/data/source/mock/read_remote_data_source_mock.dart new file mode 100644 index 00000000..e512e571 --- /dev/null +++ b/app/lib/modules/read/data/source/mock/read_remote_data_source_mock.dart @@ -0,0 +1,11 @@ +import 'package:my_quran/modules/modules.dart'; + +class ReadRemoteDataSourceMock implements ReadRemoteDataSource { + @override + Future fetchPage(int page, String quranFmt) async { + return const QuranPageResponse( + verses: [], + meta: MetaResponse(filters: FiltersResponse(pageNumber: '1')), + ); + } +} 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 index 19026474..8cad6b0c 100644 --- a/app/lib/modules/read/data/source/read_local_data_source.dart +++ b/app/lib/modules/read/data/source/read_local_data_source.dart @@ -1,27 +1,6 @@ -import 'dart:convert'; -import 'package:meta/meta.dart'; -import 'package:mq_storage/mq_storage.dart'; import 'package:my_quran/modules/modules.dart'; -@immutable -final class ReadLocalDataSource { - const ReadLocalDataSource(this.storage); - - final PreferencesStorage storage; - - QuranPageResponse? getPage(int page, String quranFmt) { - final key = 'quran-$quranFmt-$page'; - final localValue = storage.readString(key: key); - - if (localValue != null) { - final data = jsonDecode(localValue); - return QuranPageResponse.fromJson(data as Map); - } - return null; - } - - Future cachePage(int page, String quranFmt, QuranPageResponse pageData) async { - final key = 'quran-$quranFmt-$page'; - await storage.writeString(key: key, value: jsonEncode(pageData.toJson())); - } +abstract class ReadLocalDataSource { + QuranPageResponse? getPage(int page, String quranFmt); + Future cachePage(int page, String quranFmt, QuranPageResponse pageData); } 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 index 0b510e61..9e183e13 100644 --- a/app/lib/modules/read/data/source/read_remote_data_source.dart +++ b/app/lib/modules/read/data/source/read_remote_data_source.dart @@ -1,23 +1,5 @@ -import 'package:meta/meta.dart'; -import 'package:my_quran/config/config.dart'; -import 'package:my_quran/core/core.dart'; import 'package:my_quran/modules/modules.dart'; -@immutable -final class ReadRemoteDataSource { - const ReadRemoteDataSource(this.remoteClient); - - final MqDio remoteClient; - - Future fetchPage(int page, String quranFmt) async { - final remoteValue = await remoteClient.getType( - apiConst.verse(page, quranFmt), - fromJson: QuranPageResponse.fromJson, - ); - - return remoteValue.fold( - (l) => throw Exception('Failed to fetch remote data $l'), - (r) => r, - ); - } +abstract class ReadRemoteDataSource { + Future fetchPage(int page, String quranFmt); } diff --git a/app/lib/modules/read/data/source/remote/read_remote_data_source_impl.dart b/app/lib/modules/read/data/source/remote/read_remote_data_source_impl.dart new file mode 100644 index 00000000..548c735b --- /dev/null +++ b/app/lib/modules/read/data/source/remote/read_remote_data_source_impl.dart @@ -0,0 +1,24 @@ +import 'package:meta/meta.dart'; +import 'package:my_quran/config/config.dart'; +import 'package:my_quran/core/core.dart'; +import 'package:my_quran/modules/modules.dart'; + +@immutable +final class ReadRemoteDataSourceImpl implements ReadRemoteDataSource { + const ReadRemoteDataSourceImpl(this.remoteClient); + + final MqDio remoteClient; + + @override + Future fetchPage(int page, String quranFmt) async { + final remoteValue = await remoteClient.getType( + apiConst.verse(page, quranFmt), + fromJson: QuranPageResponse.fromJson, + ); + + return remoteValue.fold( + (l) => throw Exception('Failed to fetch remote data $l'), + (r) => r, + ); + } +} diff --git a/app/lib/modules/read/presentation/view/read_view.dart b/app/lib/modules/read/presentation/view/read_view.dart index 2e42089e..694dec7d 100644 --- a/app/lib/modules/read/presentation/view/read_view.dart +++ b/app/lib/modules/read/presentation/view/read_view.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:mq_ci_keys/mq_ci_keys.dart'; import 'package:mq_storage/mq_storage.dart'; +import 'package:my_quran/config/config.dart'; import 'package:my_quran/constants/contants.dart'; import 'package:my_quran/core/core.dart'; import 'package:my_quran/l10n/l10.dart'; @@ -30,15 +31,17 @@ class ReadView extends StatelessWidget { create: (context) => ReadCubit( GetReadPageUseCase( ReadRepositoryImpl( - ReadRemoteDataSource(context.read()), - ReadLocalDataSource(context.read()), + context.read().isMockData + ? ReadRemoteDataSourceMock() + : ReadRemoteDataSourceImpl(context.read()), + ReadLocalDataSourceImpl(context.read()), ), ), ), ), RepositoryProvider( create: (context) => ReadThemeRepositoryImpl( - LocalThemeDataSource(context.read()), + LocalThemeDataSourceImpl(context.read()), ), ), BlocProvider(