167 lines
5.1 KiB
Dart
167 lines
5.1 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../core/data/services/favorite_controller.dart';
|
|
import '../../core/theme/app_colors.dart';
|
|
import '../../l10n/app_localizations.dart';
|
|
|
|
enum FollowingTab { favorites, history }
|
|
|
|
/// 编辑底栏的全选与取消动作。
|
|
class FollowingEditActions {
|
|
const FollowingEditActions({
|
|
required this.onToggleAll,
|
|
required this.onRemove,
|
|
});
|
|
|
|
final void Function(Set<String> ids) onToggleAll;
|
|
final VoidCallback onRemove;
|
|
}
|
|
|
|
const double _barHeight = 48;
|
|
const double _barHorizontal = 16;
|
|
const double _barFontSize = 13;
|
|
const double _barButtonHeight = 30;
|
|
const double _removeDialogButtonHeight = 32;
|
|
|
|
/// 只在追剧编辑中显示底栏。
|
|
class FollowingEditSlot extends StatelessWidget {
|
|
const FollowingEditSlot({
|
|
super.key,
|
|
required this.tab,
|
|
required this.editing,
|
|
required this.favorites,
|
|
required this.selected,
|
|
required this.actions,
|
|
});
|
|
|
|
final ValueListenable<FollowingTab> tab;
|
|
final ValueListenable<bool> editing;
|
|
final FavoriteController favorites;
|
|
final ValueListenable<Set<String>> selected;
|
|
final FollowingEditActions actions;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ValueListenableBuilder<FollowingTab>(
|
|
valueListenable: tab,
|
|
builder: (context, current, _) {
|
|
return ValueListenableBuilder<bool>(
|
|
valueListenable: editing,
|
|
builder: (context, isEditing, _) {
|
|
if (!isEditing || current != FollowingTab.favorites) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
return _bar();
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _bar() {
|
|
return ListenableBuilder(
|
|
listenable: favorites,
|
|
builder: (context, _) {
|
|
return ValueListenableBuilder<Set<String>>(
|
|
valueListenable: selected,
|
|
builder: (context, picked, _) {
|
|
final ids = favorites.cards.map((drama) => drama.id).toSet();
|
|
return FollowingEditBar(
|
|
allSelected: ids.isNotEmpty && ids.every(picked.contains),
|
|
canRemove: picked.isNotEmpty,
|
|
onToggleAll: () => actions.onToggleAll(ids),
|
|
onRemove: actions.onRemove,
|
|
);
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 追剧编辑底栏:全选,以及取消已选追剧。
|
|
class FollowingEditBar extends StatelessWidget {
|
|
const FollowingEditBar({
|
|
super.key,
|
|
required this.allSelected,
|
|
required this.canRemove,
|
|
required this.onToggleAll,
|
|
required this.onRemove,
|
|
});
|
|
|
|
final bool allSelected;
|
|
final bool canRemove;
|
|
final VoidCallback onToggleAll;
|
|
final VoidCallback onRemove;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
return Material(
|
|
key: const Key('following-edit-bar'),
|
|
color: AppColors.card,
|
|
child: SafeArea(
|
|
top: false,
|
|
child: SizedBox(
|
|
height: _barHeight,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: _barHorizontal),
|
|
child: Row(
|
|
children: [
|
|
TextButton(
|
|
key: const Key('following-select-all'),
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: AppColors.brandRed,
|
|
visualDensity: VisualDensity.compact,
|
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
|
minimumSize: const Size(0, _barButtonHeight),
|
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
|
textStyle: const TextStyle(
|
|
fontSize: _barFontSize,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
onPressed: onToggleAll,
|
|
child: Text(
|
|
allSelected ? l10n.deselectAll : l10n.selectAll,
|
|
style: const TextStyle(
|
|
fontSize: _barFontSize,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
const Spacer(),
|
|
TextButton(
|
|
key: const Key('following-cancel-follow'),
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: AppColors.brandRed,
|
|
visualDensity: VisualDensity.compact,
|
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
|
minimumSize: const Size(0, _removeDialogButtonHeight),
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
textStyle: const TextStyle(
|
|
fontSize: _barFontSize,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
onPressed: canRemove ? onRemove : null,
|
|
child: Text(
|
|
l10n.cancelFollowing,
|
|
style: const TextStyle(
|
|
fontSize: _barFontSize,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|