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()) {
on<LoadStories>(
onLoadStories,
transformer: sequential(),
transformer: concurrent(),
);
on<StoriesInitialize>(onInitialize);
on<StoriesRefresh>(onRefresh);

View File

@ -169,20 +169,26 @@ class FavCubit extends Cubit<FavState> {
emit(FavState.init());
}
Future<void> merge() async {
Future<void> merge({required AppExceptionHandler onError}) async {
if (_authBloc.state.isLoggedIn) {
emit(state.copyWith(mergeStatus: Status.inProgress));
try {
final Iterable<int> ids = await _hackerNewsWebRepository.fetchFavorites(
of: _authBloc.state.username,
);
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(
username: username,
ids: mergedIds,
);
emit(state.copyWith(mergeStatus: Status.success));
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(
content: Constants.errorMessage,
void showErrorSnackBar([String? message]) {
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 {
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 'discoverable_feature.dart';
export 'export_destination.dart';

View File

@ -1,6 +1,7 @@
import 'package:collection/collection.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/parser.dart';
import 'package:html_unescape/html_unescape.dart';
@ -25,6 +26,14 @@ class HackerNewsWebRepository {
'''$_favoritesBaseUrl$username${isComment ? '&comments=t' : ''}&p=$page''',
);
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 List<Element> elements = document.querySelectorAll(_aThingSelector);
final Iterable<int> parsedIds = elements
@ -45,6 +54,7 @@ class HackerNewsWebRepository {
page++;
}
page = 1;
while (true) {
ids = await fetchIds(page, isComment: true);
if (ids.isEmpty) {

View File

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

View File

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