188 lines
6.9 KiB
Dart
188 lines
6.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:lemmy_api_client/v3.dart';
|
|
import 'package:nested/nested.dart';
|
|
|
|
import '../../hooks/stores.dart';
|
|
import '../../l10n/l10n.dart';
|
|
import '../../stores/accounts_store.dart';
|
|
import '../../util/async_store.dart';
|
|
import '../../util/async_store_listener.dart';
|
|
import '../../util/extensions/api.dart';
|
|
import '../../util/icons.dart';
|
|
import '../../util/mobx_provider.dart';
|
|
import '../../util/observer_consumers.dart';
|
|
import '../../util/share.dart';
|
|
import '../../widgets/failed_to_load.dart';
|
|
import '../../widgets/reveal_after_scroll.dart';
|
|
import '../../widgets/sortable_infinite_list.dart';
|
|
import '../create_post/create_post_fab.dart';
|
|
import 'community_about_tab.dart';
|
|
import 'community_more_menu.dart';
|
|
import 'community_overview.dart';
|
|
import 'community_store.dart';
|
|
|
|
/// Displays posts, comments, and general info about the given community
|
|
class CommunityPage extends HookWidget {
|
|
const CommunityPage();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final accountsStore = useAccountsStore();
|
|
final scrollController = useScrollController();
|
|
|
|
return Nested(
|
|
children: [
|
|
AsyncStoreListener(
|
|
asyncStore: context.read<CommunityStore>().communityState),
|
|
AsyncStoreListener(
|
|
asyncStore: context.read<CommunityStore>().subscribingState),
|
|
AsyncStoreListener(
|
|
asyncStore: context.read<CommunityStore>().blockingState,
|
|
successMessageBuilder: (context, BlockedCommunity data) {
|
|
final name = data.communityView.community.preferredName;
|
|
final blocked = data.blocked ? 'blocked' : 'unblocked';
|
|
return '$name $blocked';
|
|
},
|
|
),
|
|
],
|
|
child: ObserverBuilder<CommunityStore>(builder: (context, store) {
|
|
final communityState = store.communityState;
|
|
final communityAsyncState = communityState.asyncState;
|
|
|
|
// FALLBACK
|
|
if (communityAsyncState is! AsyncStateData<FullCommunityView>) {
|
|
return Scaffold(
|
|
appBar: AppBar(),
|
|
body: Center(
|
|
child: (communityState.errorTerm != null)
|
|
? FailedToLoad(
|
|
refresh: () => store.refresh(context
|
|
.read<AccountsStore>()
|
|
.defaultUserDataFor(store.instanceHost)
|
|
?.jwt),
|
|
message: communityState.errorTerm!.tr(context),
|
|
)
|
|
: const CircularProgressIndicator.adaptive()),
|
|
);
|
|
}
|
|
|
|
final fullCommunityView = communityAsyncState.data;
|
|
final community = fullCommunityView.communityView;
|
|
|
|
void _share() => share(community.community.actorId, context: context);
|
|
|
|
return Scaffold(
|
|
floatingActionButton: CreatePostFab(community: community),
|
|
body: DefaultTabController(
|
|
length: 3,
|
|
child: NestedScrollView(
|
|
controller: scrollController,
|
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
|
SliverAppBar(
|
|
expandedHeight: community.community.icon == null ? 220 : 300,
|
|
pinned: true,
|
|
backgroundColor: theme.cardColor,
|
|
title: RevealAfterScroll(
|
|
scrollController: scrollController,
|
|
after: community.community.icon == null ? 110 : 190,
|
|
fade: true,
|
|
child: Text(
|
|
community.community.preferredName,
|
|
overflow: TextOverflow.fade,
|
|
softWrap: false,
|
|
),
|
|
),
|
|
actions: [
|
|
IconButton(icon: Icon(shareIcon), onPressed: _share),
|
|
IconButton(
|
|
icon: Icon(moreIcon),
|
|
onPressed: () =>
|
|
CommunityMoreMenu.open(context, fullCommunityView)),
|
|
],
|
|
flexibleSpace: FlexibleSpaceBar(
|
|
background: CommunityOverview(fullCommunityView),
|
|
),
|
|
bottom: PreferredSize(
|
|
preferredSize: const TabBar(tabs: []).preferredSize,
|
|
child: Material(
|
|
color: theme.cardColor,
|
|
child: TabBar(
|
|
tabs: [
|
|
Tab(text: L10n.of(context).posts),
|
|
Tab(text: L10n.of(context).comments),
|
|
const Tab(text: 'About'),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
body: TabBarView(
|
|
children: [
|
|
InfinitePostList(
|
|
fetcher: (page, batchSize, sort) =>
|
|
LemmyApiV3(community.instanceHost).run(GetPosts(
|
|
type: PostListingType.community,
|
|
sort: sort,
|
|
communityId: community.community.id,
|
|
page: page,
|
|
limit: batchSize,
|
|
savedOnly: false,
|
|
)),
|
|
),
|
|
InfiniteCommentList(
|
|
fetcher: (page, batchSize, sortType) =>
|
|
LemmyApiV3(community.instanceHost).run(GetComments(
|
|
communityId: community.community.id,
|
|
auth: accountsStore
|
|
.defaultUserDataFor(community.instanceHost)
|
|
?.jwt
|
|
.raw,
|
|
type: CommentListingType.community,
|
|
sort: sortType,
|
|
limit: batchSize,
|
|
page: page,
|
|
savedOnly: false,
|
|
))),
|
|
CommmunityAboutTab(fullCommunityView),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
static Route _route(String instanceHost, CommunityStore store) {
|
|
return MaterialPageRoute(
|
|
builder: (context) {
|
|
return MobxProvider.value(
|
|
value: store
|
|
..refresh(context
|
|
.read<AccountsStore>()
|
|
.defaultUserDataFor(instanceHost)
|
|
?.jwt),
|
|
child: const CommunityPage(),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
static Route fromNameRoute(String instanceHost, String name) {
|
|
return _route(
|
|
instanceHost,
|
|
CommunityStore.fromName(communityName: name, instanceHost: instanceHost),
|
|
);
|
|
}
|
|
|
|
static Route fromIdRoute(String instanceHost, int id) {
|
|
return _route(
|
|
instanceHost,
|
|
CommunityStore.fromId(id: id, instanceHost: instanceHost),
|
|
);
|
|
}
|
|
}
|