mirror of
https://github.com/Livinglist/Hacki.git
synced 2025-08-06 18:24:42 +08:00
improved performance.
This commit is contained in:
@ -10,6 +10,7 @@ import 'package:hacki/repositories/repositories.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
|
||||
part 'stories_event.dart';
|
||||
|
||||
part 'stories_state.dart';
|
||||
|
||||
class StoriesBloc extends Bloc<StoriesEvent, StoriesState> {
|
||||
@ -55,7 +56,7 @@ class StoriesBloc extends Bloc<StoriesEvent, StoriesState> {
|
||||
final hasCachedStories = await _cacheRepository.hasCachedStories;
|
||||
final isComplexTile = _preferenceCubit.state.showComplexStoryTile;
|
||||
final pageSize = _getPageSize(isComplexTile: isComplexTile);
|
||||
emit(state.copyWith(
|
||||
emit(const StoriesState.init().copyWith(
|
||||
offlineReading: hasCachedStories,
|
||||
currentPageSize: pageSize,
|
||||
));
|
||||
|
@ -18,4 +18,25 @@ abstract class Constants {
|
||||
static const String featureOpenStoryInWebView = 'open_story_in_web_view';
|
||||
static const String featureLogIn = 'log_in';
|
||||
static const String featurePinToTop = 'pin_to_top';
|
||||
|
||||
static const List<String> happyFaces = <String>[
|
||||
'(๑•̀ㅂ•́)و✧',
|
||||
'( ͡• ͜ʖ ͡•)',
|
||||
'( ͡~ ͜ʖ ͡°)',
|
||||
'٩(˘◡˘)۶',
|
||||
'(─‿‿─)',
|
||||
'(¬‿¬)',
|
||||
];
|
||||
|
||||
static const List<String> sadFaces = <String>[
|
||||
'ಥ_ಥ',
|
||||
'(╯°□°)╯︵ ┻━┻',
|
||||
r'¯\_(ツ)_/¯',
|
||||
'( ͡° ͜ʖ ͡°)',
|
||||
'(Θ︹Θ)',
|
||||
'( ˘︹˘ )',
|
||||
'(ㆆ_ㆆ)',
|
||||
'ʕ•́ᴥ•̀ʔっ',
|
||||
'(ㆆ_ㆆ)',
|
||||
];
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ class CommentsCubit<T extends Item> extends Cubit<CommentsState> {
|
||||
emit(state.copyWith(
|
||||
comments: targetParents != null ? [...targetParents] : [],
|
||||
onlyShowTargetComment: true,
|
||||
status: CommentsStatus.loaded,
|
||||
));
|
||||
return;
|
||||
}
|
||||
@ -60,23 +61,15 @@ class CommentsCubit<T extends Item> extends Cubit<CommentsState> {
|
||||
emit(state.copyWith(item: updatedStory));
|
||||
|
||||
if (state.offlineReading) {
|
||||
_cacheRepository
|
||||
_streamSubscription = _cacheRepository
|
||||
.getCachedCommentsStream(ids: updatedStory.kids)
|
||||
.listen(_onCommentFetched)
|
||||
.onDone(() {
|
||||
emit(state.copyWith(
|
||||
status: CommentsStatus.loaded,
|
||||
));
|
||||
});
|
||||
..onDone(_onDone);
|
||||
} else {
|
||||
_streamSubscription = _storiesRepository
|
||||
.fetchCommentsStream(ids: updatedStory.kids)
|
||||
.listen(_onCommentFetched);
|
||||
// ..onDone(() {
|
||||
// emit(state.copyWith(
|
||||
// status: CommentsStatus.loaded,
|
||||
// ));
|
||||
// });
|
||||
.listen(_onCommentFetched)
|
||||
..onDone(_onDone);
|
||||
}
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
@ -106,18 +99,15 @@ class CommentsCubit<T extends Item> extends Cubit<CommentsState> {
|
||||
await _storiesRepository.fetchStoryBy(story.id) ?? story;
|
||||
|
||||
if (state.offlineReading) {
|
||||
_cacheRepository
|
||||
_streamSubscription = _cacheRepository
|
||||
.getCachedCommentsStream(ids: updatedStory.kids)
|
||||
.listen(_onCommentFetched)
|
||||
.onDone(() {
|
||||
emit(state.copyWith(
|
||||
status: CommentsStatus.loaded,
|
||||
));
|
||||
});
|
||||
..onDone(_onDone);
|
||||
} else {
|
||||
_streamSubscription = _storiesRepository
|
||||
.fetchCommentsStream(ids: updatedStory.kids)
|
||||
.listen(_onCommentFetched);
|
||||
.listen(_onCommentFetched)
|
||||
..onDone(_onDone);
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
@ -141,8 +131,18 @@ class CommentsCubit<T extends Item> extends Cubit<CommentsState> {
|
||||
}
|
||||
|
||||
void loadMore() {
|
||||
emit(state.copyWith(status: CommentsStatus.loading));
|
||||
_streamSubscription?.resume();
|
||||
if (_streamSubscription != null) {
|
||||
emit(state.copyWith(status: CommentsStatus.loading));
|
||||
_streamSubscription?.resume();
|
||||
}
|
||||
}
|
||||
|
||||
void _onDone() {
|
||||
_streamSubscription?.cancel();
|
||||
_streamSubscription = null;
|
||||
emit(state.copyWith(
|
||||
status: CommentsStatus.allLoaded,
|
||||
));
|
||||
}
|
||||
|
||||
void _onCommentFetched(Comment? comment) {
|
||||
|
@ -4,6 +4,7 @@ enum CommentsStatus {
|
||||
init,
|
||||
loading,
|
||||
loaded,
|
||||
allLoaded,
|
||||
failure,
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ class PinCubit extends Cubit<PinState> {
|
||||
final StoriesRepository _storiesRepository;
|
||||
|
||||
void init() {
|
||||
emit(PinState.init());
|
||||
_storageRepository.pinnedStoriesIds.then((ids) {
|
||||
emit(state.copyWith(pinnedStoriesIds: ids));
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
export 'date_time_extension.dart';
|
||||
export 'list_extension.dart';
|
||||
export 'object_extension.dart';
|
||||
export 'state_extension.dart';
|
||||
export 'widget_extension.dart';
|
||||
|
10
lib/extensions/list_extension.dart
Normal file
10
lib/extensions/list_extension.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'dart:math';
|
||||
|
||||
extension ListExtension<T> on List<T> {
|
||||
T? pickRandomly() {
|
||||
if (isEmpty) return null;
|
||||
final random = Random(DateTime.now().millisecondsSinceEpoch);
|
||||
final luckyNumber = random.nextInt(length);
|
||||
return this[luckyNumber];
|
||||
}
|
||||
}
|
@ -21,6 +21,16 @@ Future main() async {
|
||||
|
||||
final savedThemeMode = await AdaptiveTheme.getThemeMode();
|
||||
|
||||
// BlocOverrides.runZoned(
|
||||
// () {
|
||||
// runApp(HackiApp(
|
||||
// savedThemeMode: savedThemeMode,
|
||||
// ));
|
||||
// },
|
||||
// blocObserver: CustomBlocObserver(),
|
||||
// );
|
||||
|
||||
// Uncomment code below for running without logging.
|
||||
runApp(HackiApp(
|
||||
savedThemeMode: savedThemeMode,
|
||||
));
|
||||
|
@ -1,7 +1,7 @@
|
||||
export 'auth_repository.dart';
|
||||
export 'cache_repository.dart';
|
||||
export 'post_repository.dart';
|
||||
export 'preference_repository.dart';
|
||||
export 'search_repository.dart';
|
||||
export 'sembast_repository.dart';
|
||||
export 'storage_repository.dart';
|
||||
export 'stories_repository.dart';
|
||||
|
@ -90,6 +90,7 @@ class StoriesRepository {
|
||||
);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Stream<Item> fetchItemsStream({required List<int> ids}) async* {
|
||||
|
@ -74,9 +74,11 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
context.read<StoriesBloc>().deviceScreenType =
|
||||
getDeviceType(MediaQuery.of(context).size);
|
||||
context.read<StoriesBloc>().add(StoriesInitialize());
|
||||
final deviceType = getDeviceType(MediaQuery.of(context).size);
|
||||
if (context.read<StoriesBloc>().deviceScreenType != deviceType) {
|
||||
context.read<StoriesBloc>().deviceScreenType = deviceType;
|
||||
context.read<StoriesBloc>().add(StoriesInitialize());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -129,25 +129,7 @@ class _StoryScreenState extends State<StoryScreen> {
|
||||
);
|
||||
final focusNode = FocusNode();
|
||||
final throttle = Throttle(delay: const Duration(seconds: 2));
|
||||
final sadFaces = <String>[
|
||||
'ಥ_ಥ',
|
||||
'(╯°□°)╯︵ ┻━┻',
|
||||
r'¯\_(ツ)_/¯',
|
||||
'( ͡° ͜ʖ ͡°)',
|
||||
'(Θ︹Θ)',
|
||||
'( ˘︹˘ )',
|
||||
'(ㆆ_ㆆ)',
|
||||
'ʕ•́ᴥ•̀ʔっ',
|
||||
'(ㆆ_ㆆ)',
|
||||
];
|
||||
final happyFaces = <String>[
|
||||
'(๑•̀ㅂ•́)و✧',
|
||||
'( ͡• ͜ʖ ͡•)',
|
||||
'( ͡~ ͜ʖ ͡°)',
|
||||
'٩(˘◡˘)۶',
|
||||
'(─‿‿─)',
|
||||
'(¬‿¬)',
|
||||
];
|
||||
final happyFace = Constants.happyFaces.pickRandomly()!;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -201,7 +183,8 @@ class _StoryScreenState extends State<StoryScreen> {
|
||||
context.read<EditCubit>().state.replyingTo == null
|
||||
? 'updated'
|
||||
: 'submitted';
|
||||
final msg = 'Comment $verb! ${(happyFaces..shuffle()).first}';
|
||||
final msg =
|
||||
'Comment $verb! ${Constants.happyFaces.pickRandomly()}';
|
||||
focusNode.unfocus();
|
||||
HapticFeedback.lightImpact();
|
||||
showSnackBar(content: msg);
|
||||
@ -209,8 +192,8 @@ class _StoryScreenState extends State<StoryScreen> {
|
||||
context.read<PostCubit>().reset();
|
||||
} else if (postState.status == PostStatus.failure) {
|
||||
showSnackBar(
|
||||
content:
|
||||
'Something went wrong...${(sadFaces..shuffle()).first}',
|
||||
content: 'Something went wrong...'
|
||||
'${Constants.sadFaces.pickRandomly()}',
|
||||
label: 'Okay',
|
||||
action: ScaffoldMessenger.of(context).hideCurrentSnackBar,
|
||||
);
|
||||
@ -414,7 +397,7 @@ class _StoryScreenState extends State<StoryScreen> {
|
||||
),
|
||||
],
|
||||
if (state.comments.isEmpty &&
|
||||
state.status == CommentsStatus.loaded) ...[
|
||||
state.status == CommentsStatus.allLoaded) ...[
|
||||
const SizedBox(
|
||||
height: 240,
|
||||
),
|
||||
@ -461,6 +444,13 @@ class _StoryScreenState extends State<StoryScreen> {
|
||||
onTimeMachineActivated: onTimeMachineActivated,
|
||||
),
|
||||
),
|
||||
if (state.status == CommentsStatus.allLoaded)
|
||||
SizedBox(
|
||||
height: 240,
|
||||
child: Center(
|
||||
child: Text(happyFace),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -955,8 +945,8 @@ class _StoryScreenState extends State<StoryScreen> {
|
||||
void onLoginTapped() {
|
||||
final usernameController = TextEditingController();
|
||||
final passwordController = TextEditingController();
|
||||
final sadFace = (sadFaces..shuffle()).first;
|
||||
final happyFace = (happyFaces..shuffle()).first;
|
||||
final sadFace = Constants.sadFaces.pickRandomly();
|
||||
final happyFace = Constants.happyFaces.pickRandomly();
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
|
@ -268,6 +268,10 @@ class CommentTile extends StatelessWidget {
|
||||
}
|
||||
|
||||
Color _getColor(int level) {
|
||||
while (level >= 10) {
|
||||
level = level - 10;
|
||||
}
|
||||
|
||||
const r = 255;
|
||||
var g = level * 40 < 255 ? 152 : (level * 20).clamp(0, 255);
|
||||
var b = (level * 40).clamp(0, 255);
|
||||
|
34
lib/services/custom_bloc_observer.dart
Normal file
34
lib/services/custom_bloc_observer.dart
Normal file
@ -0,0 +1,34 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:hacki/extensions/extensions.dart' show ObjectExtension;
|
||||
|
||||
class CustomBlocObserver extends BlocObserver {
|
||||
@override
|
||||
void onCreate(BlocBase bloc) {
|
||||
super.onCreate(bloc);
|
||||
bloc.log(identifier: 'Bloc Created:');
|
||||
}
|
||||
|
||||
@override
|
||||
void onEvent(Bloc bloc, Object? event) {
|
||||
super.onEvent(bloc, event);
|
||||
event?.log(identifier: 'Bloc Event:');
|
||||
}
|
||||
|
||||
@override
|
||||
void onChange(BlocBase bloc, Change change) {
|
||||
super.onChange(bloc, change);
|
||||
change.log(identifier: 'Bloc Changed:');
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
|
||||
super.onError(bloc, error, stackTrace);
|
||||
error.log(identifier: 'Bloc Error:');
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose(BlocBase bloc) {
|
||||
super.onClose(bloc);
|
||||
bloc.log(identifier: 'Bloc Closed:');
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
export 'cache_service.dart';
|
||||
export 'custom_bloc_observer.dart';
|
||||
export 'firebase_client.dart';
|
||||
|
Reference in New Issue
Block a user