♻️ Refactored explore screen
This commit is contained in:
parent
92f7e92018
commit
060a97f5ec
@ -1,4 +1,3 @@
|
|||||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
||||||
@ -12,13 +11,15 @@ import 'package:surface/providers/sn_network.dart';
|
|||||||
import 'package:surface/providers/sn_realm.dart';
|
import 'package:surface/providers/sn_realm.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/types/realm.dart';
|
import 'package:surface/types/realm.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
|
||||||
import 'package:surface/widgets/app_bar_leading.dart';
|
import 'package:surface/widgets/app_bar_leading.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
import 'package:surface/widgets/post/post_item.dart';
|
import 'package:surface/widgets/post/post_item.dart';
|
||||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||||
|
|
||||||
|
const kPostChannels = ['Global', 'Friends', 'Following'];
|
||||||
|
const kPostChannelIcons = [Symbols.globe, Symbols.group, Symbols.subscriptions];
|
||||||
|
|
||||||
const Map<String, IconData> kCategoryIcons = {
|
const Map<String, IconData> kCategoryIcons = {
|
||||||
'technology': Symbols.tools_wrench,
|
'technology': Symbols.tools_wrench,
|
||||||
'gaming': Symbols.gamepad,
|
'gaming': Symbols.gamepad,
|
||||||
@ -39,17 +40,14 @@ class ExploreScreen extends StatefulWidget {
|
|||||||
State<ExploreScreen> createState() => _ExploreScreenState();
|
State<ExploreScreen> createState() => _ExploreScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// You know what? I'm not going to make this a global variable.
|
|
||||||
// Cuz the global key make the selected category not update to child widget when the category is changed.
|
|
||||||
SnPostCategory? _selectedCategory;
|
|
||||||
|
|
||||||
class _ExploreScreenState extends State<ExploreScreen>
|
class _ExploreScreenState extends State<ExploreScreen>
|
||||||
with SingleTickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
late final TabController _tabController =
|
late TabController _tabController = TabController(length: 3, vsync: this);
|
||||||
TabController(length: 4, vsync: this);
|
|
||||||
|
|
||||||
final _fabKey = GlobalKey<ExpandableFabState>();
|
final _fabKey = GlobalKey<ExpandableFabState>();
|
||||||
final _listKeys = List.generate(4, (_) => GlobalKey<_PostListWidgetState>());
|
final _listKeys = GlobalKey<_PostListWidgetState>();
|
||||||
|
|
||||||
|
bool _showCategories = false;
|
||||||
|
|
||||||
final List<SnPostCategory> _categories = List.empty(growable: true);
|
final List<SnPostCategory> _categories = List.empty(growable: true);
|
||||||
|
|
||||||
@ -69,14 +67,65 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearFilter() {
|
final List<SnRealm> _realms = List.empty(growable: true);
|
||||||
_selectedCategory = null;
|
|
||||||
|
Future<void> _fetchRealms() async {
|
||||||
|
try {
|
||||||
|
final rels = context.read<SnRealmProvider>();
|
||||||
|
final out = await rels.listAvailableRealms();
|
||||||
|
setState(() {
|
||||||
|
_realms.addAll(out);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleShowCategories() {
|
||||||
|
_showCategories = !_showCategories;
|
||||||
|
if (_showCategories) {
|
||||||
|
_tabController = TabController(length: _categories.length, vsync: this);
|
||||||
|
} else {
|
||||||
|
_tabController = TabController(length: 4, vsync: this);
|
||||||
|
}
|
||||||
|
_tabListen();
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _tabListen() {
|
||||||
|
_tabController.addListener(() {
|
||||||
|
if (_tabController.indexIsChanging) {
|
||||||
|
if (_showCategories) {
|
||||||
|
_listKeys.currentState
|
||||||
|
?.setCategory(_categories[_tabController.index]);
|
||||||
|
_listKeys.currentState?.refreshPosts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (_tabController.index) {
|
||||||
|
case 0:
|
||||||
|
case 3:
|
||||||
|
_listKeys.currentState?.setChannel(null);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
_listKeys.currentState?.setChannel('friends');
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
_listKeys.currentState?.setChannel('following');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_listKeys.currentState?.refreshPosts();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_fetchCategories();
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_tabListen();
|
||||||
|
_fetchCategories();
|
||||||
|
_fetchRealms();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -86,7 +135,7 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> refreshPosts() async {
|
Future<void> refreshPosts() async {
|
||||||
await _listKeys[_tabController.index].currentState?.refreshPosts();
|
await _listKeys.currentState?.refreshPosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -155,19 +204,18 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.category),
|
icon: const Icon(Symbols.category),
|
||||||
|
style: _showCategories
|
||||||
|
? ButtonStyle(
|
||||||
|
foregroundColor: WidgetStateProperty.all(
|
||||||
|
Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
backgroundColor: MaterialStateProperty.all(
|
||||||
|
Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showModalBottomSheet(
|
_toggleShowCategories();
|
||||||
context: context,
|
|
||||||
builder: (context) => _PostCategoryPickerPopup(
|
|
||||||
categories: _categories,
|
|
||||||
selected: _selectedCategory,
|
|
||||||
),
|
|
||||||
).then((value) {
|
|
||||||
if (value != null && context.mounted) {
|
|
||||||
_selectedCategory = value == false ? null : value;
|
|
||||||
refreshPosts();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -179,122 +227,74 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
const Gap(8),
|
const Gap(8),
|
||||||
],
|
],
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
|
isScrollable: _showCategories,
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
tabs: [
|
tabs: _showCategories
|
||||||
Tab(
|
? [
|
||||||
child: Row(
|
for (final category in _categories)
|
||||||
mainAxisSize: MainAxisSize.min,
|
Tab(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
child: Row(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
Icon(Symbols.globe,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
size: 20,
|
children: [
|
||||||
color: Theme.of(context)
|
Icon(
|
||||||
.appBarTheme
|
kCategoryIcons[category.alias] ??
|
||||||
.foregroundColor),
|
Symbols.question_mark,
|
||||||
const Gap(8),
|
color: Theme.of(context)
|
||||||
Flexible(
|
.appBarTheme
|
||||||
child: Text(
|
.foregroundColor!),
|
||||||
'postChannelGlobal',
|
const Gap(8),
|
||||||
maxLines: 1,
|
Flexible(
|
||||||
).tr().textColor(
|
child: Text(
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
'postCategory${category.alias.capitalize()}'
|
||||||
),
|
.trExists()
|
||||||
|
? 'postCategory${category.alias.capitalize()}'
|
||||||
|
.tr()
|
||||||
|
: category.name,
|
||||||
|
maxLines: 1,
|
||||||
|
).textColor(Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
for (final channel in kPostChannels)
|
||||||
|
Tab(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
kPostChannelIcons[
|
||||||
|
kPostChannels.indexOf(channel)],
|
||||||
|
size: 20,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor,
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
'postChannel$channel',
|
||||||
|
maxLines: 1,
|
||||||
|
).tr().textColor(Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
),
|
|
||||||
Tab(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Symbols.group,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.appBarTheme
|
|
||||||
.foregroundColor),
|
|
||||||
const Gap(8),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
'postChannelFriends',
|
|
||||||
maxLines: 1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
).tr().textColor(
|
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Tab(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Symbols.subscriptions,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.appBarTheme
|
|
||||||
.foregroundColor),
|
|
||||||
const Gap(8),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
'postChannelFollowing',
|
|
||||||
maxLines: 1,
|
|
||||||
).tr().textColor(
|
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Tab(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Symbols.workspaces,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.appBarTheme
|
|
||||||
.foregroundColor),
|
|
||||||
const Gap(8),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
'postChannelRealm',
|
|
||||||
maxLines: 1,
|
|
||||||
).tr().textColor(
|
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
body: TabBarView(
|
body: _PostListWidget(
|
||||||
controller: _tabController,
|
key: _listKeys,
|
||||||
children: [
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[0],
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[1],
|
|
||||||
channel: 'friends',
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[2],
|
|
||||||
channel: 'following',
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[3],
|
|
||||||
withRealm: true,
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -302,15 +302,7 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PostListWidget extends StatefulWidget {
|
class _PostListWidget extends StatefulWidget {
|
||||||
final String? channel;
|
const _PostListWidget({super.key});
|
||||||
final bool withRealm;
|
|
||||||
final Function onClearFilter;
|
|
||||||
|
|
||||||
const _PostListWidget(
|
|
||||||
{super.key,
|
|
||||||
this.channel,
|
|
||||||
this.withRealm = false,
|
|
||||||
required this.onClearFilter});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_PostListWidget> createState() => _PostListWidgetState();
|
State<_PostListWidget> createState() => _PostListWidgetState();
|
||||||
@ -320,25 +312,11 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
|
|
||||||
final List<SnPost> _posts = List.empty(growable: true);
|
final List<SnPost> _posts = List.empty(growable: true);
|
||||||
final List<SnRealm> _realms = List.empty(growable: true);
|
|
||||||
SnRealm? _selectedRealm;
|
SnRealm? _selectedRealm;
|
||||||
|
String? _selectedChannel;
|
||||||
|
SnPostCategory? _selectedCategory;
|
||||||
int? _postCount;
|
int? _postCount;
|
||||||
|
|
||||||
Future<void> _fetchRealms() async {
|
|
||||||
try {
|
|
||||||
final rels = context.read<SnRealmProvider>();
|
|
||||||
final out = await rels.listAvailableRealms();
|
|
||||||
setState(() {
|
|
||||||
_realms.addAll(out);
|
|
||||||
_selectedRealm = out.firstOrNull;
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
if (!mounted) return;
|
|
||||||
context.showErrorDialog(err);
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _fetchPosts() async {
|
Future<void> _fetchPosts() async {
|
||||||
if (_postCount != null && _posts.length >= _postCount!) return;
|
if (_postCount != null && _posts.length >= _postCount!) return;
|
||||||
|
|
||||||
@ -349,7 +327,7 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
take: 10,
|
take: 10,
|
||||||
offset: _posts.length,
|
offset: _posts.length,
|
||||||
categories: _selectedCategory != null ? [_selectedCategory!.alias] : null,
|
categories: _selectedCategory != null ? [_selectedCategory!.alias] : null,
|
||||||
channel: widget.channel,
|
channel: _selectedChannel,
|
||||||
realm: _selectedRealm?.alias,
|
realm: _selectedRealm?.alias,
|
||||||
);
|
);
|
||||||
final out = result.$1;
|
final out = result.$1;
|
||||||
@ -362,6 +340,21 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
if (mounted) setState(() => _isBusy = false);
|
if (mounted) setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setChannel(String? channel) {
|
||||||
|
_selectedChannel = channel;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRealm(SnRealm? realm) {
|
||||||
|
_selectedRealm = realm;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCategory(SnPostCategory? category) {
|
||||||
|
_selectedCategory = category;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> refreshPosts() {
|
Future<void> refreshPosts() {
|
||||||
_postCount = null;
|
_postCount = null;
|
||||||
_posts.clear();
|
_posts.clear();
|
||||||
@ -371,13 +364,7 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
if (widget.withRealm) {
|
_fetchPosts();
|
||||||
_fetchRealms().then((_) {
|
|
||||||
_fetchPosts();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
_fetchPosts();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -400,52 +387,13 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.clear),
|
icon: const Icon(Symbols.clear),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.onClearFilter.call();
|
setState(() => _selectedCategory = null);
|
||||||
refreshPosts();
|
refreshPosts();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
padding: const EdgeInsets.only(left: 20, right: 4),
|
padding: const EdgeInsets.only(left: 20, right: 4),
|
||||||
),
|
),
|
||||||
if (widget.withRealm)
|
|
||||||
DropdownButtonHideUnderline(
|
|
||||||
child: DropdownButton2<SnRealm>(
|
|
||||||
isExpanded: true,
|
|
||||||
items: _realms
|
|
||||||
.map(
|
|
||||||
(ele) => DropdownMenuItem<SnRealm>(
|
|
||||||
value: ele,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
AccountImage(
|
|
||||||
content: ele.avatar,
|
|
||||||
fallbackWidget: const Icon(Symbols.group, size: 16),
|
|
||||||
radius: 14,
|
|
||||||
),
|
|
||||||
const Gap(8),
|
|
||||||
Text(
|
|
||||||
ele.name,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
value: _selectedRealm,
|
|
||||||
onChanged: (SnRealm? value) {
|
|
||||||
setState(() => _selectedRealm = value);
|
|
||||||
refreshPosts();
|
|
||||||
},
|
|
||||||
buttonStyleData: const ButtonStyleData(
|
|
||||||
padding: EdgeInsets.only(left: 4, right: 12),
|
|
||||||
),
|
|
||||||
menuItemStyleData: const MenuItemStyleData(
|
|
||||||
height: 48,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (widget.withRealm) const Divider(height: 1),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MediaQuery.removePadding(
|
child: MediaQuery.removePadding(
|
||||||
context: context,
|
context: context,
|
||||||
@ -454,6 +402,7 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
displacement: 40 + MediaQuery.of(context).padding.top,
|
displacement: 40 + MediaQuery.of(context).padding.top,
|
||||||
onRefresh: () => refreshPosts(),
|
onRefresh: () => refreshPosts(),
|
||||||
child: InfiniteList(
|
child: InfiniteList(
|
||||||
|
padding: EdgeInsets.only(top: 8),
|
||||||
itemCount: _posts.length,
|
itemCount: _posts.length,
|
||||||
isLoading: _isBusy,
|
isLoading: _isBusy,
|
||||||
centerLoading: true,
|
centerLoading: true,
|
||||||
@ -475,83 +424,6 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
separatorBuilder: (_, __) => const Gap(8),
|
separatorBuilder: (_, __) => const Gap(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).padding(top: 8),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PostCategoryPickerPopup extends StatelessWidget {
|
|
||||||
final List<SnPostCategory> categories;
|
|
||||||
final SnPostCategory? selected;
|
|
||||||
|
|
||||||
const _PostCategoryPickerPopup({required this.categories, this.selected});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Icon(Symbols.category, size: 24),
|
|
||||||
const Gap(16),
|
|
||||||
Text('postCategory')
|
|
||||||
.tr()
|
|
||||||
.textStyle(Theme.of(context).textTheme.titleLarge!),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 20, top: 16, bottom: 12),
|
|
||||||
ListTile(
|
|
||||||
leading: const Icon(Symbols.clear),
|
|
||||||
title: Text('postFilterReset').tr(),
|
|
||||||
subtitle: Text('postFilterResetDescription').tr(),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.pop(context, false);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Divider(height: 1),
|
|
||||||
Expanded(
|
|
||||||
child: GridView.count(
|
|
||||||
crossAxisCount: 4,
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
childAspectRatio: 1,
|
|
||||||
children: categories
|
|
||||||
.map(
|
|
||||||
(ele) => InkWell(
|
|
||||||
onTap: () {
|
|
||||||
_selectedCategory = ele;
|
|
||||||
Navigator.pop(context, ele);
|
|
||||||
},
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
kCategoryIcons[ele.alias] ?? Symbols.question_mark,
|
|
||||||
color: selected == ele
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
const Gap(4),
|
|
||||||
Text(
|
|
||||||
'postCategory${ele.alias.capitalize()}'.trExists()
|
|
||||||
? 'postCategory${ele.alias.capitalize()}'.tr()
|
|
||||||
: ele.name,
|
|
||||||
)
|
|
||||||
.textStyle(Theme.of(context).textTheme.titleMedium!)
|
|
||||||
.textColor(selected == ele
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: null),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user