mirror of
https://github.com/Livinglist/Hacki.git
synced 2025-08-06 18:24:42 +08:00
fix status bar for android. (#200)
This commit is contained in:
@ -21,6 +21,7 @@ import 'package:hacki/screens/screens.dart';
|
|||||||
import 'package:hacki/services/custom_bloc_observer.dart';
|
import 'package:hacki/services/custom_bloc_observer.dart';
|
||||||
import 'package:hacki/services/fetcher.dart';
|
import 'package:hacki/services/fetcher.dart';
|
||||||
import 'package:hacki/styles/styles.dart';
|
import 'package:hacki/styles/styles.dart';
|
||||||
|
import 'package:hacki/utils/theme_util.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||||
import 'package:logger/logger.dart';
|
import 'package:logger/logger.dart';
|
||||||
@ -123,14 +124,6 @@ Future<void> main({bool testing = false}) async {
|
|||||||
systemNavigationBarDividerColor: Palette.transparent,
|
systemNavigationBarDividerColor: Palette.transparent,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
SystemChrome.setSystemUIOverlayStyle(
|
|
||||||
const SystemUiOverlayStyle(
|
|
||||||
statusBarBrightness: Brightness.light,
|
|
||||||
statusBarIconBrightness: Brightness.dark,
|
|
||||||
statusBarColor: Colors.transparent,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await SystemChrome.setEnabledSystemUIMode(
|
await SystemChrome.setEnabledSystemUIMode(
|
||||||
@ -147,7 +140,11 @@ Future<void> main({bool testing = false}) async {
|
|||||||
prefs.getInt(FontPreference().key) ?? Font.roboto.index,
|
prefs.getInt(FontPreference().key) ?? Font.roboto.index,
|
||||||
);
|
);
|
||||||
|
|
||||||
Bloc.observer = CustomBlocObserver();
|
// ignore: prefer_asserts_with_message
|
||||||
|
assert(() {
|
||||||
|
Bloc.observer = CustomBlocObserver();
|
||||||
|
return true;
|
||||||
|
}());
|
||||||
|
|
||||||
HydratedBloc.storage = storage;
|
HydratedBloc.storage = storage;
|
||||||
|
|
||||||
@ -276,6 +273,10 @@ class HackiApp extends StatelessWidget {
|
|||||||
AsyncSnapshot<AdaptiveThemeMode?> snapshot,
|
AsyncSnapshot<AdaptiveThemeMode?> snapshot,
|
||||||
) {
|
) {
|
||||||
final AdaptiveThemeMode? mode = snapshot.data;
|
final AdaptiveThemeMode? mode = snapshot.data;
|
||||||
|
ThemeUtil.updateAndroidStatusBarSetting(
|
||||||
|
Theme.of(context).brightness,
|
||||||
|
mode,
|
||||||
|
);
|
||||||
return BlocBuilder<PreferenceCubit, PreferenceState>(
|
return BlocBuilder<PreferenceCubit, PreferenceState>(
|
||||||
buildWhen:
|
buildWhen:
|
||||||
(PreferenceState previous, PreferenceState current) =>
|
(PreferenceState previous, PreferenceState current) =>
|
||||||
|
@ -48,131 +48,137 @@ class MainView extends StatelessWidget {
|
|||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: BlocBuilder<CommentsCubit, CommentsState>(
|
child: BlocBuilder<CommentsCubit, CommentsState>(
|
||||||
builder: (BuildContext context, CommentsState state) {
|
builder: (BuildContext context, CommentsState state) {
|
||||||
return SmartRefresher(
|
return Scrollbar(
|
||||||
scrollController: scrollController,
|
child: SmartRefresher(
|
||||||
enablePullUp: !state.onlyShowTargetComment,
|
scrollController: scrollController,
|
||||||
enablePullDown: !state.onlyShowTargetComment,
|
enablePullUp: !state.onlyShowTargetComment,
|
||||||
header: WaterDropMaterialHeader(
|
enablePullDown: !state.onlyShowTargetComment,
|
||||||
backgroundColor: Palette.orange,
|
header: WaterDropMaterialHeader(
|
||||||
offset: topPadding,
|
backgroundColor: Palette.orange,
|
||||||
),
|
offset: topPadding,
|
||||||
footer: CustomFooter(
|
),
|
||||||
loadStyle: LoadStyle.ShowWhenLoading,
|
footer: CustomFooter(
|
||||||
builder: (BuildContext context, LoadStatus? mode) {
|
loadStyle: LoadStyle.ShowWhenLoading,
|
||||||
const double height = 55;
|
builder: (BuildContext context, LoadStatus? mode) {
|
||||||
late final Widget body;
|
const double height = 55;
|
||||||
|
late final Widget body;
|
||||||
|
|
||||||
if (mode == LoadStatus.idle) {
|
if (mode == LoadStatus.idle) {
|
||||||
body = const Text('');
|
body = const Text('');
|
||||||
} else if (mode == LoadStatus.loading) {
|
} else if (mode == LoadStatus.loading) {
|
||||||
body = const Text('');
|
body = const Text('');
|
||||||
} else if (mode == LoadStatus.failed) {
|
} else if (mode == LoadStatus.failed) {
|
||||||
body = const Text(
|
body = const Text(
|
||||||
'',
|
'',
|
||||||
);
|
);
|
||||||
} else if (mode == LoadStatus.canLoading) {
|
} else if (mode == LoadStatus.canLoading) {
|
||||||
body = const Text(
|
body = const Text(
|
||||||
'',
|
'',
|
||||||
);
|
|
||||||
} else {
|
|
||||||
body = const Text('');
|
|
||||||
}
|
|
||||||
return SizedBox(
|
|
||||||
height: height,
|
|
||||||
child: Center(child: body),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
controller: refreshController,
|
|
||||||
onRefresh: () {
|
|
||||||
HapticFeedback.lightImpact();
|
|
||||||
|
|
||||||
if (context.read<StoriesBloc>().state.isOfflineReading) {
|
|
||||||
refreshController.refreshCompleted();
|
|
||||||
} else {
|
|
||||||
context.read<CommentsCubit>().refresh();
|
|
||||||
|
|
||||||
if (state.item.isPoll) {
|
|
||||||
context.read<PollCubit>().refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLoading: () {
|
|
||||||
if (state.fetchMode == FetchMode.eager) {
|
|
||||||
context.read<CommentsCubit>().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 {
|
} else {
|
||||||
return const SizedBox.shrink();
|
body = const Text('');
|
||||||
|
}
|
||||||
|
return SizedBox(
|
||||||
|
height: height,
|
||||||
|
child: Center(child: body),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
controller: refreshController,
|
||||||
|
onRefresh: () {
|
||||||
|
HapticFeedback.lightImpact();
|
||||||
|
|
||||||
|
if (context.read<StoriesBloc>().state.isOfflineReading) {
|
||||||
|
refreshController.refreshCompleted();
|
||||||
|
} else {
|
||||||
|
context.read<CommentsCubit>().refresh();
|
||||||
|
|
||||||
|
if (state.item.isPoll) {
|
||||||
|
context.read<PollCubit>().refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index = index - 1;
|
|
||||||
final Comment comment = state.comments.elementAt(index);
|
|
||||||
return FadeIn(
|
|
||||||
key: ValueKey<String>('${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<EditCubit>().state.replyingTo?.id) {
|
|
||||||
commentEditingController.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
context.read<EditCubit>().onReplyTapped(cmt);
|
|
||||||
focusNode.requestFocus();
|
|
||||||
},
|
|
||||||
onEditTapped: (Comment cmt) {
|
|
||||||
HapticFeedback.lightImpact();
|
|
||||||
if (cmt.deleted || cmt.dead) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
commentEditingController.clear();
|
|
||||||
context.read<EditCubit>().onEditTapped(cmt);
|
|
||||||
focusNode.requestFocus();
|
|
||||||
},
|
|
||||||
onMoreTapped: onMoreTapped,
|
|
||||||
onRightMoreTapped: onRightMoreTapped,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
onLoading: () {
|
||||||
|
if (state.fetchMode == FetchMode.eager) {
|
||||||
|
context.read<CommentsCubit>().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<String>('${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<EditCubit>()
|
||||||
|
.state
|
||||||
|
.replyingTo
|
||||||
|
?.id) {
|
||||||
|
commentEditingController.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.read<EditCubit>().onReplyTapped(cmt);
|
||||||
|
focusNode.requestFocus();
|
||||||
|
},
|
||||||
|
onEditTapped: (Comment cmt) {
|
||||||
|
HapticFeedback.lightImpact();
|
||||||
|
if (cmt.deleted || cmt.dead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
commentEditingController.clear();
|
||||||
|
context.read<EditCubit>().onEditTapped(cmt);
|
||||||
|
focusNode.requestFocus();
|
||||||
|
},
|
||||||
|
onMoreTapped: onMoreTapped,
|
||||||
|
onRightMoreTapped: onRightMoreTapped,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -372,22 +372,19 @@ class _SettingsState extends State<Settings> {
|
|||||||
RadioListTile<AdaptiveThemeMode>(
|
RadioListTile<AdaptiveThemeMode>(
|
||||||
value: AdaptiveThemeMode.light,
|
value: AdaptiveThemeMode.light,
|
||||||
groupValue: themeMode,
|
groupValue: themeMode,
|
||||||
onChanged: (AdaptiveThemeMode? val) =>
|
onChanged: updateThemeSetting,
|
||||||
AdaptiveTheme.of(context).setLight(),
|
|
||||||
title: const Text('Light'),
|
title: const Text('Light'),
|
||||||
),
|
),
|
||||||
RadioListTile<AdaptiveThemeMode>(
|
RadioListTile<AdaptiveThemeMode>(
|
||||||
value: AdaptiveThemeMode.dark,
|
value: AdaptiveThemeMode.dark,
|
||||||
groupValue: themeMode,
|
groupValue: themeMode,
|
||||||
onChanged: (AdaptiveThemeMode? val) =>
|
onChanged: updateThemeSetting,
|
||||||
AdaptiveTheme.of(context).setDark(),
|
|
||||||
title: const Text('Dark'),
|
title: const Text('Dark'),
|
||||||
),
|
),
|
||||||
RadioListTile<AdaptiveThemeMode>(
|
RadioListTile<AdaptiveThemeMode>(
|
||||||
value: AdaptiveThemeMode.system,
|
value: AdaptiveThemeMode.system,
|
||||||
groupValue: themeMode,
|
groupValue: themeMode,
|
||||||
onChanged: (AdaptiveThemeMode? val) =>
|
onChanged: updateThemeSetting,
|
||||||
AdaptiveTheme.of(context).setSystem(),
|
|
||||||
title: const Text('System'),
|
title: const Text('System'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -397,6 +394,24 @@ class _SettingsState extends State<Settings> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
void showClearCacheDialog() {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -183,7 +183,7 @@ class CommentTile extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: Dimens.pt8,
|
left: Dimens.pt8,
|
||||||
right: Dimens.pt8,
|
right: Dimens.pt2,
|
||||||
top: Dimens.pt6,
|
top: Dimens.pt6,
|
||||||
bottom: Dimens.pt12,
|
bottom: Dimens.pt12,
|
||||||
),
|
),
|
||||||
|
66
lib/utils/theme_util.dart
Normal file
66
lib/utils/theme_util.dart
Normal file
@ -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<void> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,4 +4,5 @@ export 'link_util.dart';
|
|||||||
export 'linkifier_util.dart';
|
export 'linkifier_util.dart';
|
||||||
export 'log_util.dart';
|
export 'log_util.dart';
|
||||||
export 'service_exception.dart';
|
export 'service_exception.dart';
|
||||||
|
export 'theme_util.dart';
|
||||||
export 'throttle.dart';
|
export 'throttle.dart';
|
||||||
|
@ -1375,4 +1375,4 @@ packages:
|
|||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.19.0 <3.0.0"
|
dart: ">=2.19.0 <3.0.0"
|
||||||
flutter: ">=3.7.10"
|
flutter: ">=3.7.9"
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
name: hacki
|
name: hacki
|
||||||
description: A Hacker News reader.
|
description: A Hacker News reader.
|
||||||
version: 1.4.2+106
|
version: 1.4.3+107
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.17.0 <3.0.0"
|
sdk: ">=2.17.0 <3.0.0"
|
||||||
flutter: "3.7.10"
|
flutter: "3.7.9"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
adaptive_theme: ^3.2.0
|
adaptive_theme: ^3.2.0
|
||||||
|
Reference in New Issue
Block a user