Able to edit visibility

This commit is contained in:
2024-07-30 20:49:01 +08:00
parent bb77b74356
commit 19751617cb
10 changed files with 406 additions and 51 deletions

View File

@ -0,0 +1,176 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:solian/models/account.dart';
import 'package:solian/models/relations.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/providers/relation.dart';
import 'package:solian/services.dart';
import 'package:solian/widgets/account/account_avatar.dart';
class AccountSelector extends StatefulWidget {
final String title;
final Widget? Function(Account item)? trailingBuilder;
final List<int>? initialSelection;
final Function(List<Account>)? onMultipleSelect;
const AccountSelector({
super.key,
required this.title,
this.trailingBuilder,
this.initialSelection,
this.onMultipleSelect,
});
@override
State<AccountSelector> createState() => _AccountSelectorState();
}
class _AccountSelectorState extends State<AccountSelector> {
final TextEditingController _probeController = TextEditingController();
final List<Account> _relativeUsers = List.empty(growable: true);
final List<Account> _pendingUsers = List.empty(growable: true);
final List<Account> _selectedUsers = List.empty(growable: true);
int _accountId = 0;
_revertSelectedUsers() async {
if (widget.initialSelection?.isEmpty ?? true) return;
final client = ServiceFinder.configureClient('auth');
final idQuery = widget.initialSelection!.join(',');
final resp = await client.get('/users?id=$idQuery');
setState(() {
_selectedUsers.addAll(
resp.body
.map((e) => Account.fromJson(e))
.toList()
.cast<Account>(),
);
});
}
_getFriends() async {
final AuthProvider auth = Get.find();
_accountId = auth.userProfile.value!['id'];
final RelationshipProvider provider = Get.find();
final resp = await provider.listRelationWithStatus(1);
setState(() {
_relativeUsers.addAll(
resp.body
.map((e) => Relationship.fromJson(e).related)
.toList()
.cast<Account>(),
);
});
}
_searchAccount() async {
final AuthProvider auth = Get.find();
_accountId = auth.userProfile.value!['id'];
if (_probeController.text.isEmpty) return;
final client = auth.configureClient('auth');
final resp = await client.get(
'/users/search?probe=${_probeController.text}',
);
setState(() {
_pendingUsers.clear();
_pendingUsers.addAll(
resp.body.map((e) => Account.fromJson(e)).toList().cast<Account>(),
);
});
}
bool _checkSelected(Account item) {
return _selectedUsers.any((x) => x.id == item.id);
}
@override
void initState() {
super.initState();
_getFriends();
_revertSelectedUsers();
}
@override
void dispose() {
super.dispose();
_probeController.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.85,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: Theme.of(context).textTheme.headlineSmall,
).paddingOnly(left: 24, right: 24, top: 32, bottom: 16),
Container(
color: Theme.of(context).colorScheme.secondaryContainer,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: TextField(
controller: _probeController,
decoration: InputDecoration(
isCollapsed: true,
border: InputBorder.none,
hintText: 'search'.tr,
),
onSubmitted: (_) {
_searchAccount();
},
),
),
Expanded(
child: ListView.builder(
itemCount: _pendingUsers.isEmpty
? _relativeUsers.length
: _pendingUsers.length,
itemBuilder: (context, index) {
var element = _pendingUsers.isEmpty
? _relativeUsers[index]
: _pendingUsers[index];
return ListTile(
title: Text(element.nick),
subtitle: Text(element.name),
leading: AccountAvatar(content: element.avatar),
trailing: widget.trailingBuilder != null
? widget.trailingBuilder!(element)
: _checkSelected(element)
? const Icon(Icons.check)
: null,
onTap: element.id == _accountId
? null
: () {
if (widget.onMultipleSelect == null) {
Navigator.pop(context, element);
return;
}
setState(() {
final idx = _selectedUsers.indexWhere((x) => x.id == element.id);
if (idx != -1) {
_selectedUsers.removeAt(idx);
} else {
_selectedUsers.add(element);
}
});
widget.onMultipleSelect!(_selectedUsers);
},
);
},
),
),
],
),
);
}
}

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:solian/models/account.dart';
import 'package:solian/models/relations.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/providers/relation.dart';
import 'package:solian/widgets/account/account_avatar.dart';
@ -10,21 +9,17 @@ class RelativeSelector extends StatefulWidget {
final String title;
final Widget? Function(Account item)? trailingBuilder;
const RelativeSelector({super.key, required this.title, this.trailingBuilder});
const RelativeSelector(
{super.key, required this.title, this.trailingBuilder});
@override
State<RelativeSelector> createState() => _RelativeSelectorState();
}
class _RelativeSelectorState extends State<RelativeSelector> {
int _accountId = 0;
final List<Relationship> _friends = List.empty(growable: true);
getFriends() async {
final AuthProvider auth = Get.find();
_accountId = auth.userProfile.value!['id'];
_getFriends() async {
final RelationshipProvider provider = Get.find();
final resp = await provider.listRelationWithStatus(1);
@ -39,8 +34,7 @@ class _RelativeSelectorState extends State<RelativeSelector> {
@override
void initState() {
super.initState();
getFriends();
_getFriends();
}
@override
@ -58,7 +52,7 @@ class _RelativeSelectorState extends State<RelativeSelector> {
child: ListView.builder(
itemCount: _friends.length,
itemBuilder: (context, index) {
var element = _friends[index].getOtherside(_accountId);
var element = _friends[index].related;
return ListTile(
title: Text(element.nick),
subtitle: Text(element.name),

View File

@ -18,12 +18,12 @@ import 'package:solian/providers/auth.dart';
import 'package:solian/providers/content/attachment.dart';
import 'package:solian/widgets/attachments/attachment_item.dart';
class AttachmentPublishPopup extends StatefulWidget {
class AttachmentEditorPopup extends StatefulWidget {
final String usage;
final List<int> current;
final void Function(List<int> data) onUpdate;
const AttachmentPublishPopup({
const AttachmentEditorPopup({
super.key,
required this.usage,
required this.current,
@ -31,10 +31,10 @@ class AttachmentPublishPopup extends StatefulWidget {
});
@override
State<AttachmentPublishPopup> createState() => _AttachmentPublishPopupState();
State<AttachmentEditorPopup> createState() => _AttachmentEditorPopupState();
}
class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
final _imagePicker = ImagePicker();
bool _isBusy = false;

View File

@ -6,7 +6,7 @@ import 'package:solian/models/account.dart';
import 'package:solian/models/channel.dart';
import 'package:solian/models/event.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/widgets/attachments/attachment_publish.dart';
import 'package:solian/widgets/attachments/attachment_editor.dart';
import 'package:solian/widgets/chat/chat_event.dart';
import 'package:uuid/uuid.dart';
@ -47,7 +47,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => AttachmentPublishPopup(
builder: (context) => AttachmentEditorPopup(
usage: 'm.attachment',
current: _attachments,
onUpdate: (value) => _attachments = value,

View File

@ -0,0 +1,127 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:solian/controllers/post_editor_controller.dart';
import 'package:solian/widgets/account/account_select.dart';
class PostEditorVisibilityDialog extends StatelessWidget {
final PostEditorController controller;
const PostEditorVisibilityDialog({super.key, required this.controller});
static List<(int, String)> visibilityLevels = [
(0, 'postVisibilityAll'),
(1, 'postVisibilityFriends'),
(2, 'postVisibilitySelected'),
(3, 'postVisibilityFiltered'),
(4, 'postVisibilityNone'),
];
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('postVisibility'.tr),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Obx(() {
return DropdownButtonFormField2<int>(
isExpanded: true,
decoration: const InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
),
items: visibilityLevels
.map(
(entry) => DropdownMenuItem<int>(
value: entry.$1,
child: Text(
entry.$2.tr,
style: const TextStyle(fontSize: 14),
),
),
)
.toList(),
value: controller.visibility.value,
onChanged: (int? value) {
if (value != null) {
controller.visibility.value = value;
}
},
buttonStyleData: const ButtonStyleData(height: 20),
menuItemStyleData: const MenuItemStyleData(height: 40),
);
}),
Obx(() {
if (controller.visibility.value != 2 &&
controller.visibility.value != 3) {
return const SizedBox(height: 8);
}
return const SizedBox();
}),
Obx(() {
if (controller.visibility.value == 2) {
return ListTile(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
contentPadding: const EdgeInsets.only(left: 16, right: 13),
trailing: const Icon(Icons.chevron_right),
title: Text('postVisibleUsers'.tr),
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => AccountSelector(
title: 'postVisibleUsers'.tr,
initialSelection: controller.visibleUsers,
onMultipleSelect: (value) {
controller.visibleUsers.value =
value.map((e) => e.id).toList();
controller.visibleUsers.refresh();
},
),
);
},
);
}
return const SizedBox();
}),
Obx(() {
if (controller.visibility.value == 3) {
return ListTile(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
contentPadding: const EdgeInsets.only(left: 16, right: 13),
trailing: const Icon(Icons.chevron_right),
title: Text('postInvisibleUsers'.tr),
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => AccountSelector(
title: 'postInvisibleUsers'.tr,
initialSelection: controller.invisibleUsers,
onMultipleSelect: (value) {
controller.invisibleUsers.value =
value.map((e) => e.id).toList();
controller.invisibleUsers.refresh();
},
),
);
},
);
}
return const SizedBox();
}),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('confirm'.tr),
),
],
);
}
}