add drafts section to settings
This commit is contained in:
parent
5f23176e6e
commit
89df32f4a9
|
@ -12,6 +12,7 @@ import 'app_config.dart';
|
||||||
import 'l10n/timeago/pl.dart';
|
import 'l10n/timeago/pl.dart';
|
||||||
import 'pages/log_console/log_console_page_store.dart';
|
import 'pages/log_console/log_console_page_store.dart';
|
||||||
import 'stores/accounts_store.dart';
|
import 'stores/accounts_store.dart';
|
||||||
|
import 'stores/comment_drafts_store.dart';
|
||||||
import 'stores/config_store.dart';
|
import 'stores/config_store.dart';
|
||||||
import 'util/mobx_provider.dart';
|
import 'util/mobx_provider.dart';
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ Future<void> mainCommon(AppConfig appConfig) async {
|
||||||
final logConsoleStore = LogConsolePageStore();
|
final logConsoleStore = LogConsolePageStore();
|
||||||
final sharedPrefs = await SharedPreferences.getInstance();
|
final sharedPrefs = await SharedPreferences.getInstance();
|
||||||
await Hive.initFlutter();
|
await Hive.initFlutter();
|
||||||
|
await CommentDraftStore.open();
|
||||||
|
|
||||||
_setupLogger(appConfig, logConsoleStore);
|
_setupLogger(appConfig, logConsoleStore);
|
||||||
_setupTimeago();
|
_setupTimeago();
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
|
import '../../stores/comment_drafts_store.dart';
|
||||||
|
|
||||||
|
class DraftsPage extends HookWidget {
|
||||||
|
const DraftsPage._();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DefaultTabController(
|
||||||
|
length: 2,
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: const BackButton(),
|
||||||
|
title: const Text('Drafts'),
|
||||||
|
bottom: const TabBar(
|
||||||
|
isScrollable: true,
|
||||||
|
tabs: [
|
||||||
|
Tab(child: Text('Comments')),
|
||||||
|
Tab(child: Text('Posts')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: const TabBarView(children: [
|
||||||
|
_CommentsTab(),
|
||||||
|
_PostsTab(),
|
||||||
|
])),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Route route() => MaterialPageRoute(
|
||||||
|
builder: (context) => const DraftsPage._(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CommentsTab extends HookWidget {
|
||||||
|
const _CommentsTab();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ValueListenableBuilder<LazyBox<String>>(
|
||||||
|
valueListenable: CommentDraftStore.allDraftsListenable(),
|
||||||
|
builder: (context, box, widget) {
|
||||||
|
if (box.isEmpty) {
|
||||||
|
return const Center(child: Text('no drafts yet'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeAllDrafts() async {
|
||||||
|
final removeAll = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: const Text(
|
||||||
|
'Do you want to remove ALL comment drafts?'),
|
||||||
|
actions: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
primary: Colors.red,
|
||||||
|
),
|
||||||
|
child: const Text('Yes'),
|
||||||
|
),
|
||||||
|
OutlinedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(false);
|
||||||
|
},
|
||||||
|
child: const Text('No'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)) ??
|
||||||
|
false;
|
||||||
|
if (removeAll) {
|
||||||
|
await CommentDraftStore.removeAllDrafts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: box.length + 1,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == box.length) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: removeAllDrafts,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
primary: Colors.red,
|
||||||
|
),
|
||||||
|
child: const Text('Remove all drafts'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _CommentDraftTile(CommentDraftStore.keyAt(index)!);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CommentDraftTile extends HookWidget {
|
||||||
|
final String databaseKey;
|
||||||
|
|
||||||
|
const _CommentDraftTile(this.databaseKey);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final body = useState<String?>(null);
|
||||||
|
useEffect(() {
|
||||||
|
CommentDraftStore.loadDraft(databaseKey)
|
||||||
|
.then((value) => body.value = value);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
key: ValueKey(key),
|
||||||
|
title: body.value == null
|
||||||
|
? const CircularProgressIndicator.adaptive()
|
||||||
|
: Text(body.value!),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
onPressed: () {
|
||||||
|
CommentDraftStore.removeDraft(databaseKey);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
subtitle: Text(databaseKey),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostsTab extends StatelessWidget {
|
||||||
|
const _PostsTab();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const Center(child: Text('TBD'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import '../manage_account.dart';
|
||||||
import 'add_account_page.dart';
|
import 'add_account_page.dart';
|
||||||
import 'add_instance_page.dart';
|
import 'add_instance_page.dart';
|
||||||
import 'blocks/blocks.dart';
|
import 'blocks/blocks.dart';
|
||||||
|
import 'drafts_page.dart';
|
||||||
|
|
||||||
/// Page with a list of different settings sections
|
/// Page with a list of different settings sections
|
||||||
class SettingsPage extends HookWidget {
|
class SettingsPage extends HookWidget {
|
||||||
|
@ -60,6 +61,13 @@ class SettingsPage extends HookWidget {
|
||||||
goTo(context, (_) => const AppearanceConfigPage());
|
goTo(context, (_) => const AppearanceConfigPage());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.drive_file_rename_outline_outlined),
|
||||||
|
title: const Text('Drafts'),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(DraftsPage.route());
|
||||||
|
},
|
||||||
|
),
|
||||||
const AboutTile()
|
const AboutTile()
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,24 +1,37 @@
|
||||||
import 'package:hive/hive.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:hive_flutter/adapters.dart';
|
||||||
|
|
||||||
class CommentDraftStore {
|
class CommentDraftStore {
|
||||||
static const _boxKey = 'comment_drafts';
|
static const _boxKey = 'comment_drafts';
|
||||||
|
static late LazyBox<String> _box;
|
||||||
|
|
||||||
static Future<String?> loadDraft(String apId) async {
|
static Future<void> open() async {
|
||||||
final box = await Hive.openBox<String>(_boxKey);
|
_box = await Hive.openLazyBox<String>(_boxKey);
|
||||||
final text = box.get(apId);
|
|
||||||
await box.close();
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> saveDraft(String apId, String text) async {
|
static Future<void> close() async {
|
||||||
final box = await Hive.openBox<String>(_boxKey);
|
await _box.compact();
|
||||||
await box.put(apId, text);
|
await _box.close();
|
||||||
await box.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> removeDraft(String apId) async {
|
static Future<void> compact() async {
|
||||||
final box = await Hive.openBox<String>(_boxKey);
|
await _box.compact();
|
||||||
await box.delete(apId);
|
}
|
||||||
await box.close();
|
|
||||||
|
static String? keyAt(int index) => _box.keyAt(index);
|
||||||
|
|
||||||
|
static ValueListenable<LazyBox<String>> allDraftsListenable() =>
|
||||||
|
_box.listenable();
|
||||||
|
|
||||||
|
static Future<String?> loadDraft(String apId) => _box.get(apId);
|
||||||
|
|
||||||
|
static Future<void> saveDraft(String apId, String text) =>
|
||||||
|
_box.put(apId, text);
|
||||||
|
|
||||||
|
static Future<void> removeDraft(String apId) => _box.delete(apId);
|
||||||
|
|
||||||
|
static Future<void> removeAllDrafts() async {
|
||||||
|
await _box.deleteFromDisk();
|
||||||
|
await open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,10 +116,15 @@ class WriteComment extends HookWidget {
|
||||||
leading: CloseButton(
|
leading: CloseButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// save draft before closing
|
// save draft before closing
|
||||||
if (!_isEdit &&
|
if (!_isEdit) {
|
||||||
editorController.textEditingController.text.trim().isNotEmpty) {
|
if (editorController.textEditingController.text
|
||||||
await CommentDraftStore.saveDraft(comment?.apId ?? post.apId,
|
.trim()
|
||||||
editorController.textEditingController.text);
|
.isNotEmpty) {
|
||||||
|
await CommentDraftStore.saveDraft(comment?.apId ?? post.apId,
|
||||||
|
editorController.textEditingController.text);
|
||||||
|
} else {
|
||||||
|
await CommentDraftStore.removeDraft(comment?.apId ?? post.apId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue