diff --git a/lib/main.dart b/lib/main.dart index f3ec627..ed3ee38 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,6 +21,7 @@ import 'package:hacki/screens/screens.dart'; import 'package:hacki/services/custom_bloc_observer.dart'; import 'package:hacki/services/fetcher.dart'; import 'package:hacki/styles/styles.dart'; +import 'package:hacki/utils/theme_util.dart'; import 'package:hive/hive.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:logger/logger.dart'; @@ -123,14 +124,6 @@ Future main({bool testing = false}) async { systemNavigationBarDividerColor: Palette.transparent, ), ); - } else { - SystemChrome.setSystemUIOverlayStyle( - const SystemUiOverlayStyle( - statusBarBrightness: Brightness.light, - statusBarIconBrightness: Brightness.dark, - statusBarColor: Colors.transparent, - ), - ); } await SystemChrome.setEnabledSystemUIMode( @@ -147,7 +140,11 @@ Future main({bool testing = false}) async { prefs.getInt(FontPreference().key) ?? Font.roboto.index, ); - Bloc.observer = CustomBlocObserver(); + // ignore: prefer_asserts_with_message + assert(() { + Bloc.observer = CustomBlocObserver(); + return true; + }()); HydratedBloc.storage = storage; @@ -276,6 +273,10 @@ class HackiApp extends StatelessWidget { AsyncSnapshot snapshot, ) { final AdaptiveThemeMode? mode = snapshot.data; + ThemeUtil.updateAndroidStatusBarSetting( + Theme.of(context).brightness, + mode, + ); return BlocBuilder( buildWhen: (PreferenceState previous, PreferenceState current) => diff --git a/lib/screens/item/widgets/main_view.dart b/lib/screens/item/widgets/main_view.dart index 4c37ada..2837026 100644 --- a/lib/screens/item/widgets/main_view.dart +++ b/lib/screens/item/widgets/main_view.dart @@ -48,131 +48,137 @@ class MainView extends StatelessWidget { Positioned.fill( child: BlocBuilder( builder: (BuildContext context, CommentsState state) { - return SmartRefresher( - scrollController: scrollController, - enablePullUp: !state.onlyShowTargetComment, - enablePullDown: !state.onlyShowTargetComment, - header: WaterDropMaterialHeader( - backgroundColor: Palette.orange, - offset: topPadding, - ), - footer: CustomFooter( - loadStyle: LoadStyle.ShowWhenLoading, - builder: (BuildContext context, LoadStatus? mode) { - const double height = 55; - late final Widget body; + return Scrollbar( + child: SmartRefresher( + scrollController: scrollController, + enablePullUp: !state.onlyShowTargetComment, + enablePullDown: !state.onlyShowTargetComment, + header: WaterDropMaterialHeader( + backgroundColor: Palette.orange, + offset: topPadding, + ), + footer: CustomFooter( + loadStyle: LoadStyle.ShowWhenLoading, + builder: (BuildContext context, LoadStatus? mode) { + const double height = 55; + late final Widget body; - if (mode == LoadStatus.idle) { - body = const Text(''); - } else if (mode == LoadStatus.loading) { - body = const Text(''); - } else if (mode == LoadStatus.failed) { - body = const Text( - '', - ); - } else if (mode == LoadStatus.canLoading) { - body = const Text( - '', - ); - } else { - body = const Text(''); - } - return SizedBox( - height: height, - child: Center(child: body), - ); - }, - ), - controller: refreshController, - onRefresh: () { - HapticFeedback.lightImpact(); - - if (context.read().state.isOfflineReading) { - refreshController.refreshCompleted(); - } else { - context.read().refresh(); - - if (state.item.isPoll) { - context.read().refresh(); - } - } - }, - onLoading: () { - if (state.fetchMode == FetchMode.eager) { - context.read().loadMore(); - } else { - refreshController.loadComplete(); - } - }, - child: ListView.builder( - primary: false, - itemCount: state.comments.length + 2, - itemBuilder: (BuildContext context, int index) { - if (index == 0) { - return _ParentItemSection( - scrollController: scrollController, - refreshController: refreshController, - commentEditingController: commentEditingController, - state: state, - authState: authState, - focusNode: focusNode, - topPadding: topPadding, - splitViewEnabled: splitViewEnabled, - onMoreTapped: onMoreTapped, - onRightMoreTapped: onRightMoreTapped, - ); - } else if (index == state.comments.length + 1) { - if ((state.status == CommentsStatus.allLoaded && - state.comments.isNotEmpty) || - state.onlyShowTargetComment) { - return SizedBox( - height: _trailingBoxHeight, - child: Center( - child: Text(Constants.happyFace), - ), + if (mode == LoadStatus.idle) { + body = const Text(''); + } else if (mode == LoadStatus.loading) { + body = const Text(''); + } else if (mode == LoadStatus.failed) { + body = const Text( + '', + ); + } else if (mode == LoadStatus.canLoading) { + body = const Text( + '', ); } else { - return const SizedBox.shrink(); + body = const Text(''); + } + return SizedBox( + height: height, + child: Center(child: body), + ); + }, + ), + controller: refreshController, + onRefresh: () { + HapticFeedback.lightImpact(); + + if (context.read().state.isOfflineReading) { + refreshController.refreshCompleted(); + } else { + context.read().refresh(); + + if (state.item.isPoll) { + context.read().refresh(); } } - - index = index - 1; - final Comment comment = state.comments.elementAt(index); - return FadeIn( - key: ValueKey('${comment.id}-FadeIn'), - child: CommentTile( - comment: comment, - level: comment.level, - opUsername: state.item.by, - fetchMode: state.fetchMode, - onReplyTapped: (Comment cmt) { - HapticFeedback.lightImpact(); - if (cmt.deleted || cmt.dead) { - return; - } - - if (cmt.id != - context.read().state.replyingTo?.id) { - commentEditingController.clear(); - } - - context.read().onReplyTapped(cmt); - focusNode.requestFocus(); - }, - onEditTapped: (Comment cmt) { - HapticFeedback.lightImpact(); - if (cmt.deleted || cmt.dead) { - return; - } - commentEditingController.clear(); - context.read().onEditTapped(cmt); - focusNode.requestFocus(); - }, - onMoreTapped: onMoreTapped, - onRightMoreTapped: onRightMoreTapped, - ), - ); }, + onLoading: () { + if (state.fetchMode == FetchMode.eager) { + context.read().loadMore(); + } else { + refreshController.loadComplete(); + } + }, + child: ListView.builder( + primary: false, + itemCount: state.comments.length + 2, + itemBuilder: (BuildContext context, int index) { + if (index == 0) { + return _ParentItemSection( + scrollController: scrollController, + refreshController: refreshController, + commentEditingController: commentEditingController, + state: state, + authState: authState, + focusNode: focusNode, + topPadding: topPadding, + splitViewEnabled: splitViewEnabled, + onMoreTapped: onMoreTapped, + onRightMoreTapped: onRightMoreTapped, + ); + } else if (index == state.comments.length + 1) { + if ((state.status == CommentsStatus.allLoaded && + state.comments.isNotEmpty) || + state.onlyShowTargetComment) { + return SizedBox( + height: _trailingBoxHeight, + child: Center( + child: Text(Constants.happyFace), + ), + ); + } else { + return const SizedBox.shrink(); + } + } + + index = index - 1; + final Comment comment = state.comments.elementAt(index); + return FadeIn( + key: ValueKey('${comment.id}-FadeIn'), + child: CommentTile( + comment: comment, + level: comment.level, + opUsername: state.item.by, + fetchMode: state.fetchMode, + onReplyTapped: (Comment cmt) { + HapticFeedback.lightImpact(); + if (cmt.deleted || cmt.dead) { + return; + } + + if (cmt.id != + context + .read() + .state + .replyingTo + ?.id) { + commentEditingController.clear(); + } + + context.read().onReplyTapped(cmt); + focusNode.requestFocus(); + }, + onEditTapped: (Comment cmt) { + HapticFeedback.lightImpact(); + if (cmt.deleted || cmt.dead) { + return; + } + commentEditingController.clear(); + context.read().onEditTapped(cmt); + focusNode.requestFocus(); + }, + onMoreTapped: onMoreTapped, + onRightMoreTapped: onRightMoreTapped, + ), + ); + }, + ), ), ); }, diff --git a/lib/screens/profile/widgets/settings.dart b/lib/screens/profile/widgets/settings.dart index 7f9da13..6049086 100644 --- a/lib/screens/profile/widgets/settings.dart +++ b/lib/screens/profile/widgets/settings.dart @@ -372,22 +372,19 @@ class _SettingsState extends State { RadioListTile( value: AdaptiveThemeMode.light, groupValue: themeMode, - onChanged: (AdaptiveThemeMode? val) => - AdaptiveTheme.of(context).setLight(), + onChanged: updateThemeSetting, title: const Text('Light'), ), RadioListTile( value: AdaptiveThemeMode.dark, groupValue: themeMode, - onChanged: (AdaptiveThemeMode? val) => - AdaptiveTheme.of(context).setDark(), + onChanged: updateThemeSetting, title: const Text('Dark'), ), RadioListTile( value: AdaptiveThemeMode.system, groupValue: themeMode, - onChanged: (AdaptiveThemeMode? val) => - AdaptiveTheme.of(context).setSystem(), + onChanged: updateThemeSetting, title: const Text('System'), ), ], @@ -397,6 +394,24 @@ class _SettingsState extends State { ); } + void updateThemeSetting(AdaptiveThemeMode? val) { + switch (val) { + case AdaptiveThemeMode.light: + AdaptiveTheme.of(context).setLight(); + break; + case AdaptiveThemeMode.dark: + AdaptiveTheme.of(context).setDark(); + break; + case AdaptiveThemeMode.system: + case null: + AdaptiveTheme.of(context).setSystem(); + break; + } + + final Brightness brightness = Theme.of(context).brightness; + ThemeUtil.updateAndroidStatusBarSetting(brightness, val); + } + void showClearCacheDialog() { showDialog( context: context, diff --git a/lib/screens/widgets/comment_tile.dart b/lib/screens/widgets/comment_tile.dart index cb8df22..f16228d 100644 --- a/lib/screens/widgets/comment_tile.dart +++ b/lib/screens/widgets/comment_tile.dart @@ -183,7 +183,7 @@ class CommentTile extends StatelessWidget { Padding( padding: const EdgeInsets.only( left: Dimens.pt8, - right: Dimens.pt8, + right: Dimens.pt2, top: Dimens.pt6, bottom: Dimens.pt12, ), diff --git a/lib/utils/theme_util.dart b/lib/utils/theme_util.dart new file mode 100644 index 0000000..921e109 --- /dev/null +++ b/lib/utils/theme_util.dart @@ -0,0 +1,66 @@ +import 'dart:io'; + +import 'package:adaptive_theme/adaptive_theme.dart'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/services.dart'; +import 'package:hacki/styles/styles.dart'; + +abstract class ThemeUtil { + /// Temp fix for the issue: + /// https://github.com/flutter/flutter/issues/119465 + static Future updateAndroidStatusBarSetting( + Brightness brightness, + AdaptiveThemeMode? mode, + ) async { + if (Platform.isAndroid == false) return; + + final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + final AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo; + final int sdk = androidInfo.version.sdkInt; + + if (sdk > 28) return; + switch (mode) { + case AdaptiveThemeMode.light: + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarBrightness: Brightness.dark, + statusBarIconBrightness: Brightness.dark, + statusBarColor: Palette.transparent, + ), + ); + break; + case AdaptiveThemeMode.dark: + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarColor: Palette.transparent, + ), + ); + break; + case AdaptiveThemeMode.system: + case null: + switch (brightness) { + case Brightness.light: + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarBrightness: Brightness.dark, + statusBarIconBrightness: Brightness.dark, + statusBarColor: Palette.transparent, + ), + ); + break; + case Brightness.dark: + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarColor: Palette.transparent, + ), + ); + break; + } + break; + } + } +} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index bd26c6f..a3132c1 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -4,4 +4,5 @@ export 'link_util.dart'; export 'linkifier_util.dart'; export 'log_util.dart'; export 'service_exception.dart'; +export 'theme_util.dart'; export 'throttle.dart'; diff --git a/pubspec.lock b/pubspec.lock index 1f94e9a..e655455 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1375,4 +1375,4 @@ packages: version: "3.1.1" sdks: dart: ">=2.19.0 <3.0.0" - flutter: ">=3.7.10" + flutter: ">=3.7.9" diff --git a/pubspec.yaml b/pubspec.yaml index 6a792d7..0ea03e6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,11 @@ name: hacki description: A Hacker News reader. -version: 1.4.2+106 +version: 1.4.3+107 publish_to: none environment: sdk: ">=2.17.0 <3.0.0" - flutter: "3.7.10" + flutter: "3.7.9" dependencies: adaptive_theme: ^3.2.0