fix flickering image. (#343)

This commit is contained in:
Jojo Feng
2023-12-07 23:24:43 -08:00
committed by GitHub
parent 835ed7e841
commit cb90751330
8 changed files with 71 additions and 21 deletions

View File

@ -35,7 +35,7 @@ class StoriesBloc extends Bloc<StoriesEvent, StoriesState> {
super(const StoriesState.init()) { super(const StoriesState.init()) {
on<LoadStories>( on<LoadStories>(
onLoadStories, onLoadStories,
transformer: sequential(), transformer: concurrent(),
); );
on<StoriesInitialize>(onInitialize); on<StoriesInitialize>(onInitialize);
on<StoriesRefresh>(onRefresh); on<StoriesRefresh>(onRefresh);

View File

@ -169,20 +169,26 @@ class FavCubit extends Cubit<FavState> {
emit(FavState.init()); emit(FavState.init());
} }
Future<void> merge() async { Future<void> merge({required AppExceptionHandler onError}) async {
if (_authBloc.state.isLoggedIn) { if (_authBloc.state.isLoggedIn) {
emit(state.copyWith(mergeStatus: Status.inProgress)); emit(state.copyWith(mergeStatus: Status.inProgress));
try {
final Iterable<int> ids = await _hackerNewsWebRepository.fetchFavorites( final Iterable<int> ids = await _hackerNewsWebRepository.fetchFavorites(
of: _authBloc.state.username, of: _authBloc.state.username,
); );
final List<int> combinedIds = <int>[...ids, ...state.favIds]; final List<int> combinedIds = <int>[...ids, ...state.favIds];
final LinkedHashSet<int> mergedIds = LinkedHashSet<int>.from(combinedIds); final LinkedHashSet<int> mergedIds =
LinkedHashSet<int>.from(combinedIds);
await _preferenceRepository.overwriteFav( await _preferenceRepository.overwriteFav(
username: username, username: username,
ids: mergedIds, ids: mergedIds,
); );
emit(state.copyWith(mergeStatus: Status.success)); emit(state.copyWith(mergeStatus: Status.success));
refresh(); refresh();
} on RateLimitedException catch (e) {
onError(e);
emit(state.copyWith(mergeStatus: Status.failure));
}
} }
} }

View File

@ -38,9 +38,19 @@ extension ContextExtension on BuildContext {
); );
} }
void showErrorSnackBar() => showSnackBar( void showErrorSnackBar([String? message]) {
content: Constants.errorMessage, ScaffoldMessenger.of(this).showSnackBar(
SnackBar(
backgroundColor: Theme.of(this).colorScheme.errorContainer,
content: Text(
message ?? Constants.errorMessage,
style: TextStyle(
color: Theme.of(this).colorScheme.onErrorContainer,
),
),
),
); );
}
Rect? get rect { Rect? get rect {
final RenderBox? box = findRenderObject() as RenderBox?; final RenderBox? box = findRenderObject() as RenderBox?;

View File

@ -0,0 +1,15 @@
typedef AppExceptionHandler = void Function(AppException);
class AppException implements Exception {
AppException({
required this.message,
this.stackTrace,
});
final String message;
final StackTrace? stackTrace;
}
class RateLimitedException extends AppException {
RateLimitedException() : super(message: 'Rate limited...');
}

View File

@ -1,3 +1,4 @@
export 'app_exception.dart';
export 'comments_order.dart'; export 'comments_order.dart';
export 'discoverable_feature.dart'; export 'discoverable_feature.dart';
export 'export_destination.dart'; export 'export_destination.dart';

View File

@ -1,6 +1,7 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:hacki/models/item/comment.dart'; import 'package:hacki/config/constants.dart';
import 'package:hacki/models/models.dart';
import 'package:html/dom.dart' hide Comment; import 'package:html/dom.dart' hide Comment;
import 'package:html/parser.dart'; import 'package:html/parser.dart';
import 'package:html_unescape/html_unescape.dart'; import 'package:html_unescape/html_unescape.dart';
@ -25,6 +26,14 @@ class HackerNewsWebRepository {
'''$_favoritesBaseUrl$username${isComment ? '&comments=t' : ''}&p=$page''', '''$_favoritesBaseUrl$username${isComment ? '&comments=t' : ''}&p=$page''',
); );
final Response response = await get(url); final Response response = await get(url);
if (response.body.contains('Sorry')) {
throw RateLimitedException();
}
/// Due to rate limiting, we have a short break here.
await Future<void>.delayed(AppDurations.oneSecond);
final Document document = parse(response.body); final Document document = parse(response.body);
final List<Element> elements = document.querySelectorAll(_aThingSelector); final List<Element> elements = document.querySelectorAll(_aThingSelector);
final Iterable<int> parsedIds = elements final Iterable<int> parsedIds = elements
@ -45,6 +54,7 @@ class HackerNewsWebRepository {
page++; page++;
} }
page = 1;
while (true) { while (true) {
ids = await fetchIds(page, isComment: true); ids = await fetchIds(page, isComment: true);
if (ids.isEmpty) { if (ids.isEmpty) {

View File

@ -150,7 +150,11 @@ class _ProfileScreenState extends State<ProfileScreen>
) => ) =>
TextButton( TextButton(
onPressed: () { onPressed: () {
context.read<FavCubit>().merge(); context.read<FavCubit>().merge(
onError: (AppException e) {
context.showErrorSnackBar(e.message);
},
);
}, },
child: status == Status.inProgress child: status == Status.inProgress
? const SizedBox( ? const SizedBox(

View File

@ -119,10 +119,14 @@ class LinkView extends StatelessWidget {
: CachedNetworkImage( : CachedNetworkImage(
imageUrl: imageUri!, imageUrl: imageUri!,
fit: isIcon ? BoxFit.scaleDown : BoxFit.fitWidth, fit: isIcon ? BoxFit.scaleDown : BoxFit.fitWidth,
memCacheHeight: layoutHeight.toInt() * 4,
cacheKey: imageUri, cacheKey: imageUri,
errorWidget: (_, __, ___) => const Center( errorWidget: (_, __, ___) => Center(
child: Text(r'¯\_(ツ)_/¯'), child: Text(
r'¯\_(ツ)_/¯',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
), ),
), ),
), ),