♻️ Refactor the profile and pub profile
This commit is contained in:
@@ -27,112 +27,24 @@ import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'pub_profile.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<SnPublisher> publisher(Ref ref, String uname) async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get("/sphere/publishers/$uname");
|
||||
return SnPublisher.fromJson(resp.data);
|
||||
}
|
||||
class _PublisherBasisWidget extends StatelessWidget {
|
||||
final SnPublisher data;
|
||||
final AsyncValue<SnSubscriptionStatus> subStatus;
|
||||
final ValueNotifier<bool> subscribing;
|
||||
final VoidCallback subscribe;
|
||||
final VoidCallback unsubscribe;
|
||||
|
||||
@riverpod
|
||||
Future<List<SnAccountBadge>> publisherBadges(Ref ref, String pubName) async {
|
||||
final pub = await ref.watch(publisherProvider(pubName).future);
|
||||
if (pub.type != 0 || pub.account == null) return [];
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get("/id/accounts/${pub.account!.name}/badges");
|
||||
return List<SnAccountBadge>.from(
|
||||
resp.data.map((x) => SnAccountBadge.fromJson(x)),
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<SnSubscriptionStatus> publisherSubscriptionStatus(
|
||||
Ref ref,
|
||||
String pubName,
|
||||
) async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get("/sphere/publishers/$pubName/subscription");
|
||||
return SnSubscriptionStatus.fromJson(resp.data);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<Color?> publisherAppbarForcegroundColor(Ref ref, String pubName) async {
|
||||
try {
|
||||
final publisher = await ref.watch(publisherProvider(pubName).future);
|
||||
if (publisher.background == null) return null;
|
||||
final palette = await PaletteGenerator.fromImageProvider(
|
||||
CloudImageWidget.provider(
|
||||
fileId: publisher.background!.id,
|
||||
serverUrl: ref.watch(serverUrlProvider),
|
||||
),
|
||||
);
|
||||
final dominantColor = palette.dominantColor?.color;
|
||||
if (dominantColor == null) return null;
|
||||
return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class PublisherProfileScreen extends HookConsumerWidget {
|
||||
final String name;
|
||||
const PublisherProfileScreen({super.key, required this.name});
|
||||
const _PublisherBasisWidget({
|
||||
required this.data,
|
||||
required this.subStatus,
|
||||
required this.subscribing,
|
||||
required this.subscribe,
|
||||
required this.unsubscribe,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final publisher = ref.watch(publisherProvider(name));
|
||||
final badges = ref.watch(publisherBadgesProvider(name));
|
||||
final subStatus = ref.watch(publisherSubscriptionStatusProvider(name));
|
||||
final appbarColor = ref.watch(
|
||||
publisherAppbarForcegroundColorProvider(name),
|
||||
);
|
||||
|
||||
final categoryTabController = useTabController(initialLength: 3);
|
||||
final categoryTab = useState(0);
|
||||
categoryTabController.addListener(() {
|
||||
categoryTab.value = categoryTabController.index;
|
||||
});
|
||||
|
||||
final subscribing = useState(false);
|
||||
|
||||
Future<void> subscribe() async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
subscribing.value = true;
|
||||
try {
|
||||
await apiClient.post(
|
||||
"/sphere/publishers/$name/subscribe",
|
||||
data: {'tier': 0},
|
||||
);
|
||||
ref.invalidate(publisherSubscriptionStatusProvider(name));
|
||||
HapticFeedback.heavyImpact();
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
subscribing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> unsubscribe() async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
subscribing.value = true;
|
||||
try {
|
||||
await apiClient.post("/sphere/publishers/$name/unsubscribe");
|
||||
ref.invalidate(publisherSubscriptionStatusProvider(name));
|
||||
HapticFeedback.heavyImpact();
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
subscribing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
final appbarShadow = Shadow(
|
||||
color: appbarColor.value?.invert ?? Colors.transparent,
|
||||
blurRadius: 5.0,
|
||||
offset: Offset(1.0, 1.0),
|
||||
);
|
||||
|
||||
Widget publisherBasisWidget(SnPublisher data) => Row(
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 20,
|
||||
children: [
|
||||
@@ -247,25 +159,51 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 24, top: 24);
|
||||
}
|
||||
}
|
||||
|
||||
Widget publisherBadgesWidget(SnPublisher data) =>
|
||||
(badges.value?.isNotEmpty ?? false)
|
||||
? Card(
|
||||
child: BadgeList(
|
||||
badges: badges.value!,
|
||||
).padding(horizontal: 26, vertical: 20),
|
||||
).padding(horizontal: 4)
|
||||
: const SizedBox.shrink();
|
||||
class _PublisherBadgesWidget extends StatelessWidget {
|
||||
final SnPublisher data;
|
||||
final AsyncValue<List<SnAccountBadge>> badges;
|
||||
|
||||
Widget publisherVerificationWidget(SnPublisher data) =>
|
||||
(data.verification != null)
|
||||
? Card(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: VerificationStatusCard(mark: data.verification!),
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
const _PublisherBadgesWidget({required this.data, required this.badges});
|
||||
|
||||
Widget publisherBioWidget(SnPublisher data) => Card(
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return (badges.value?.isNotEmpty ?? false)
|
||||
? Card(
|
||||
child: BadgeList(
|
||||
badges: badges.value!,
|
||||
).padding(horizontal: 26, vertical: 20),
|
||||
).padding(horizontal: 4)
|
||||
: const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
class _PublisherVerificationWidget extends StatelessWidget {
|
||||
final SnPublisher data;
|
||||
|
||||
const _PublisherVerificationWidget({required this.data});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return (data.verification != null)
|
||||
? Card(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: VerificationStatusCard(mark: data.verification!),
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
class _PublisherBioWidget extends StatelessWidget {
|
||||
final SnPublisher data;
|
||||
|
||||
const _PublisherBioWidget({required this.data});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
@@ -281,8 +219,17 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
],
|
||||
).padding(horizontal: 20, vertical: 16),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget publisherCategoryTabWidget() => Card(
|
||||
class _PublisherCategoryTabWidget extends StatelessWidget {
|
||||
final TabController categoryTabController;
|
||||
|
||||
const _PublisherCategoryTabWidget({required this.categoryTabController});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: TabBar(
|
||||
controller: categoryTabController,
|
||||
@@ -295,6 +242,113 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<SnPublisher> publisher(Ref ref, String uname) async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get("/sphere/publishers/$uname");
|
||||
return SnPublisher.fromJson(resp.data);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<List<SnAccountBadge>> publisherBadges(Ref ref, String pubName) async {
|
||||
final pub = await ref.watch(publisherProvider(pubName).future);
|
||||
if (pub.type != 0 || pub.account == null) return [];
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get("/id/accounts/${pub.account!.name}/badges");
|
||||
return List<SnAccountBadge>.from(
|
||||
resp.data.map((x) => SnAccountBadge.fromJson(x)),
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<SnSubscriptionStatus> publisherSubscriptionStatus(
|
||||
Ref ref,
|
||||
String pubName,
|
||||
) async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final resp = await apiClient.get("/sphere/publishers/$pubName/subscription");
|
||||
return SnSubscriptionStatus.fromJson(resp.data);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<Color?> publisherAppbarForcegroundColor(Ref ref, String pubName) async {
|
||||
try {
|
||||
final publisher = await ref.watch(publisherProvider(pubName).future);
|
||||
if (publisher.background == null) return null;
|
||||
final palette = await PaletteGenerator.fromImageProvider(
|
||||
CloudImageWidget.provider(
|
||||
fileId: publisher.background!.id,
|
||||
serverUrl: ref.watch(serverUrlProvider),
|
||||
),
|
||||
);
|
||||
final dominantColor = palette.dominantColor?.color;
|
||||
if (dominantColor == null) return null;
|
||||
return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class PublisherProfileScreen extends HookConsumerWidget {
|
||||
final String name;
|
||||
const PublisherProfileScreen({super.key, required this.name});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final publisher = ref.watch(publisherProvider(name));
|
||||
final badges = ref.watch(publisherBadgesProvider(name));
|
||||
final subStatus = ref.watch(publisherSubscriptionStatusProvider(name));
|
||||
final appbarColor = ref.watch(
|
||||
publisherAppbarForcegroundColorProvider(name),
|
||||
);
|
||||
|
||||
final categoryTabController = useTabController(initialLength: 3);
|
||||
final categoryTab = useState(0);
|
||||
categoryTabController.addListener(() {
|
||||
categoryTab.value = categoryTabController.index;
|
||||
});
|
||||
|
||||
final subscribing = useState(false);
|
||||
|
||||
Future<void> subscribe() async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
subscribing.value = true;
|
||||
try {
|
||||
await apiClient.post(
|
||||
"/sphere/publishers/$name/subscribe",
|
||||
data: {'tier': 0},
|
||||
);
|
||||
ref.invalidate(publisherSubscriptionStatusProvider(name));
|
||||
HapticFeedback.heavyImpact();
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
subscribing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> unsubscribe() async {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
subscribing.value = true;
|
||||
try {
|
||||
await apiClient.post("/sphere/publishers/$name/unsubscribe");
|
||||
ref.invalidate(publisherSubscriptionStatusProvider(name));
|
||||
HapticFeedback.heavyImpact();
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
subscribing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
final appbarShadow = Shadow(
|
||||
color: appbarColor.value?.invert ?? Colors.transparent,
|
||||
blurRadius: 5.0,
|
||||
offset: Offset(1.0, 1.0),
|
||||
);
|
||||
|
||||
return publisher.when(
|
||||
data:
|
||||
@@ -351,7 +405,9 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
SliverGap(16),
|
||||
SliverPostList(pubName: name, pinned: true),
|
||||
SliverToBoxAdapter(
|
||||
child: publisherCategoryTabWidget(),
|
||||
child: _PublisherCategoryTabWidget(
|
||||
categoryTabController: categoryTabController,
|
||||
),
|
||||
),
|
||||
SliverPostList(
|
||||
key: ValueKey(categoryTab.value),
|
||||
@@ -377,10 +433,19 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
publisherBasisWidget(data).padding(bottom: 8),
|
||||
publisherBadgesWidget(data),
|
||||
publisherVerificationWidget(data),
|
||||
publisherBioWidget(data),
|
||||
_PublisherBasisWidget(
|
||||
data: data,
|
||||
subStatus: subStatus,
|
||||
subscribing: subscribing,
|
||||
subscribe: subscribe,
|
||||
unsubscribe: unsubscribe,
|
||||
).padding(bottom: 8),
|
||||
_PublisherBadgesWidget(
|
||||
data: data,
|
||||
badges: badges,
|
||||
),
|
||||
_PublisherVerificationWidget(data: data),
|
||||
_PublisherBioWidget(data: data),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -432,15 +497,32 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: publisherBasisWidget(data).padding(bottom: 8),
|
||||
child: _PublisherBasisWidget(
|
||||
data: data,
|
||||
subStatus: subStatus,
|
||||
subscribing: subscribing,
|
||||
subscribe: subscribe,
|
||||
unsubscribe: unsubscribe,
|
||||
).padding(bottom: 8),
|
||||
),
|
||||
SliverToBoxAdapter(child: publisherBadgesWidget(data)),
|
||||
SliverToBoxAdapter(
|
||||
child: publisherVerificationWidget(data),
|
||||
child: _PublisherBadgesWidget(
|
||||
data: data,
|
||||
badges: badges,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _PublisherVerificationWidget(data: data),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _PublisherBioWidget(data: data),
|
||||
),
|
||||
SliverToBoxAdapter(child: publisherBioWidget(data)),
|
||||
SliverPostList(pubName: name, pinned: true),
|
||||
SliverToBoxAdapter(child: publisherCategoryTabWidget()),
|
||||
SliverToBoxAdapter(
|
||||
child: _PublisherCategoryTabWidget(
|
||||
categoryTabController: categoryTabController,
|
||||
),
|
||||
),
|
||||
SliverPostList(
|
||||
key: ValueKey(categoryTab.value),
|
||||
pubName: name,
|
||||
|
Reference in New Issue
Block a user