Solian/lib/controllers/post_editor_controller.dart

325 lines
8.9 KiB
Dart
Raw Normal View History

2024-07-30 08:29:30 +00:00
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:solian/models/post.dart';
import 'package:solian/models/realm.dart';
2024-07-30 12:49:01 +00:00
import 'package:solian/widgets/attachments/attachment_editor.dart';
2024-07-30 18:00:03 +00:00
import 'package:solian/widgets/posts/editor/post_editor_categories_tags.dart';
import 'package:solian/widgets/posts/editor/post_editor_date.dart';
import 'package:solian/widgets/posts/editor/post_editor_overview.dart';
2024-08-01 07:21:43 +00:00
import 'package:solian/widgets/posts/editor/post_editor_publish_zone.dart';
2024-07-30 12:49:01 +00:00
import 'package:solian/widgets/posts/editor/post_editor_visibility.dart';
2024-07-30 08:29:30 +00:00
import 'package:shared_preferences/shared_preferences.dart';
class PostEditorController extends GetxController {
2024-07-30 08:29:30 +00:00
late final SharedPreferences _prefs;
final titleController = TextEditingController();
final descriptionController = TextEditingController();
final contentController = TextEditingController();
RxInt mode = 0.obs;
RxInt contentLength = 0.obs;
Rx<Post?> editTo = Rx(null);
Rx<Post?> replyTo = Rx(null);
Rx<Post?> repostTo = Rx(null);
Rx<Realm?> realmZone = Rx(null);
Rx<DateTime?> publishedAt = Rx(null);
Rx<DateTime?> publishedUntil = Rx(null);
RxList<int> attachments = RxList<int>.empty(growable: true);
2024-07-30 18:00:03 +00:00
RxList<String> tags = RxList<String>.empty(growable: true);
2024-07-30 12:49:01 +00:00
RxList<int> visibleUsers = RxList.empty(growable: true);
RxList<int> invisibleUsers = RxList.empty(growable: true);
RxInt visibility = 0.obs;
RxBool isDraft = false.obs;
2024-07-30 08:29:30 +00:00
RxBool isRestoreFromLocal = false.obs;
Rx<DateTime?> lastSaveTime = Rx(null);
Timer? _saveTimer;
PostEditorController() {
2024-07-30 08:29:30 +00:00
SharedPreferences.getInstance().then((inst) {
_prefs = inst;
_saveTimer = Timer.periodic(
const Duration(seconds: 3),
(Timer t) {
if (isNotEmpty) {
localSave();
lastSaveTime.value = DateTime.now();
lastSaveTime.refresh();
} else if (_prefs.containsKey('post_editor_local_save')) {
localClear();
lastSaveTime.value = null;
}
},
);
});
contentController.addListener(() {
contentLength.value = contentController.text.length;
});
}
Future<void> editOverview(BuildContext context) {
return showDialog(
context: context,
builder: (context) => PostEditorOverviewDialog(
controller: this,
),
);
}
2024-07-30 12:49:01 +00:00
Future<void> editVisibility(BuildContext context) {
return showDialog(
context: context,
builder: (context) => PostEditorVisibilityDialog(
controller: this,
),
);
}
2024-07-30 18:00:03 +00:00
Future<void> editCategoriesAndTags(BuildContext context) {
return showDialog(
context: context,
builder: (context) => PostEditorCategoriesDialog(
controller: this,
),
);
}
2024-08-01 07:21:43 +00:00
Future<void> editPublishZone(BuildContext context) {
return showDialog(
context: context,
builder: (context) => PostEditorPublishZoneDialog(
controller: this,
),
);
}
Future<void> editPublishDate(BuildContext context) {
return showDialog(
context: context,
builder: (context) => PostEditorDateDialog(
controller: this,
),
);
}
Future<void> editAttachment(BuildContext context) {
return showModalBottomSheet(
context: context,
2024-07-30 12:49:01 +00:00
builder: (context) => AttachmentEditorPopup(
usage: 'i.attachment',
2024-08-01 14:13:08 +00:00
initialAttachments: attachments,
onAdd: (int value) {
2024-08-01 14:13:08 +00:00
attachments.add(value);
},
onRemove: (int value) {
2024-08-01 14:13:08 +00:00
attachments.remove(value);
},
),
);
}
void toggleDraftMode() {
isDraft.value = !isDraft.value;
}
2024-07-30 08:29:30 +00:00
void localSave() {
_prefs.setString(
'post_editor_local_save',
jsonEncode({
...payload,
'reply_to': replyTo.value?.toJson(),
'repost_to': repostTo.value?.toJson(),
'edit_to': editTo.value?.toJson(),
'realm': realmZone.value?.toJson(),
'type': type,
2024-07-30 08:29:30 +00:00
}),
);
}
void localRead() {
2024-08-01 08:09:09 +00:00
SharedPreferences.getInstance().then((inst) {
if (inst.containsKey('post_editor_local_save')) {
isRestoreFromLocal.value = true;
payload = jsonDecode(inst.getString('post_editor_local_save')!);
}
});
2024-07-30 08:29:30 +00:00
}
void localClear() {
_prefs.remove('post_editor_local_save');
}
void currentClear() {
titleController.clear();
descriptionController.clear();
contentController.clear();
attachments.clear();
2024-07-30 18:00:03 +00:00
tags.clear();
2024-07-30 12:49:01 +00:00
visibleUsers.clear();
invisibleUsers.clear();
visibility.value = 0;
2024-08-01 14:13:08 +00:00
publishedAt.value = null;
publishedUntil.value = null;
2024-07-30 08:29:30 +00:00
isDraft.value = false;
isRestoreFromLocal.value = false;
lastSaveTime.value = null;
contentLength.value = 0;
editTo.value = null;
replyTo.value = null;
repostTo.value = null;
realmZone.value = null;
}
set editTarget(Post? value) {
if (value == null) {
editTo.value = null;
return;
}
type = value.type;
editTo.value = value;
isDraft.value = value.isDraft ?? false;
titleController.text = value.body['title'] ?? '';
descriptionController.text = value.body['description'] ?? '';
contentController.text = value.body['content'] ?? '';
publishedAt.value = value.publishedAt;
publishedUntil.value = value.publishedUntil;
2024-08-01 03:49:28 +00:00
tags.value =
value.body['tags']?.map((x) => x['alias']).toList() ?? List.empty();
tags.refresh();
attachments.value = value.body['attachments']?.cast<int>() ?? List.empty();
attachments.refresh();
contentLength.value = contentController.text.length;
}
String get typeEndpoint {
2024-07-30 12:49:01 +00:00
switch (mode.value) {
case 0:
return 'stories';
case 1:
return 'articles';
default:
return 'stories';
}
}
String get type {
2024-07-30 12:49:01 +00:00
switch (mode.value) {
case 0:
return 'story';
case 1:
return 'article';
default:
return 'story';
}
}
set type(String value) {
switch (value) {
case 'story':
mode.value = 0;
case 'article':
mode.value = 1;
}
}
String? get title {
if (titleController.text.isEmpty) return null;
return titleController.text;
}
String? get description {
if (descriptionController.text.isEmpty) return null;
return descriptionController.text;
}
Map<String, dynamic> get payload {
return {
'title': title,
'description': description,
'content': contentController.text,
2024-08-01 03:49:28 +00:00
'tags': tags.map((x) => {'alias': x}).toList(),
'attachments': attachments,
2024-07-30 12:49:01 +00:00
'visible_users': visibleUsers,
'invisible_users': invisibleUsers,
'visibility': visibility.value,
'published_at': publishedAt.value?.toUtc().toIso8601String() ??
DateTime.now().toUtc().toIso8601String(),
'published_until': publishedUntil.value?.toUtc().toIso8601String(),
'is_draft': isDraft.value,
if (replyTo.value != null) 'reply_to': replyTo.value!.id,
if (repostTo.value != null) 'repost_to': repostTo.value!.id,
if (realmZone.value != null) 'realm': realmZone.value!.alias,
};
}
2024-07-30 08:29:30 +00:00
set payload(Map<String, dynamic> value) {
type = value['type'];
2024-08-01 08:09:09 +00:00
tags.value = value['tags'].map((x) => x['alias']).toList().cast<String>();
2024-07-30 08:29:30 +00:00
titleController.text = value['title'] ?? '';
descriptionController.text = value['description'] ?? '';
contentController.text = value['content'] ?? '';
attachments.value = value['attachments'].cast<int>() ?? List.empty();
attachments.refresh();
2024-07-30 12:49:01 +00:00
visibility.value = value['visibility'];
2024-07-30 08:29:30 +00:00
isDraft.value = value['is_draft'];
2024-07-30 12:49:01 +00:00
if (value['visible_users'] != null) {
visibleUsers.value = value['visible_users'].cast<int>();
}
if (value['invisible_users'] != null) {
invisibleUsers.value = value['invisible_users'].cast<int>();
}
if (value['published_at'] != null) {
publishedAt.value = DateTime.parse(value['published_at']).toLocal();
}
if (value['published_until'] != null) {
publishedAt.value = DateTime.parse(value['published_until']).toLocal();
}
2024-07-30 08:29:30 +00:00
if (value['reply_to'] != null) {
replyTo.value = Post.fromJson(value['reply_to']);
}
if (value['repost_to'] != null) {
repostTo.value = Post.fromJson(value['repost_to']);
}
if (value['edit_to'] != null) {
editTo.value = Post.fromJson(value['edit_to']);
}
if (value['realm'] != null) {
realmZone.value = Realm.fromJson(value['realm']);
}
}
bool get isEmpty {
if (contentController.text.isEmpty) return true;
return false;
}
2024-07-30 08:29:30 +00:00
bool get isNotEmpty {
return [
titleController.text.isNotEmpty,
descriptionController.text.isNotEmpty,
contentController.text.isNotEmpty,
attachments.isNotEmpty,
2024-07-30 18:00:03 +00:00
tags.isNotEmpty
2024-07-30 08:29:30 +00:00
].any((x) => x);
}
@override
void dispose() {
2024-07-30 08:29:30 +00:00
_saveTimer?.cancel();
2024-07-30 18:00:03 +00:00
titleController.dispose();
descriptionController.dispose();
contentController.dispose();
super.dispose();
}
}