From 6c787009eb69d7cd3847719a97ab8e725f7a967f Mon Sep 17 00:00:00 2001 From: Livinglist Date: Fri, 19 Jul 2024 10:30:38 -0700 Subject: [PATCH] update. --- assets/remote-config-dev.json | 7 +++++++ lib/blocs/stories/stories_bloc.dart | 19 +++++++++++-------- lib/cubits/comments/comments_cubit.dart | 18 ++++++++++++------ .../notification/notification_cubit.dart | 3 ++- lib/cubits/preference/preference_cubit.dart | 3 ++- .../remote_config/remote_config_cubit.dart | 13 +++++++++++-- lib/cubits/split_view/split_view_cubit.dart | 3 ++- lib/cubits/tab/tab_cubit.dart | 7 +++++-- .../remote_config_repository.dart | 7 ++++++- lib/repositories/sembast_repository.dart | 14 +++++++++++++- lib/screens/home/home_screen.dart | 3 ++- lib/screens/profile/widgets/settings.dart | 9 +++++++++ lib/services/fetcher.dart | 8 ++++---- lib/services/web_analyzer.dart | 7 ++++--- lib/utils/log_util.dart | 8 +++++--- pubspec.yaml | 2 +- 16 files changed, 96 insertions(+), 35 deletions(-) create mode 100644 assets/remote-config-dev.json diff --git a/assets/remote-config-dev.json b/assets/remote-config-dev.json new file mode 100644 index 00000000..082d1f18 --- /dev/null +++ b/assets/remote-config-dev.json @@ -0,0 +1,7 @@ +{ + "athingComtrSelector": "#hnmain > tbody > tr > td > table > tbody > .athing.comtr", + "commentTextSelector": "td > table > tbody > tr > td.default > div.comment > div.commtext", + "commentHeadSelector": "td > table > tbody > tr > td.default > div > span > a", + "commentAgeSelector": "td > table > tbody > tr > td.default > div > span > span.age", + "commentIndentSelector": "td > table > tbody > tr > td.ind" +} diff --git a/lib/blocs/stories/stories_bloc.dart b/lib/blocs/stories/stories_bloc.dart index 7e840b0a..598efeb0 100644 --- a/lib/blocs/stories/stories_bloc.dart +++ b/lib/blocs/stories/stories_bloc.dart @@ -69,6 +69,7 @@ class StoriesBloc extends Bloc { static const int _largePageSize = 20; static const int _tabletSmallPageSize = 15; static const int _tabletLargePageSize = 25; + static const String _logPrefix = '[StoriesBloc]'; Future onInitialize( StoriesInitialize event, @@ -245,7 +246,9 @@ class StoriesBloc extends Bloc { final Story story = event.story; if (state.storiesByType[event.type]?.contains(story) ?? false) { - _logger.d('story already exists.'); + _logger.d( + '$_logPrefix story ${story.id} for ${event.type} already exists.', + ); return; } final bool hasRead = await _preferenceRepository.hasRead(story.id); @@ -349,20 +352,20 @@ class StoriesBloc extends Bloc { >[]; for (final int id in ids) { if (state.downloadStatus == StoriesDownloadStatus.canceled) { - _logger.d('aborting downloading'); + _logger.d('$_logPrefix aborting downloading'); for (final StreamSubscription stream in downloadStreams) { await stream.cancel(); } - _logger.d('deleting downloaded contents'); + _logger.d('$_logPrefix deleting downloaded contents'); await _offlineRepository.deleteAllStoryIds(); await _offlineRepository.deleteAllStories(); await _offlineRepository.deleteAllComments(); break; } - _logger.d('fetching story $id'); + _logger.d('$_logPrefix fetching story $id'); final Story? story = await _hackerNewsRepository.fetchStory(id: id); if (story == null) { @@ -382,7 +385,7 @@ class StoriesBloc extends Bloc { await _offlineRepository.cacheStory(story: story); if (story.url.isNotEmpty && includingWebPage) { - _logger.i('downloading ${story.url}'); + _logger.i('$_logPrefix downloading ${story.url}'); await _offlineRepository.cacheUrl(url: story.url); } @@ -399,19 +402,19 @@ class StoriesBloc extends Bloc { .listen( (Comment comment) { if (state.downloadStatus == StoriesDownloadStatus.canceled) { - _logger.d('aborting downloading from comments stream'); + _logger.d('$_logPrefix aborting downloading from comments stream'); downloadStream?.cancel(); return; } - _logger.d('fetched comment ${comment.id}'); + _logger.d('$_logPrefix fetched comment ${comment.id}'); unawaited( _offlineRepository.cacheComment(comment: comment), ); }, )..onDone(() { _logger.d( - '''finished downloading story ${story.id} with ${story.descendants} comments''', + '''$_logPrefix finished downloading story ${story.id} with ${story.descendants} comments''', ); add(StoryDownloaded(skipped: false)); }); diff --git a/lib/cubits/comments/comments_cubit.dart b/lib/cubits/comments/comments_cubit.dart index b8c6dfcd..6489339d 100644 --- a/lib/cubits/comments/comments_cubit.dart +++ b/lib/cubits/comments/comments_cubit.dart @@ -84,6 +84,7 @@ class CommentsCubit extends Cubit { >{}; static const int _webFetchingCmtCountLowerLimit = 5; + static const String _logPrefix = '[CommentsCubit]'; Future get _shouldFetchFromWeb async { final bool isOnWifi = await _isOnWifi; @@ -182,13 +183,14 @@ class CommentsCubit extends Cubit { case CommentsOrder.natural: final bool shouldFetchFromWeb = await _shouldFetchFromWeb; if (fetchFromWeb && shouldFetchFromWeb) { - _logger.d('fetching from web.'); + _logger + .d('$_logPrefix fetching comments of ${item.id} from web.'); commentStream = _hackerNewsWebRepository .fetchCommentsStream(state.item) .handleError((dynamic e) { _streamSubscription?.cancel(); - _logger.e(e); + _logger.e('$_logPrefix $e'); switch (e.runtimeType) { case RateLimitedException: @@ -205,7 +207,8 @@ class CommentsCubit extends Cubit { } }); } else { - _logger.d('fetching from API.'); + _logger + .d('$_logPrefix fetching comments of ${item.id} from API.'); commentStream = _hackerNewsRepository.fetchAllCommentsRecursivelyStream( ids: kids, @@ -280,11 +283,13 @@ class CommentsCubit extends Cubit { case CommentsOrder.natural: final bool shouldFetchFromWeb = await _shouldFetchFromWeb; if (fetchFromWeb && shouldFetchFromWeb) { - _logger.d('fetching from web.'); + _logger.d( + '$_logPrefix fetching comments of ${item.id} from web.', + ); commentStream = _hackerNewsWebRepository .fetchCommentsStream(state.item) .handleError((dynamic e) { - _logger.e(e); + _logger.e('$_logPrefix $e'); switch (e.runtimeType) { case RateLimitedException: @@ -301,7 +306,8 @@ class CommentsCubit extends Cubit { } }); } else { - _logger.d('fetching from API.'); + _logger + .d('$_logPrefix fetching comments of ${item.id} from API.'); commentStream = _hackerNewsRepository .fetchAllCommentsRecursivelyStream(ids: kids); } diff --git a/lib/cubits/notification/notification_cubit.dart b/lib/cubits/notification/notification_cubit.dart index 08156d36..a3e36b62 100644 --- a/lib/cubits/notification/notification_cubit.dart +++ b/lib/cubits/notification/notification_cubit.dart @@ -67,6 +67,7 @@ class NotificationCubit extends Cubit { static const Duration _refreshInterval = Duration(minutes: 5); static const int _subscriptionUpperLimit = 15; static const int _pageSize = 20; + static const String _logPrefix = '[NotificationCubit]'; Future init() async { emit(NotificationState.init()); @@ -78,7 +79,7 @@ class NotificationCubit extends Cubit { }); await _preferenceRepository.unreadCommentsIds.then((List unreadIds) { - _logger.i('NotificationCubit: ${unreadIds.length} unread items.'); + _logger.i('$_logPrefix ${unreadIds.length} unread items.'); emit(state.copyWith(unreadCommentsIds: unreadIds)); }); diff --git a/lib/cubits/preference/preference_cubit.dart b/lib/cubits/preference/preference_cubit.dart index 4bf09535..808e051e 100644 --- a/lib/cubits/preference/preference_cubit.dart +++ b/lib/cubits/preference/preference_cubit.dart @@ -23,6 +23,7 @@ class PreferenceCubit extends Cubit { final PreferenceRepository _preferenceRepository; final Logger _logger; + static const String _logPrefix = '[PreferenceCubit]'; void init() { for (final BooleanPreference p @@ -73,7 +74,7 @@ class PreferenceCubit extends Cubit { } void update(Preference preference) { - _logger.i('updating $preference to ${preference.val}'); + _logger.i('$_logPrefix updating $preference to ${preference.val}'); emit(state.copyWithPreference(preference)); diff --git a/lib/cubits/remote_config/remote_config_cubit.dart b/lib/cubits/remote_config/remote_config_cubit.dart index e794eac1..98b49657 100644 --- a/lib/cubits/remote_config/remote_config_cubit.dart +++ b/lib/cubits/remote_config/remote_config_cubit.dart @@ -3,25 +3,34 @@ import 'package:flutter/cupertino.dart'; import 'package:hacki/config/locator.dart'; import 'package:hacki/repositories/remote_config_repository.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; +import 'package:logger/logger.dart'; part 'remote_config_state.dart'; class RemoteConfigCubit extends HydratedCubit { - RemoteConfigCubit({RemoteConfigRepository? remoteConfigRepository}) - : _remoteConfigRepository = + RemoteConfigCubit({ + RemoteConfigRepository? remoteConfigRepository, + Logger? logger, + }) : _remoteConfigRepository = remoteConfigRepository ?? locator.get(), + _logger = logger ?? locator.get(), super(RemoteConfigState.init()) { init(); } final RemoteConfigRepository _remoteConfigRepository; + final Logger _logger; + static const String _logPrefix = ''; void init() { _remoteConfigRepository .fetchRemoteConfig() .then((Map data) { if (data.isNotEmpty) { + _logger.i('$_logPrefix remote config fetched: $data'); emit(state.copyWith(data: data)); + } else { + _logger.i('$_logPrefix empty remote config.'); } }); } diff --git a/lib/cubits/split_view/split_view_cubit.dart b/lib/cubits/split_view/split_view_cubit.dart index 9aafe1df..3a301960 100644 --- a/lib/cubits/split_view/split_view_cubit.dart +++ b/lib/cubits/split_view/split_view_cubit.dart @@ -17,9 +17,10 @@ class SplitViewCubit extends Cubit { final Logger _logger; final CommentCache _commentCache; + static const String _logPrefix = '[SplitViewCubit]'; void updateItemScreenArgs(ItemScreenArgs args) { - _logger.i('resetting comments in CommentCache'); + _logger.i('$_logPrefix resetting comments in CommentCache'); _commentCache.resetComments(); emit(state.copyWith(itemScreenArgs: args)); } diff --git a/lib/cubits/tab/tab_cubit.dart b/lib/cubits/tab/tab_cubit.dart index 4eb034f3..c756d237 100644 --- a/lib/cubits/tab/tab_cubit.dart +++ b/lib/cubits/tab/tab_cubit.dart @@ -19,17 +19,20 @@ class TabCubit extends Cubit { final PreferenceCubit _preferenceCubit; final Logger _logger; + static const String _logPrefix = '[TabCubit]'; void init() { final List tabs = _preferenceCubit.state.tabs; - _logger.i('updating tabs to $tabs'); + _logger.i('$_logPrefix updating tabs to $tabs'); emit(state.copyWith(tabs: tabs)); } void update(int startIndex, int endIndex) { - _logger.d('updating ${state.tabs} by moving $startIndex to $endIndex'); + _logger.d( + '$_logPrefix updating ${state.tabs} by moving $startIndex to $endIndex', + ); final StoryType tab = state.tabs.elementAt(startIndex); final List updatedTabs = List.from(state.tabs) ..insert(endIndex, tab) diff --git a/lib/repositories/remote_config_repository.dart b/lib/repositories/remote_config_repository.dart index 45399d83..6b0c9618 100644 --- a/lib/repositories/remote_config_repository.dart +++ b/lib/repositories/remote_config_repository.dart @@ -1,15 +1,20 @@ import 'dart:convert'; import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; class RemoteConfigRepository { RemoteConfigRepository({Dio? dio}) : _dio = dio ?? Dio(); final Dio _dio; + static const String _path = + 'https://raw.githubusercontent.com/Livinglist/Hacki/master/assets/'; Future> fetchRemoteConfig() async { + const String fileName = + kReleaseMode ? 'remote-config.json' : 'remote-config-dev.json'; final Response response = await _dio.get( - 'https://raw.githubusercontent.com/Livinglist/Hacki/master/assets/remote-config.json', + '$_path$fileName', ); final String data = response.data as String? ?? ''; final Map json = jsonDecode(data) as Map; diff --git a/lib/repositories/sembast_repository.dart b/lib/repositories/sembast_repository.dart index 64b7eac7..2e3dad30 100644 --- a/lib/repositories/sembast_repository.dart +++ b/lib/repositories/sembast_repository.dart @@ -1,8 +1,10 @@ import 'dart:async'; import 'dart:io'; +import 'package:hacki/config/locator.dart'; import 'package:hacki/models/models.dart'; import 'package:hacki/services/services.dart'; +import 'package:logger/logger.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sembast/sembast.dart'; @@ -17,7 +19,8 @@ class SembastRepository { SembastRepository({ Database? database, Database? cache, - }) { + Logger? logger, + }) : _logger = logger ?? locator.get() { if (database == null) { initializeDatabase(); } else { @@ -31,6 +34,9 @@ class SembastRepository { } } + final Logger _logger; + static const String _logPrefix = '[SembastRepository]'; + Database? _database; Database? _cache; List? _idsOfCommentsRepliedToMe; @@ -44,6 +50,9 @@ class SembastRepository { final Directory dir = await getApplicationCacheDirectory(); await dir.create(recursive: true); final String dbPath = join(dir.path, 'hacki.db'); + final File file = File(dbPath); + final FileStat stat = file.statSync(); + _logger.i('$_logPrefix hacki.db file size: ${stat.size / 1000000}MB'); final DatabaseFactory dbFactory = databaseFactoryIo; final Database db = await dbFactory.openDatabase(dbPath); _database = db; @@ -54,6 +63,9 @@ class SembastRepository { final Directory tempDir = await getTemporaryDirectory(); await tempDir.create(recursive: true); final String dbPath = join(tempDir.path, 'hacki_cache.db'); + final File file = File(dbPath); + final FileStat stat = file.statSync(); + _logger.i('$_logPrefix hacki_cache.db file size: ${stat.size / 1000000}MB'); final DatabaseFactory dbFactory = databaseFactoryIo; final Database db = await dbFactory.openDatabase(dbPath); _cache = db; diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart index eaf275d0..7778f015 100644 --- a/lib/screens/home/home_screen.dart +++ b/lib/screens/home/home_screen.dart @@ -43,13 +43,14 @@ class _HomeScreenState extends State late final StreamSubscription siriSuggestionStreamSubscription; static final int tabLength = StoryType.values.length + 1; + static const String logPrefix = '[HomeScreen]'; @override void didPopNext() { super.didPopNext(); if (context.read().deviceScreenType == DeviceScreenType.mobile) { - locator.get().i('resetting comments in CommentCache'); + locator.get().i('$logPrefix resetting comments in CommentCache'); Future.delayed( AppDurations.ms500, locator.get().resetComments, diff --git a/lib/screens/profile/widgets/settings.dart b/lib/screens/profile/widgets/settings.dart index e368a1a0..01d4150b 100644 --- a/lib/screens/profile/widgets/settings.dart +++ b/lib/screens/profile/widgets/settings.dart @@ -341,6 +341,15 @@ class _SettingsState extends State with ItemActionMixin { ), onTap: showClearCacheDialog, ), + if(preferenceState.isDevModeEnabled) + ListTile( + title: const Text( + 'Logs', + ), + onTap: (){ + + }, + ), ListTile( title: const Text('About'), subtitle: const Text('nothing interesting here.'), diff --git a/lib/services/fetcher.dart b/lib/services/fetcher.dart index 0c43eb49..74a71d51 100644 --- a/lib/services/fetcher.dart +++ b/lib/services/fetcher.dart @@ -38,15 +38,15 @@ abstract class Fetcher { final Logger logger = Logger(); final PreferenceRepository preferenceRepository = PreferenceRepository(logger: logger); - final AuthRepository authRepository = AuthRepository( preferenceRepository: preferenceRepository, logger: logger, ); - - final HackerNewsRepository hackerNewsRepository = HackerNewsRepository(); final SembastRepository sembastRepository = SembastRepository(); - + final HackerNewsRepository hackerNewsRepository = HackerNewsRepository( + sembastRepository: sembastRepository, + logger: logger, + ); final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); diff --git a/lib/services/web_analyzer.dart b/lib/services/web_analyzer.dart index b3c9071f..fb202d97 100644 --- a/lib/services/web_analyzer.dart +++ b/lib/services/web_analyzer.dart @@ -85,6 +85,7 @@ class WebAnalyzer { RegExp('(title|icon|description|image)', caseSensitive: false); static final RegExp _lineReg = RegExp(r'[\n\r]| |>'); static final RegExp _spaceReg = RegExp(r'\s+'); + static const String _logPrefix = '[WebAnalyzer]'; static bool isEmpty(String? str) { return !isNotEmpty(str); @@ -120,7 +121,7 @@ class WebAnalyzer { if (info != null) { locator.get().d(''' -fetched mem cached metadata using key $key for $story: +$_logPrefix fetched mem cached metadata using key $key for $story: ${info.toJson()} '''); return info; @@ -168,7 +169,7 @@ ${info.toJson()} /// [5] If there is file cache, move it to mem cache for later retrieval. if (info != null) { locator.get().d(''' -fetched file cached metadata using key $key for $story: +$_logPrefix fetched file cached metadata using key $key for $story: ${info.toJson()} '''); cacheMap[key] = info; @@ -189,7 +190,7 @@ ${info.toJson()} if (info is WebInfo) { locator .get() - .d('caching metadata using key $key for $story.'); + .d('$_logPrefix caching metadata using key $key for $story.'); unawaited( locator.get().cacheMetadata( key: key, diff --git a/lib/utils/log_util.dart b/lib/utils/log_util.dart index 40ed692a..c2a18978 100644 --- a/lib/utils/log_util.dart +++ b/lib/utils/log_util.dart @@ -8,10 +8,12 @@ import 'package:path_provider/path_provider.dart'; abstract class LogUtil { static LogPrinter get logPrinter => kReleaseMode - ? SimplePrinter(colors: false) - : PrettyPrinter( - methodCount: 0, + ? SimplePrinter( colors: false, + printTime: true, + ) + : PrettyPrinter( + printTime: true, ); static LogOutput logOutput(File outputFile) => MultiOutput( diff --git a/pubspec.yaml b/pubspec.yaml index eb757d3f..248a0fdf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: hacki description: A Hacker News reader. -version: 2.8.1+146 +version: 2.8.2+147 publish_to: none environment: