Refactor user list state management
This commit is contained in:
parent
2562375778
commit
c338b304dd
3 changed files with 165 additions and 107 deletions
|
|
@ -16,8 +16,23 @@ abstract class _ChatDetailsStoreBase with Store {
|
|||
@readonly
|
||||
ChatUsers? _chatUsers;
|
||||
|
||||
@observable
|
||||
var showJumpButton = false;
|
||||
|
||||
@observable
|
||||
var filterText = '';
|
||||
|
||||
@computed
|
||||
Iterable<List<String>> get filteredUsers => [
|
||||
_chatUsers!.chatters.broadcaster,
|
||||
_chatUsers!.chatters.staff,
|
||||
_chatUsers!.chatters.admins,
|
||||
_chatUsers!.chatters.globalMods,
|
||||
_chatUsers!.chatters.moderators,
|
||||
_chatUsers!.chatters.vips,
|
||||
_chatUsers!.chatters.viewers,
|
||||
].map((e) => e.where((user) => user.contains(filterText)).toList());
|
||||
|
||||
@action
|
||||
Future<void> updateChatters(String userLogin) async {
|
||||
_chatUsers = await Twitch.getChatters(userLogin: userLogin);
|
||||
}
|
||||
Future<void> updateChatters(String userLogin) async => _chatUsers = await Twitch.getChatters(userLogin: userLogin);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ part of 'chat_details_store.dart';
|
|||
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
|
||||
|
||||
mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store {
|
||||
Computed<Iterable<List<String>>>? _$filteredUsersComputed;
|
||||
|
||||
@override
|
||||
Iterable<List<String>> get filteredUsers => (_$filteredUsersComputed ??=
|
||||
Computed<Iterable<List<String>>>(() => super.filteredUsers,
|
||||
name: '_ChatDetailsStoreBase.filteredUsers'))
|
||||
.value;
|
||||
|
||||
final _$roomStateAtom = Atom(name: '_ChatDetailsStoreBase.roomState');
|
||||
|
||||
@override
|
||||
|
|
@ -41,6 +49,37 @@ mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
final _$showJumpButtonAtom =
|
||||
Atom(name: '_ChatDetailsStoreBase.showJumpButton');
|
||||
|
||||
@override
|
||||
bool get showJumpButton {
|
||||
_$showJumpButtonAtom.reportRead();
|
||||
return super.showJumpButton;
|
||||
}
|
||||
|
||||
@override
|
||||
set showJumpButton(bool value) {
|
||||
_$showJumpButtonAtom.reportWrite(value, super.showJumpButton, () {
|
||||
super.showJumpButton = value;
|
||||
});
|
||||
}
|
||||
|
||||
final _$filterTextAtom = Atom(name: '_ChatDetailsStoreBase.filterText');
|
||||
|
||||
@override
|
||||
String get filterText {
|
||||
_$filterTextAtom.reportRead();
|
||||
return super.filterText;
|
||||
}
|
||||
|
||||
@override
|
||||
set filterText(String value) {
|
||||
_$filterTextAtom.reportWrite(value, super.filterText, () {
|
||||
super.filterText = value;
|
||||
});
|
||||
}
|
||||
|
||||
final _$updateChattersAsyncAction =
|
||||
AsyncAction('_ChatDetailsStoreBase.updateChatters');
|
||||
|
||||
|
|
@ -53,7 +92,10 @@ mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store {
|
|||
@override
|
||||
String toString() {
|
||||
return '''
|
||||
roomState: ${roomState}
|
||||
roomState: ${roomState},
|
||||
showJumpButton: ${showJumpButton},
|
||||
filterText: ${filterText},
|
||||
filteredUsers: ${filteredUsers}
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:frosty/screens/channel/chat/details/chat_details_store.dart';
|
||||
import 'package:frosty/widgets/scroll_to_top_button.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
|
@ -22,132 +23,132 @@ class _ChattersListState extends State<ChattersList> {
|
|||
final _scrollController = ScrollController();
|
||||
final _textController = TextEditingController();
|
||||
|
||||
var _showJumpButton = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController.addListener(() {
|
||||
if (_scrollController.position.pixels > 0.0 && _showJumpButton == false) setState(() => _showJumpButton = true);
|
||||
if (_scrollController.position.pixels <= 0.0 && _showJumpButton == true) setState(() => _showJumpButton = false);
|
||||
if (_scrollController.position.atEdge || _scrollController.position.outOfRange) {
|
||||
widget.chatDetails.showJumpButton = false;
|
||||
} else {
|
||||
widget.chatDetails.showJumpButton = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final chatters = widget.chatDetails.chatUsers?.chatters;
|
||||
if (chatters != null) {
|
||||
const textStyle = TextStyle(fontWeight: FontWeight.bold);
|
||||
const textStyle = TextStyle(fontWeight: FontWeight.bold);
|
||||
|
||||
const headers = [
|
||||
'Broadcaster',
|
||||
'Staff',
|
||||
'Admins',
|
||||
'Global Moderators',
|
||||
'Moderators',
|
||||
'VIPs',
|
||||
'Viewers',
|
||||
];
|
||||
const headers = [
|
||||
'Broadcaster',
|
||||
'Staff',
|
||||
'Admins',
|
||||
'Global Moderators',
|
||||
'Moderators',
|
||||
'VIPs',
|
||||
'Viewers',
|
||||
];
|
||||
|
||||
final userTypes = [
|
||||
chatters.broadcaster,
|
||||
chatters.staff,
|
||||
chatters.admins,
|
||||
chatters.globalMods,
|
||||
chatters.moderators,
|
||||
chatters.vips,
|
||||
chatters.viewers,
|
||||
].map((e) => e.where((user) => user.contains(_textController.text)).toList());
|
||||
final chatDetailStore = widget.chatDetails;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: TextField(
|
||||
controller: _textController,
|
||||
autocorrect: false,
|
||||
onChanged: (value) => setState(() {}),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: 'Filter',
|
||||
contentPadding: const EdgeInsets.all(10.0),
|
||||
suffixIcon: IconButton(
|
||||
tooltip: 'Clear Filter',
|
||||
onPressed: () => setState(() {
|
||||
_textController.clear();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
}),
|
||||
icon: const Icon(Icons.clear),
|
||||
),
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||
),
|
||||
return GestureDetector(
|
||||
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: TextField(
|
||||
controller: _textController,
|
||||
autocorrect: false,
|
||||
onChanged: (text) => chatDetailStore.filterText = text,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: 'Filter',
|
||||
contentPadding: const EdgeInsets.all(10.0),
|
||||
suffixIcon: IconButton(
|
||||
tooltip: 'Clear Filter',
|
||||
onPressed: () {
|
||||
chatDetailStore.filterText = '';
|
||||
_textController.clear();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
},
|
||||
icon: const Icon(Icons.clear),
|
||||
),
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await widget.chatDetails.updateChatters(widget.userLogin);
|
||||
setState(() {});
|
||||
},
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
children: [
|
||||
CustomScrollView(
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Chatters', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
|
||||
const SizedBox(height: 5.0),
|
||||
Text('${NumberFormat().format(widget.chatDetails.chatUsers?.chatterCount)} in chat'),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () => chatDetailStore.updateChatters(widget.userLogin),
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
children: [
|
||||
Observer(
|
||||
builder: (context) {
|
||||
if (chatDetailStore.chatUsers == null) {
|
||||
return const Center(child: Text('Failed to get chatters :('));
|
||||
}
|
||||
|
||||
return CustomScrollView(
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Chatters', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
|
||||
const SizedBox(height: 5.0),
|
||||
Text('${NumberFormat().format(chatDetailStore.chatUsers?.chatterCount)} in chat'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
...userTypes.expandIndexed(
|
||||
(index, type) => [
|
||||
if (type.isNotEmpty) ...[
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 20.0),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Text(
|
||||
headers[index],
|
||||
style: textStyle,
|
||||
...chatDetailStore.filteredUsers.expandIndexed(
|
||||
(index, type) => [
|
||||
if (type.isNotEmpty) ...[
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 20.0),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Text(
|
||||
headers[index],
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => Text(type[index]),
|
||||
childCount: type.length,
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => Text(type[index]),
|
||||
childCount: type.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
if (_showJumpButton) ScrollToTopButton(scrollController: _scrollController)
|
||||
],
|
||||
),
|
||||
]
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
Observer(builder: (context) {
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: chatDetailStore.showJumpButton ? ScrollToTopButton(scrollController: _scrollController) : const SizedBox(),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return const Center(child: Text('Failed to get chatters :('));
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue