Publisher selection

This commit is contained in:
LittleSheep 2025-04-30 00:54:43 +08:00
parent a4e27e57a3
commit 1b790baee1
7 changed files with 132 additions and 12 deletions

View File

@ -46,5 +46,7 @@
"postCreateAccountTitle": "Thanks for joining!",
"postCreateAccountNext": "What's next?",
"postCreateAccountNext1": "Go to your email inbox and receive the account activation email.",
"postCreateAccountNext2": "Log in to your account and start exploring the Solar Network!"
"postCreateAccountNext2": "Log in to your account and start exploring the Solar Network!",
"publishersEmpty": "No publishers yet",
"publishersEmptyDescription": "You can need to create a publisher to start publishing your posts."
}

View File

@ -246,7 +246,7 @@ class EditPublisherScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
final resp = await client.request(
name == null ? '/publishers' : '/publishers/$name',
name == null ? '/publishers/individual' : '/publishers/$name',
data: {
'name': nameController.text,
'nick': nickController.text,

View File

@ -18,7 +18,9 @@ import 'package:island/services/file.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/post/publishers_modal.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'package:styled_widget/styled_widget.dart';
@RoutePage()
@ -94,6 +96,7 @@ class PostComposeScreen extends HookConsumerWidget {
final result = await ref
.watch(imagePickerProvider)
.pickMultiImage(requestFullMetadata: true);
if (result.isEmpty) return;
attachments.value = [
...attachments.value,
...result.map(
@ -106,6 +109,7 @@ class PostComposeScreen extends HookConsumerWidget {
final result = await ref
.watch(imagePickerProvider)
.pickVideo(source: ImageSource.gallery);
if (result == null) return;
attachments.value = [
...attachments.value,
UniversalFile(data: result, type: UniversalFileType.video),
@ -241,9 +245,19 @@ class PostComposeScreen extends HookConsumerWidget {
spacing: 12,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ProfilePictureWidget(
item: currentPublisher.value?.picture,
radius: 24,
GestureDetector(
child: ProfilePictureWidget(
item: currentPublisher.value?.picture,
radius: 24,
),
onTap: () {
showCupertinoModalBottomSheet(
context: context,
builder: (context) => PublisherModal(),
).then((value) {
if (value is SnPublisher) currentPublisher.value = value;
});
},
).padding(top: 16),
Expanded(
child: SingleChildScrollView(

View File

@ -1,10 +1,11 @@
import 'dart:convert';
import 'dart:developer';
import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_platform_alert/flutter_platform_alert.dart';
String _parseRemoteError(DioException err) {
log('${err.requestOptions.method} ${err.requestOptions.uri} ${err.message}');
if (err.response?.data is String) return err.response?.data;
if (err.response?.data?['errors'] != null) {
final errors = err.response?.data['errors'] as Map<String, dynamic>;
@ -15,7 +16,7 @@ String _parseRemoteError(DioException err) {
)
.join('\n');
}
return jsonEncode(err.response?.data);
return err.message ?? err.toString();
}
void showErrorAlert(dynamic err) async {

View File

@ -3,7 +3,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart';
@ -16,7 +16,7 @@ import 'package:lucide_icons/lucide_icons.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:super_context_menu/super_context_menu.dart';
class PostItem extends ConsumerWidget {
class PostItem extends HookConsumerWidget {
final SnPost item;
final EdgeInsets? padding;
final bool isOpenable;

View File

@ -7,7 +7,9 @@ import 'package:island/pods/network.dart';
import 'package:island/screens/account/me/publishers.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/post/publishers_modal.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'package:styled_widget/styled_widget.dart';
class PostQuickReply extends HookConsumerWidget {
@ -62,9 +64,19 @@ class PostQuickReply extends HookConsumerWidget {
(data) => Row(
spacing: 8,
children: [
ProfilePictureWidget(
item: currentPublisher.value?.picture,
radius: 16,
GestureDetector(
child: ProfilePictureWidget(
item: currentPublisher.value?.picture,
radius: 16,
),
onTap: () {
showCupertinoModalBottomSheet(
context: context,
builder: (context) => PublisherModal(),
).then((value) {
if (value is SnPublisher) currentPublisher.value = value;
});
},
).padding(right: 4),
Expanded(
child: TextField(

View File

@ -0,0 +1,91 @@
import 'dart:math' as math;
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/route.gr.dart';
import 'package:island/screens/account/me/publishers.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:styled_widget/styled_widget.dart';
class PublisherModal extends HookConsumerWidget {
const PublisherModal({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final publishers = ref.watch(publishersManagedProvider);
return SizedBox(
height: math.min(MediaQuery.of(context).size.height * 0.4, 480),
child: Column(
children: [
Expanded(
child: Material(
color: Colors.transparent,
child: publishers.when(
data:
(value) =>
value.isEmpty
? ConstrainedBox(
constraints: BoxConstraints(maxWidth: 280),
child:
Column(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'publishersEmpty',
textAlign: TextAlign.center,
).tr().fontSize(17).bold(),
Text(
'publishersEmptyDescription',
textAlign: TextAlign.center,
).tr(),
const Gap(12),
ElevatedButton(
onPressed: () {
context.router
.push(NewPublisherRoute())
.then((value) {
if (value != null) {
ref.invalidate(
publishersManagedProvider,
);
}
});
},
child: Text('createPublisher').tr(),
),
],
).center(),
)
: SingleChildScrollView(
child: Column(
children: [
for (final publisher in value)
ListTile(
leading: ProfilePictureWidget(
item: publisher.picture,
),
title: Text(publisher.nick),
subtitle: Text('@${publisher.name}'),
onTap: () {
Navigator.pop(context, publisher);
},
),
],
),
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Text('Error: $e'),
),
),
),
],
),
);
}
}