mnemo_cards/lib/widgets/card_pack/cards_view_controller.dart

127 lines
3.2 KiB
Dart
Raw Normal View History

2024-05-28 21:25:51 +00:00
import 'dart:async';
import 'dart:math';
import 'package:flutter/widgets.dart';
import 'package:mnemo_cards/features/packs/images_holder.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
import 'package:rxdart/rxdart.dart';
import '../../di/locator.dart';
class CardsViewController extends ChangeNotifier {
bool _expanded = false;
bool _favorite = false;
double imageWidth = 0.0;
List<GameCardDto> cards = [];
final CardPackDto cardPack;
final ScrollController _cardsScrollController =
ScrollController(keepScrollOffset: true);
ScrollController get cardsScrollController => _cardsScrollController;
StreamController<CardsViewState> _streamController =
StreamController.broadcast();
Stream<CardsViewState> get asStream =>
_streamController.stream.startWith(state).distinct();
Stream<bool> get expandedStream => asStream.map((s) => s.expanded).distinct();
Stream<bool> get favoriteStream => asStream.map((s) => s.favorite).distinct();
Stream<List<GameCardDto>> get cardsStream =>
asStream.map((s) => s.packCards).distinct((p, n) =>
(p.length == n.length) &&
p.indexed.every((p) => n[p.$1].id == p.$2.id));
CardsViewState get state => CardsViewState(
expanded: _expanded,
favorite: _favorite,
packCards: cards,
);
List<GameCardDto> _filterPackCards() => cardPack.cards
.where(
(card) =>
!_favorite ||
locator.favoriteCardsController.isFavoriteCard(card.id),
)
.toList();
void setExpanded(bool expanded) {
if (cards.isNotEmpty) {
_expanded = expanded;
notifyListeners();
}
}
void setFavorite(bool favorite) {
_favorite = favorite;
_updateCards();
notifyListeners();
}
void _addToStream() {
_streamController.add(state);
}
double get offset => _cardsScrollController.offset;
int get offsetCards => (_cardsScrollController.offset / imageWidth).floor();
void toggleExpanded() => setExpanded(!_expanded);
CardsViewController(this.cardPack) {
addListener(_addToStream);
_updateCards();
}
void _updateCards() {
cards = _filterPackCards();
notifyListeners();
}
Future<void> animateTo(int index) {
final millis =
((_cardsScrollController.offset / imageWidth - index).abs() * 30.0)
.ceil();
return _cardsScrollController.animateTo(
imageWidth * index,
duration: Duration(milliseconds: max(millis, 100)),
curve: Curves.easeInOut,
);
}
void jumpTo(int index) {
return _cardsScrollController.jumpTo(
imageWidth * index,
);
}
}
class CardsViewState {
final bool expanded;
final bool favorite;
final List<GameCardDto> packCards;
CardsViewState({
required this.expanded,
required this.favorite,
required this.packCards,
});
@override
int get hashCode => expanded.hashCode ^ expanded.hashCode ^ packCards.length;
@override
bool operator ==(Object other) {
return (other is CardsViewState) &&
expanded == other.expanded &&
favorite == other.favorite &&
(packCards.length == other.packCards.length) &&
packCards.indexed.every((p) => other.packCards[p.$1].id == p.$2.id);
}
}