✨ Reworked post draft
This commit is contained in:
@@ -471,6 +471,8 @@
|
|||||||
"close": "Close",
|
"close": "Close",
|
||||||
"drafts": "Drafts",
|
"drafts": "Drafts",
|
||||||
"noDrafts": "No drafts yet",
|
"noDrafts": "No drafts yet",
|
||||||
|
"searchDrafts": "Search drafts...",
|
||||||
|
"noSearchResults": "No search results",
|
||||||
"articleDrafts": "Article drafts",
|
"articleDrafts": "Article drafts",
|
||||||
"postDrafts": "Post drafts",
|
"postDrafts": "Post drafts",
|
||||||
"saveDraft": "Save draft",
|
"saveDraft": "Save draft",
|
||||||
|
@@ -2,8 +2,15 @@ import 'package:drift/drift.dart';
|
|||||||
|
|
||||||
class PostDrafts extends Table {
|
class PostDrafts extends Table {
|
||||||
TextColumn get id => text()();
|
TextColumn get id => text()();
|
||||||
TextColumn get post => text()(); // Store SnPost model as JSON string
|
// Searchable fields stored separately for performance
|
||||||
|
TextColumn get title => text().nullable()();
|
||||||
|
TextColumn get description => text().nullable()();
|
||||||
|
TextColumn get content => text().nullable()();
|
||||||
|
IntColumn get visibility => integer().withDefault(const Constant(0))();
|
||||||
|
IntColumn get type => integer().withDefault(const Constant(0))();
|
||||||
DateTimeColumn get lastModified => dateTime()();
|
DateTimeColumn get lastModified => dateTime()();
|
||||||
|
// Full post data stored as JSON for complete restoration
|
||||||
|
TextColumn get postData => text()();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Set<Column> get primaryKey => {id};
|
Set<Column> get primaryKey => {id};
|
||||||
|
@@ -12,7 +12,7 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
AppDatabase(super.e);
|
AppDatabase(super.e);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 4;
|
int get schemaVersion => 6;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration => MigrationStrategy(
|
MigrationStrategy get migration => MigrationStrategy(
|
||||||
@@ -28,9 +28,67 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
// Drop old draft tables if they exist
|
// Drop old draft tables if they exist
|
||||||
await m.createTable(postDrafts);
|
await m.createTable(postDrafts);
|
||||||
}
|
}
|
||||||
|
if (from < 6) {
|
||||||
|
// Migrate from old schema to new schema with separate searchable fields
|
||||||
|
await _migrateToVersion6(m);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Future<void> _migrateToVersion6(Migrator m) async {
|
||||||
|
// Rename existing table to old if it exists
|
||||||
|
try {
|
||||||
|
await customStatement(
|
||||||
|
'ALTER TABLE post_drafts RENAME TO post_drafts_old',
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// Table might not exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop the table
|
||||||
|
await customStatement('DROP TABLE IF EXISTS post_drafts');
|
||||||
|
|
||||||
|
// Create new table
|
||||||
|
await m.createTable(postDrafts);
|
||||||
|
|
||||||
|
// Migrate existing data if any
|
||||||
|
try {
|
||||||
|
final oldDrafts =
|
||||||
|
await customSelect(
|
||||||
|
'SELECT id, post, lastModified FROM post_drafts_old',
|
||||||
|
readsFrom: {postDrafts},
|
||||||
|
).get();
|
||||||
|
|
||||||
|
for (final row in oldDrafts) {
|
||||||
|
final postJson = row.read<String>('post');
|
||||||
|
final id = row.read<String>('id');
|
||||||
|
final lastModified = row.read<DateTime>('lastModified');
|
||||||
|
|
||||||
|
if (postJson.isNotEmpty) {
|
||||||
|
final post = SnPost.fromJson(jsonDecode(postJson));
|
||||||
|
await into(postDrafts).insert(
|
||||||
|
PostDraftsCompanion(
|
||||||
|
id: Value(id),
|
||||||
|
title: Value(post.title),
|
||||||
|
description: Value(post.description),
|
||||||
|
content: Value(post.content),
|
||||||
|
visibility: Value(post.visibility),
|
||||||
|
type: Value(post.type),
|
||||||
|
lastModified: Value(lastModified),
|
||||||
|
postData: Value(postJson),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop old table
|
||||||
|
await customStatement('DROP TABLE IF EXISTS post_drafts_old');
|
||||||
|
} catch (e) {
|
||||||
|
// If migration fails, just recreate the table
|
||||||
|
await m.createTable(postDrafts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Methods for chat messages
|
// Methods for chat messages
|
||||||
Future<List<ChatMessage>> getMessagesForRoom(
|
Future<List<ChatMessage>> getMessagesForRoom(
|
||||||
String roomId, {
|
String roomId, {
|
||||||
@@ -69,7 +127,9 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<int> getTotalMessagesForRoom(String roomId) {
|
Future<int> getTotalMessagesForRoom(String roomId) {
|
||||||
return (select(chatMessages)..where((m) => m.roomId.equals(roomId))).get().then((list) => list.length);
|
return (select(
|
||||||
|
chatMessages,
|
||||||
|
)..where((m) => m.roomId.equals(roomId))).get().then((list) => list.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<LocalChatMessage>> searchMessages(
|
Future<List<LocalChatMessage>> searchMessages(
|
||||||
@@ -85,10 +145,6 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
..where((m) => m.content.like('%${query.toLowerCase()}%'));
|
..where((m) => m.content.like('%${query.toLowerCase()}%'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final messages =
|
final messages =
|
||||||
await (selectStatement
|
await (selectStatement
|
||||||
..orderBy([(m) => OrderingTerm.desc(m.createdAt)]))
|
..orderBy([(m) => OrderingTerm.desc(m.createdAt)]))
|
||||||
@@ -129,10 +185,31 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
Future<List<SnPost>> getAllPostDrafts() async {
|
Future<List<SnPost>> getAllPostDrafts() async {
|
||||||
final drafts = await select(postDrafts).get();
|
final drafts = await select(postDrafts).get();
|
||||||
return drafts
|
return drafts
|
||||||
.map((draft) => SnPost.fromJson(jsonDecode(draft.post)))
|
.map((draft) => SnPost.fromJson(jsonDecode(draft.postData)))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<PostDraft>> getAllPostDraftRecords() async {
|
||||||
|
return await select(postDrafts).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<PostDraft>> searchPostDrafts(String query) async {
|
||||||
|
if (query.isEmpty) {
|
||||||
|
return await select(postDrafts).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
final searchTerm = '%${query.toLowerCase()}%';
|
||||||
|
return await (select(postDrafts)
|
||||||
|
..where(
|
||||||
|
(draft) =>
|
||||||
|
draft.title.like(searchTerm) |
|
||||||
|
draft.description.like(searchTerm) |
|
||||||
|
draft.content.like(searchTerm),
|
||||||
|
)
|
||||||
|
..orderBy([(draft) => OrderingTerm.desc(draft.lastModified)]))
|
||||||
|
.get();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> addPostDraft(PostDraftsCompanion entry) async {
|
Future<void> addPostDraft(PostDraftsCompanion entry) async {
|
||||||
await into(postDrafts).insert(entry, mode: InsertMode.replace);
|
await into(postDrafts).insert(entry, mode: InsertMode.replace);
|
||||||
}
|
}
|
||||||
@@ -144,4 +221,9 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
Future<void> clearAllPostDrafts() async {
|
Future<void> clearAllPostDrafts() async {
|
||||||
await delete(postDrafts).go();
|
await delete(postDrafts).go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<PostDraft?> getPostDraftById(String id) async {
|
||||||
|
return await (select(postDrafts)
|
||||||
|
..where((tbl) => tbl.id.equals(id))).getSingleOrNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -584,14 +584,58 @@ class $PostDraftsTable extends PostDrafts
|
|||||||
type: DriftSqlType.string,
|
type: DriftSqlType.string,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: true,
|
||||||
);
|
);
|
||||||
static const VerificationMeta _postMeta = const VerificationMeta('post');
|
static const VerificationMeta _titleMeta = const VerificationMeta('title');
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumn<String> post = GeneratedColumn<String>(
|
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||||
'post',
|
'title',
|
||||||
|
aliasedName,
|
||||||
|
true,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
);
|
||||||
|
static const VerificationMeta _descriptionMeta = const VerificationMeta(
|
||||||
|
'description',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> description = GeneratedColumn<String>(
|
||||||
|
'description',
|
||||||
|
aliasedName,
|
||||||
|
true,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
);
|
||||||
|
static const VerificationMeta _contentMeta = const VerificationMeta(
|
||||||
|
'content',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> content = GeneratedColumn<String>(
|
||||||
|
'content',
|
||||||
|
aliasedName,
|
||||||
|
true,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
);
|
||||||
|
static const VerificationMeta _visibilityMeta = const VerificationMeta(
|
||||||
|
'visibility',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<int> visibility = GeneratedColumn<int>(
|
||||||
|
'visibility',
|
||||||
aliasedName,
|
aliasedName,
|
||||||
false,
|
false,
|
||||||
type: DriftSqlType.string,
|
type: DriftSqlType.int,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: const Constant(0),
|
||||||
|
);
|
||||||
|
static const VerificationMeta _typeMeta = const VerificationMeta('type');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<int> type = GeneratedColumn<int>(
|
||||||
|
'type',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: DriftSqlType.int,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: const Constant(0),
|
||||||
);
|
);
|
||||||
static const VerificationMeta _lastModifiedMeta = const VerificationMeta(
|
static const VerificationMeta _lastModifiedMeta = const VerificationMeta(
|
||||||
'lastModified',
|
'lastModified',
|
||||||
@@ -604,8 +648,28 @@ class $PostDraftsTable extends PostDrafts
|
|||||||
type: DriftSqlType.dateTime,
|
type: DriftSqlType.dateTime,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: true,
|
||||||
);
|
);
|
||||||
|
static const VerificationMeta _postDataMeta = const VerificationMeta(
|
||||||
|
'postData',
|
||||||
|
);
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [id, post, lastModified];
|
late final GeneratedColumn<String> postData = GeneratedColumn<String>(
|
||||||
|
'post_data',
|
||||||
|
aliasedName,
|
||||||
|
false,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: true,
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
List<GeneratedColumn> get $columns => [
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
content,
|
||||||
|
visibility,
|
||||||
|
type,
|
||||||
|
lastModified,
|
||||||
|
postData,
|
||||||
|
];
|
||||||
@override
|
@override
|
||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@override
|
@override
|
||||||
@@ -623,13 +687,38 @@ class $PostDraftsTable extends PostDrafts
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_idMeta);
|
context.missing(_idMeta);
|
||||||
}
|
}
|
||||||
if (data.containsKey('post')) {
|
if (data.containsKey('title')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_postMeta,
|
_titleMeta,
|
||||||
post.isAcceptableOrUnknown(data['post']!, _postMeta),
|
title.isAcceptableOrUnknown(data['title']!, _titleMeta),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (data.containsKey('description')) {
|
||||||
|
context.handle(
|
||||||
|
_descriptionMeta,
|
||||||
|
description.isAcceptableOrUnknown(
|
||||||
|
data['description']!,
|
||||||
|
_descriptionMeta,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (data.containsKey('content')) {
|
||||||
|
context.handle(
|
||||||
|
_contentMeta,
|
||||||
|
content.isAcceptableOrUnknown(data['content']!, _contentMeta),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (data.containsKey('visibility')) {
|
||||||
|
context.handle(
|
||||||
|
_visibilityMeta,
|
||||||
|
visibility.isAcceptableOrUnknown(data['visibility']!, _visibilityMeta),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (data.containsKey('type')) {
|
||||||
|
context.handle(
|
||||||
|
_typeMeta,
|
||||||
|
type.isAcceptableOrUnknown(data['type']!, _typeMeta),
|
||||||
);
|
);
|
||||||
} else if (isInserting) {
|
|
||||||
context.missing(_postMeta);
|
|
||||||
}
|
}
|
||||||
if (data.containsKey('last_modified')) {
|
if (data.containsKey('last_modified')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
@@ -642,6 +731,14 @@ class $PostDraftsTable extends PostDrafts
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_lastModifiedMeta);
|
context.missing(_lastModifiedMeta);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('post_data')) {
|
||||||
|
context.handle(
|
||||||
|
_postDataMeta,
|
||||||
|
postData.isAcceptableOrUnknown(data['post_data']!, _postDataMeta),
|
||||||
|
);
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_postDataMeta);
|
||||||
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,16 +753,38 @@ class $PostDraftsTable extends PostDrafts
|
|||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}id'],
|
data['${effectivePrefix}id'],
|
||||||
)!,
|
)!,
|
||||||
post:
|
title: attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}title'],
|
||||||
|
),
|
||||||
|
description: attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}description'],
|
||||||
|
),
|
||||||
|
content: attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}content'],
|
||||||
|
),
|
||||||
|
visibility:
|
||||||
attachedDatabase.typeMapping.read(
|
attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.string,
|
DriftSqlType.int,
|
||||||
data['${effectivePrefix}post'],
|
data['${effectivePrefix}visibility'],
|
||||||
|
)!,
|
||||||
|
type:
|
||||||
|
attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.int,
|
||||||
|
data['${effectivePrefix}type'],
|
||||||
)!,
|
)!,
|
||||||
lastModified:
|
lastModified:
|
||||||
attachedDatabase.typeMapping.read(
|
attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.dateTime,
|
DriftSqlType.dateTime,
|
||||||
data['${effectivePrefix}last_modified'],
|
data['${effectivePrefix}last_modified'],
|
||||||
)!,
|
)!,
|
||||||
|
postData:
|
||||||
|
attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}post_data'],
|
||||||
|
)!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -677,27 +796,60 @@ class $PostDraftsTable extends PostDrafts
|
|||||||
|
|
||||||
class PostDraft extends DataClass implements Insertable<PostDraft> {
|
class PostDraft extends DataClass implements Insertable<PostDraft> {
|
||||||
final String id;
|
final String id;
|
||||||
final String post;
|
final String? title;
|
||||||
|
final String? description;
|
||||||
|
final String? content;
|
||||||
|
final int visibility;
|
||||||
|
final int type;
|
||||||
final DateTime lastModified;
|
final DateTime lastModified;
|
||||||
|
final String postData;
|
||||||
const PostDraft({
|
const PostDraft({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.post,
|
this.title,
|
||||||
|
this.description,
|
||||||
|
this.content,
|
||||||
|
required this.visibility,
|
||||||
|
required this.type,
|
||||||
required this.lastModified,
|
required this.lastModified,
|
||||||
|
required this.postData,
|
||||||
});
|
});
|
||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, Expression>{};
|
final map = <String, Expression>{};
|
||||||
map['id'] = Variable<String>(id);
|
map['id'] = Variable<String>(id);
|
||||||
map['post'] = Variable<String>(post);
|
if (!nullToAbsent || title != null) {
|
||||||
|
map['title'] = Variable<String>(title);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || description != null) {
|
||||||
|
map['description'] = Variable<String>(description);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || content != null) {
|
||||||
|
map['content'] = Variable<String>(content);
|
||||||
|
}
|
||||||
|
map['visibility'] = Variable<int>(visibility);
|
||||||
|
map['type'] = Variable<int>(type);
|
||||||
map['last_modified'] = Variable<DateTime>(lastModified);
|
map['last_modified'] = Variable<DateTime>(lastModified);
|
||||||
|
map['post_data'] = Variable<String>(postData);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
PostDraftsCompanion toCompanion(bool nullToAbsent) {
|
PostDraftsCompanion toCompanion(bool nullToAbsent) {
|
||||||
return PostDraftsCompanion(
|
return PostDraftsCompanion(
|
||||||
id: Value(id),
|
id: Value(id),
|
||||||
post: Value(post),
|
title:
|
||||||
|
title == null && nullToAbsent ? const Value.absent() : Value(title),
|
||||||
|
description:
|
||||||
|
description == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(description),
|
||||||
|
content:
|
||||||
|
content == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(content),
|
||||||
|
visibility: Value(visibility),
|
||||||
|
type: Value(type),
|
||||||
lastModified: Value(lastModified),
|
lastModified: Value(lastModified),
|
||||||
|
postData: Value(postData),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,8 +860,13 @@ class PostDraft extends DataClass implements Insertable<PostDraft> {
|
|||||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
return PostDraft(
|
return PostDraft(
|
||||||
id: serializer.fromJson<String>(json['id']),
|
id: serializer.fromJson<String>(json['id']),
|
||||||
post: serializer.fromJson<String>(json['post']),
|
title: serializer.fromJson<String?>(json['title']),
|
||||||
|
description: serializer.fromJson<String?>(json['description']),
|
||||||
|
content: serializer.fromJson<String?>(json['content']),
|
||||||
|
visibility: serializer.fromJson<int>(json['visibility']),
|
||||||
|
type: serializer.fromJson<int>(json['type']),
|
||||||
lastModified: serializer.fromJson<DateTime>(json['lastModified']),
|
lastModified: serializer.fromJson<DateTime>(json['lastModified']),
|
||||||
|
postData: serializer.fromJson<String>(json['postData']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
@@ -717,25 +874,50 @@ class PostDraft extends DataClass implements Insertable<PostDraft> {
|
|||||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
return <String, dynamic>{
|
return <String, dynamic>{
|
||||||
'id': serializer.toJson<String>(id),
|
'id': serializer.toJson<String>(id),
|
||||||
'post': serializer.toJson<String>(post),
|
'title': serializer.toJson<String?>(title),
|
||||||
|
'description': serializer.toJson<String?>(description),
|
||||||
|
'content': serializer.toJson<String?>(content),
|
||||||
|
'visibility': serializer.toJson<int>(visibility),
|
||||||
|
'type': serializer.toJson<int>(type),
|
||||||
'lastModified': serializer.toJson<DateTime>(lastModified),
|
'lastModified': serializer.toJson<DateTime>(lastModified),
|
||||||
|
'postData': serializer.toJson<String>(postData),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
PostDraft copyWith({String? id, String? post, DateTime? lastModified}) =>
|
PostDraft copyWith({
|
||||||
PostDraft(
|
String? id,
|
||||||
id: id ?? this.id,
|
Value<String?> title = const Value.absent(),
|
||||||
post: post ?? this.post,
|
Value<String?> description = const Value.absent(),
|
||||||
lastModified: lastModified ?? this.lastModified,
|
Value<String?> content = const Value.absent(),
|
||||||
);
|
int? visibility,
|
||||||
|
int? type,
|
||||||
|
DateTime? lastModified,
|
||||||
|
String? postData,
|
||||||
|
}) => PostDraft(
|
||||||
|
id: id ?? this.id,
|
||||||
|
title: title.present ? title.value : this.title,
|
||||||
|
description: description.present ? description.value : this.description,
|
||||||
|
content: content.present ? content.value : this.content,
|
||||||
|
visibility: visibility ?? this.visibility,
|
||||||
|
type: type ?? this.type,
|
||||||
|
lastModified: lastModified ?? this.lastModified,
|
||||||
|
postData: postData ?? this.postData,
|
||||||
|
);
|
||||||
PostDraft copyWithCompanion(PostDraftsCompanion data) {
|
PostDraft copyWithCompanion(PostDraftsCompanion data) {
|
||||||
return PostDraft(
|
return PostDraft(
|
||||||
id: data.id.present ? data.id.value : this.id,
|
id: data.id.present ? data.id.value : this.id,
|
||||||
post: data.post.present ? data.post.value : this.post,
|
title: data.title.present ? data.title.value : this.title,
|
||||||
|
description:
|
||||||
|
data.description.present ? data.description.value : this.description,
|
||||||
|
content: data.content.present ? data.content.value : this.content,
|
||||||
|
visibility:
|
||||||
|
data.visibility.present ? data.visibility.value : this.visibility,
|
||||||
|
type: data.type.present ? data.type.value : this.type,
|
||||||
lastModified:
|
lastModified:
|
||||||
data.lastModified.present
|
data.lastModified.present
|
||||||
? data.lastModified.value
|
? data.lastModified.value
|
||||||
: this.lastModified,
|
: this.lastModified,
|
||||||
|
postData: data.postData.present ? data.postData.value : this.postData,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,66 +925,120 @@ class PostDraft extends DataClass implements Insertable<PostDraft> {
|
|||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('PostDraft(')
|
return (StringBuffer('PostDraft(')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
..write('post: $post, ')
|
..write('title: $title, ')
|
||||||
..write('lastModified: $lastModified')
|
..write('description: $description, ')
|
||||||
|
..write('content: $content, ')
|
||||||
|
..write('visibility: $visibility, ')
|
||||||
|
..write('type: $type, ')
|
||||||
|
..write('lastModified: $lastModified, ')
|
||||||
|
..write('postData: $postData')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(id, post, lastModified);
|
int get hashCode => Object.hash(
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
content,
|
||||||
|
visibility,
|
||||||
|
type,
|
||||||
|
lastModified,
|
||||||
|
postData,
|
||||||
|
);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
(other is PostDraft &&
|
(other is PostDraft &&
|
||||||
other.id == this.id &&
|
other.id == this.id &&
|
||||||
other.post == this.post &&
|
other.title == this.title &&
|
||||||
other.lastModified == this.lastModified);
|
other.description == this.description &&
|
||||||
|
other.content == this.content &&
|
||||||
|
other.visibility == this.visibility &&
|
||||||
|
other.type == this.type &&
|
||||||
|
other.lastModified == this.lastModified &&
|
||||||
|
other.postData == this.postData);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PostDraftsCompanion extends UpdateCompanion<PostDraft> {
|
class PostDraftsCompanion extends UpdateCompanion<PostDraft> {
|
||||||
final Value<String> id;
|
final Value<String> id;
|
||||||
final Value<String> post;
|
final Value<String?> title;
|
||||||
|
final Value<String?> description;
|
||||||
|
final Value<String?> content;
|
||||||
|
final Value<int> visibility;
|
||||||
|
final Value<int> type;
|
||||||
final Value<DateTime> lastModified;
|
final Value<DateTime> lastModified;
|
||||||
|
final Value<String> postData;
|
||||||
final Value<int> rowid;
|
final Value<int> rowid;
|
||||||
const PostDraftsCompanion({
|
const PostDraftsCompanion({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
this.post = const Value.absent(),
|
this.title = const Value.absent(),
|
||||||
|
this.description = const Value.absent(),
|
||||||
|
this.content = const Value.absent(),
|
||||||
|
this.visibility = const Value.absent(),
|
||||||
|
this.type = const Value.absent(),
|
||||||
this.lastModified = const Value.absent(),
|
this.lastModified = const Value.absent(),
|
||||||
|
this.postData = const Value.absent(),
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
});
|
});
|
||||||
PostDraftsCompanion.insert({
|
PostDraftsCompanion.insert({
|
||||||
required String id,
|
required String id,
|
||||||
required String post,
|
this.title = const Value.absent(),
|
||||||
|
this.description = const Value.absent(),
|
||||||
|
this.content = const Value.absent(),
|
||||||
|
this.visibility = const Value.absent(),
|
||||||
|
this.type = const Value.absent(),
|
||||||
required DateTime lastModified,
|
required DateTime lastModified,
|
||||||
|
required String postData,
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
}) : id = Value(id),
|
}) : id = Value(id),
|
||||||
post = Value(post),
|
lastModified = Value(lastModified),
|
||||||
lastModified = Value(lastModified);
|
postData = Value(postData);
|
||||||
static Insertable<PostDraft> custom({
|
static Insertable<PostDraft> custom({
|
||||||
Expression<String>? id,
|
Expression<String>? id,
|
||||||
Expression<String>? post,
|
Expression<String>? title,
|
||||||
|
Expression<String>? description,
|
||||||
|
Expression<String>? content,
|
||||||
|
Expression<int>? visibility,
|
||||||
|
Expression<int>? type,
|
||||||
Expression<DateTime>? lastModified,
|
Expression<DateTime>? lastModified,
|
||||||
|
Expression<String>? postData,
|
||||||
Expression<int>? rowid,
|
Expression<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return RawValuesInsertable({
|
return RawValuesInsertable({
|
||||||
if (id != null) 'id': id,
|
if (id != null) 'id': id,
|
||||||
if (post != null) 'post': post,
|
if (title != null) 'title': title,
|
||||||
|
if (description != null) 'description': description,
|
||||||
|
if (content != null) 'content': content,
|
||||||
|
if (visibility != null) 'visibility': visibility,
|
||||||
|
if (type != null) 'type': type,
|
||||||
if (lastModified != null) 'last_modified': lastModified,
|
if (lastModified != null) 'last_modified': lastModified,
|
||||||
|
if (postData != null) 'post_data': postData,
|
||||||
if (rowid != null) 'rowid': rowid,
|
if (rowid != null) 'rowid': rowid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PostDraftsCompanion copyWith({
|
PostDraftsCompanion copyWith({
|
||||||
Value<String>? id,
|
Value<String>? id,
|
||||||
Value<String>? post,
|
Value<String?>? title,
|
||||||
|
Value<String?>? description,
|
||||||
|
Value<String?>? content,
|
||||||
|
Value<int>? visibility,
|
||||||
|
Value<int>? type,
|
||||||
Value<DateTime>? lastModified,
|
Value<DateTime>? lastModified,
|
||||||
|
Value<String>? postData,
|
||||||
Value<int>? rowid,
|
Value<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return PostDraftsCompanion(
|
return PostDraftsCompanion(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
post: post ?? this.post,
|
title: title ?? this.title,
|
||||||
|
description: description ?? this.description,
|
||||||
|
content: content ?? this.content,
|
||||||
|
visibility: visibility ?? this.visibility,
|
||||||
|
type: type ?? this.type,
|
||||||
lastModified: lastModified ?? this.lastModified,
|
lastModified: lastModified ?? this.lastModified,
|
||||||
|
postData: postData ?? this.postData,
|
||||||
rowid: rowid ?? this.rowid,
|
rowid: rowid ?? this.rowid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -813,12 +1049,27 @@ class PostDraftsCompanion extends UpdateCompanion<PostDraft> {
|
|||||||
if (id.present) {
|
if (id.present) {
|
||||||
map['id'] = Variable<String>(id.value);
|
map['id'] = Variable<String>(id.value);
|
||||||
}
|
}
|
||||||
if (post.present) {
|
if (title.present) {
|
||||||
map['post'] = Variable<String>(post.value);
|
map['title'] = Variable<String>(title.value);
|
||||||
|
}
|
||||||
|
if (description.present) {
|
||||||
|
map['description'] = Variable<String>(description.value);
|
||||||
|
}
|
||||||
|
if (content.present) {
|
||||||
|
map['content'] = Variable<String>(content.value);
|
||||||
|
}
|
||||||
|
if (visibility.present) {
|
||||||
|
map['visibility'] = Variable<int>(visibility.value);
|
||||||
|
}
|
||||||
|
if (type.present) {
|
||||||
|
map['type'] = Variable<int>(type.value);
|
||||||
}
|
}
|
||||||
if (lastModified.present) {
|
if (lastModified.present) {
|
||||||
map['last_modified'] = Variable<DateTime>(lastModified.value);
|
map['last_modified'] = Variable<DateTime>(lastModified.value);
|
||||||
}
|
}
|
||||||
|
if (postData.present) {
|
||||||
|
map['post_data'] = Variable<String>(postData.value);
|
||||||
|
}
|
||||||
if (rowid.present) {
|
if (rowid.present) {
|
||||||
map['rowid'] = Variable<int>(rowid.value);
|
map['rowid'] = Variable<int>(rowid.value);
|
||||||
}
|
}
|
||||||
@@ -829,8 +1080,13 @@ class PostDraftsCompanion extends UpdateCompanion<PostDraft> {
|
|||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('PostDraftsCompanion(')
|
return (StringBuffer('PostDraftsCompanion(')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
..write('post: $post, ')
|
..write('title: $title, ')
|
||||||
|
..write('description: $description, ')
|
||||||
|
..write('content: $content, ')
|
||||||
|
..write('visibility: $visibility, ')
|
||||||
|
..write('type: $type, ')
|
||||||
..write('lastModified: $lastModified, ')
|
..write('lastModified: $lastModified, ')
|
||||||
|
..write('postData: $postData, ')
|
||||||
..write('rowid: $rowid')
|
..write('rowid: $rowid')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
@@ -1140,15 +1396,25 @@ typedef $$ChatMessagesTableProcessedTableManager =
|
|||||||
typedef $$PostDraftsTableCreateCompanionBuilder =
|
typedef $$PostDraftsTableCreateCompanionBuilder =
|
||||||
PostDraftsCompanion Function({
|
PostDraftsCompanion Function({
|
||||||
required String id,
|
required String id,
|
||||||
required String post,
|
Value<String?> title,
|
||||||
|
Value<String?> description,
|
||||||
|
Value<String?> content,
|
||||||
|
Value<int> visibility,
|
||||||
|
Value<int> type,
|
||||||
required DateTime lastModified,
|
required DateTime lastModified,
|
||||||
|
required String postData,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
typedef $$PostDraftsTableUpdateCompanionBuilder =
|
typedef $$PostDraftsTableUpdateCompanionBuilder =
|
||||||
PostDraftsCompanion Function({
|
PostDraftsCompanion Function({
|
||||||
Value<String> id,
|
Value<String> id,
|
||||||
Value<String> post,
|
Value<String?> title,
|
||||||
|
Value<String?> description,
|
||||||
|
Value<String?> content,
|
||||||
|
Value<int> visibility,
|
||||||
|
Value<int> type,
|
||||||
Value<DateTime> lastModified,
|
Value<DateTime> lastModified,
|
||||||
|
Value<String> postData,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1166,8 +1432,28 @@ class $$PostDraftsTableFilterComposer
|
|||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
ColumnFilters<String> get post => $composableBuilder(
|
ColumnFilters<String> get title => $composableBuilder(
|
||||||
column: $table.post,
|
column: $table.title,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnFilters<String> get description => $composableBuilder(
|
||||||
|
column: $table.description,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnFilters<String> get content => $composableBuilder(
|
||||||
|
column: $table.content,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnFilters<int> get visibility => $composableBuilder(
|
||||||
|
column: $table.visibility,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnFilters<int> get type => $composableBuilder(
|
||||||
|
column: $table.type,
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1175,6 +1461,11 @@ class $$PostDraftsTableFilterComposer
|
|||||||
column: $table.lastModified,
|
column: $table.lastModified,
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnFilters<String> get postData => $composableBuilder(
|
||||||
|
column: $table.postData,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$PostDraftsTableOrderingComposer
|
class $$PostDraftsTableOrderingComposer
|
||||||
@@ -1191,8 +1482,28 @@ class $$PostDraftsTableOrderingComposer
|
|||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
ColumnOrderings<String> get post => $composableBuilder(
|
ColumnOrderings<String> get title => $composableBuilder(
|
||||||
column: $table.post,
|
column: $table.title,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<String> get description => $composableBuilder(
|
||||||
|
column: $table.description,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<String> get content => $composableBuilder(
|
||||||
|
column: $table.content,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<int> get visibility => $composableBuilder(
|
||||||
|
column: $table.visibility,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<int> get type => $composableBuilder(
|
||||||
|
column: $table.type,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1200,6 +1511,11 @@ class $$PostDraftsTableOrderingComposer
|
|||||||
column: $table.lastModified,
|
column: $table.lastModified,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<String> get postData => $composableBuilder(
|
||||||
|
column: $table.postData,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$PostDraftsTableAnnotationComposer
|
class $$PostDraftsTableAnnotationComposer
|
||||||
@@ -1214,13 +1530,32 @@ class $$PostDraftsTableAnnotationComposer
|
|||||||
GeneratedColumn<String> get id =>
|
GeneratedColumn<String> get id =>
|
||||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<String> get post =>
|
GeneratedColumn<String> get title =>
|
||||||
$composableBuilder(column: $table.post, builder: (column) => column);
|
$composableBuilder(column: $table.title, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumn<String> get description => $composableBuilder(
|
||||||
|
column: $table.description,
|
||||||
|
builder: (column) => column,
|
||||||
|
);
|
||||||
|
|
||||||
|
GeneratedColumn<String> get content =>
|
||||||
|
$composableBuilder(column: $table.content, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumn<int> get visibility => $composableBuilder(
|
||||||
|
column: $table.visibility,
|
||||||
|
builder: (column) => column,
|
||||||
|
);
|
||||||
|
|
||||||
|
GeneratedColumn<int> get type =>
|
||||||
|
$composableBuilder(column: $table.type, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<DateTime> get lastModified => $composableBuilder(
|
GeneratedColumn<DateTime> get lastModified => $composableBuilder(
|
||||||
column: $table.lastModified,
|
column: $table.lastModified,
|
||||||
builder: (column) => column,
|
builder: (column) => column,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GeneratedColumn<String> get postData =>
|
||||||
|
$composableBuilder(column: $table.postData, builder: (column) => column);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$PostDraftsTableTableManager
|
class $$PostDraftsTableTableManager
|
||||||
@@ -1255,25 +1590,45 @@ class $$PostDraftsTableTableManager
|
|||||||
updateCompanionCallback:
|
updateCompanionCallback:
|
||||||
({
|
({
|
||||||
Value<String> id = const Value.absent(),
|
Value<String> id = const Value.absent(),
|
||||||
Value<String> post = const Value.absent(),
|
Value<String?> title = const Value.absent(),
|
||||||
|
Value<String?> description = const Value.absent(),
|
||||||
|
Value<String?> content = const Value.absent(),
|
||||||
|
Value<int> visibility = const Value.absent(),
|
||||||
|
Value<int> type = const Value.absent(),
|
||||||
Value<DateTime> lastModified = const Value.absent(),
|
Value<DateTime> lastModified = const Value.absent(),
|
||||||
|
Value<String> postData = const Value.absent(),
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => PostDraftsCompanion(
|
}) => PostDraftsCompanion(
|
||||||
id: id,
|
id: id,
|
||||||
post: post,
|
title: title,
|
||||||
|
description: description,
|
||||||
|
content: content,
|
||||||
|
visibility: visibility,
|
||||||
|
type: type,
|
||||||
lastModified: lastModified,
|
lastModified: lastModified,
|
||||||
|
postData: postData,
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
createCompanionCallback:
|
createCompanionCallback:
|
||||||
({
|
({
|
||||||
required String id,
|
required String id,
|
||||||
required String post,
|
Value<String?> title = const Value.absent(),
|
||||||
|
Value<String?> description = const Value.absent(),
|
||||||
|
Value<String?> content = const Value.absent(),
|
||||||
|
Value<int> visibility = const Value.absent(),
|
||||||
|
Value<int> type = const Value.absent(),
|
||||||
required DateTime lastModified,
|
required DateTime lastModified,
|
||||||
|
required String postData,
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => PostDraftsCompanion.insert(
|
}) => PostDraftsCompanion.insert(
|
||||||
id: id,
|
id: id,
|
||||||
post: post,
|
title: title,
|
||||||
|
description: description,
|
||||||
|
content: content,
|
||||||
|
visibility: visibility,
|
||||||
|
type: type,
|
||||||
lastModified: lastModified,
|
lastModified: lastModified,
|
||||||
|
postData: postData,
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
withReferenceMapper:
|
withReferenceMapper:
|
||||||
|
@@ -128,14 +128,6 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
return null;
|
return null;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Auto-save cleanup
|
|
||||||
useEffect(() {
|
|
||||||
return () {
|
|
||||||
state.stopAutoSave();
|
|
||||||
ComposeLogic.dispose(state);
|
|
||||||
};
|
|
||||||
}, [state]);
|
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
void showSettingsSheet() {
|
void showSettingsSheet() {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
@@ -182,6 +174,12 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
MarkdownTextContent(
|
MarkdownTextContent(
|
||||||
content: contentValue.text,
|
content: contentValue.text,
|
||||||
textStyle: theme.textTheme.bodyMedium,
|
textStyle: theme.textTheme.bodyMedium,
|
||||||
|
attachments:
|
||||||
|
state.attachments.value
|
||||||
|
.where((e) => e.isOnCloud)
|
||||||
|
.map((e) => e.data)
|
||||||
|
.cast<SnCloudFile>()
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -268,7 +266,7 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
child: KeyboardListener(
|
child: KeyboardListener(
|
||||||
focusNode: FocusNode(),
|
focusNode: FocusNode(),
|
||||||
onKeyEvent:
|
onKeyEvent:
|
||||||
(event) => _handleKeyPress(
|
(event) => ComposeLogic.handleKeyPress(
|
||||||
event,
|
event,
|
||||||
state,
|
state,
|
||||||
ref,
|
ref,
|
||||||
@@ -511,38 +509,4 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to handle keyboard shortcuts
|
|
||||||
void _handleKeyPress(
|
|
||||||
KeyEvent event,
|
|
||||||
ComposeState state,
|
|
||||||
WidgetRef ref,
|
|
||||||
BuildContext context, {
|
|
||||||
SnPost? originalPost,
|
|
||||||
}) {
|
|
||||||
if (event is! RawKeyDownEvent) return;
|
|
||||||
|
|
||||||
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
|
|
||||||
final isSave = event.logicalKey == LogicalKeyboardKey.keyS;
|
|
||||||
final isModifierPressed =
|
|
||||||
HardwareKeyboard.instance.isMetaPressed ||
|
|
||||||
HardwareKeyboard.instance.isControlPressed;
|
|
||||||
final isSubmit = event.logicalKey == LogicalKeyboardKey.enter;
|
|
||||||
|
|
||||||
if (isPaste && isModifierPressed) {
|
|
||||||
ComposeLogic.handlePaste(state);
|
|
||||||
} else if (isSave && isModifierPressed) {
|
|
||||||
ComposeLogic.saveDraft(ref, state);
|
|
||||||
ComposeLogic.saveDraft(ref, state);
|
|
||||||
} else if (isSubmit && isModifierPressed && !state.submitting.value) {
|
|
||||||
ComposeLogic.performAction(
|
|
||||||
ref,
|
|
||||||
state,
|
|
||||||
context,
|
|
||||||
originalPost: originalPost,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to save article draft
|
|
||||||
}
|
}
|
||||||
|
@@ -39,8 +39,13 @@ class ComposeStorageNotifier extends _$ComposeStorageNotifier {
|
|||||||
await database.addPostDraft(
|
await database.addPostDraft(
|
||||||
PostDraftsCompanion(
|
PostDraftsCompanion(
|
||||||
id: Value(updatedDraft.id),
|
id: Value(updatedDraft.id),
|
||||||
post: Value(jsonEncode(updatedDraft.toJson())),
|
title: Value(updatedDraft.title),
|
||||||
|
description: Value(updatedDraft.description),
|
||||||
|
content: Value(updatedDraft.content),
|
||||||
|
visibility: Value(updatedDraft.visibility),
|
||||||
|
type: Value(updatedDraft.type),
|
||||||
lastModified: Value(updatedDraft.updatedAt ?? DateTime.now()),
|
lastModified: Value(updatedDraft.updatedAt ?? DateTime.now()),
|
||||||
|
postData: Value(jsonEncode(updatedDraft.toJson())),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@@ -7,7 +7,7 @@ part of 'compose_storage_db.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$composeStorageNotifierHash() =>
|
String _$composeStorageNotifierHash() =>
|
||||||
r'4ab4dce85d0a961f096dc3b11505f8f0964dee9d';
|
r'8baf17aa06b6f69641c20645ba8a3dfe01c97f8c';
|
||||||
|
|
||||||
/// See also [ComposeStorageNotifier].
|
/// See also [ComposeStorageNotifier].
|
||||||
@ProviderFor(ComposeStorageNotifier)
|
@ProviderFor(ComposeStorageNotifier)
|
||||||
|
@@ -173,10 +173,6 @@ class ComposeLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (state._autoSaveTimer == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload any local attachments first
|
// Upload any local attachments first
|
||||||
final baseUrl = ref.watch(serverUrlProvider);
|
final baseUrl = ref.watch(serverUrlProvider);
|
||||||
final token = await getToken(ref.watch(tokenProvider));
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
@@ -284,10 +280,6 @@ class ComposeLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (state._autoSaveTimer == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final draft = SnPost(
|
final draft = SnPost(
|
||||||
id: state.draftId,
|
id: state.draftId,
|
||||||
title: state.titleController.text,
|
title: state.titleController.text,
|
||||||
|
@@ -34,7 +34,7 @@ class ComposeToolbar extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void saveDraft() {
|
void saveDraft() {
|
||||||
ComposeLogic.saveDraft(ref, state);
|
ComposeLogic.saveDraftManually(ref, state, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pickPoll() {
|
void pickPoll() {
|
||||||
|
@@ -16,138 +16,145 @@ class DraftManagerSheet extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final colorScheme = theme.colorScheme;
|
final colorScheme = theme.colorScheme;
|
||||||
final isLoading = useState(true);
|
final searchController = useTextEditingController();
|
||||||
|
final searchQuery = useState('');
|
||||||
|
|
||||||
final drafts = ref.watch(composeStorageNotifierProvider);
|
final drafts = ref.watch(composeStorageNotifierProvider);
|
||||||
|
|
||||||
// Track loading state based on drafts being loaded
|
// Search functionality
|
||||||
useEffect(() {
|
final filteredDrafts = useMemoized(() {
|
||||||
// Set loading to false after drafts are loaded
|
if (searchQuery.value.isEmpty) {
|
||||||
// We consider drafts loaded when the provider has been initialized
|
return drafts.values.toList()
|
||||||
Future.microtask(() {
|
..sort((a, b) => b.updatedAt!.compareTo(a.updatedAt!));
|
||||||
if (isLoading.value) {
|
}
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}, [drafts]);
|
|
||||||
|
|
||||||
final sortedDrafts = useMemoized(
|
final query = searchQuery.value.toLowerCase();
|
||||||
() {
|
return drafts.values.where((draft) {
|
||||||
final draftList = drafts.values.toList();
|
return (draft.title?.toLowerCase().contains(query) ?? false) ||
|
||||||
draftList.sort((a, b) => b.updatedAt!.compareTo(a.updatedAt!));
|
(draft.description?.toLowerCase().contains(query) ?? false) ||
|
||||||
return draftList;
|
(draft.content?.toLowerCase().contains(query) ?? false);
|
||||||
},
|
}).toList()
|
||||||
[
|
..sort((a, b) => b.updatedAt!.compareTo(a.updatedAt!));
|
||||||
drafts.length,
|
}, [drafts, searchQuery.value]);
|
||||||
drafts.values.map((e) => e.updatedAt!.millisecondsSinceEpoch).join(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
return SheetScaffold(
|
return SheetScaffold(
|
||||||
titleText: 'drafts'.tr(),
|
titleText: 'drafts'.tr(),
|
||||||
child:
|
child: Column(
|
||||||
isLoading.value
|
children: [
|
||||||
? const Center(child: CircularProgressIndicator())
|
// Search bar
|
||||||
: Column(
|
Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(16),
|
||||||
if (sortedDrafts.isEmpty)
|
child: TextField(
|
||||||
Expanded(
|
controller: searchController,
|
||||||
child: Center(
|
decoration: InputDecoration(
|
||||||
child: Column(
|
hintText: 'searchDrafts'.tr(),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
prefixIcon: const Icon(Symbols.search),
|
||||||
children: [
|
border: OutlineInputBorder(
|
||||||
Icon(
|
borderRadius: BorderRadius.circular(12),
|
||||||
Symbols.draft,
|
),
|
||||||
size: 64,
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
color: colorScheme.onSurface.withOpacity(0.3),
|
horizontal: 16,
|
||||||
),
|
vertical: 12,
|
||||||
const Gap(16),
|
),
|
||||||
Text(
|
),
|
||||||
'noDrafts'.tr(),
|
onChanged: (value) => searchQuery.value = value,
|
||||||
style: theme.textTheme.bodyLarge?.copyWith(
|
),
|
||||||
color: colorScheme.onSurface.withOpacity(0.6),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else
|
|
||||||
Expanded(
|
|
||||||
child: ListView.builder(
|
|
||||||
itemCount: sortedDrafts.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final draft = sortedDrafts[index];
|
|
||||||
return _DraftItem(
|
|
||||||
draft: draft,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
onDraftSelected?.call(draft.id);
|
|
||||||
},
|
|
||||||
onDelete: () async {
|
|
||||||
await ref
|
|
||||||
.read(composeStorageNotifierProvider.notifier)
|
|
||||||
.deleteDraft(draft.id);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (sortedDrafts.isNotEmpty) ...[
|
|
||||||
const Divider(),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: OutlinedButton.icon(
|
|
||||||
onPressed: () async {
|
|
||||||
final confirmed = await showDialog<bool>(
|
|
||||||
context: context,
|
|
||||||
builder:
|
|
||||||
(context) => AlertDialog(
|
|
||||||
title: Text('clearAllDrafts'.tr()),
|
|
||||||
content: Text(
|
|
||||||
'clearAllDraftsConfirm'.tr(),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed:
|
|
||||||
() => Navigator.of(
|
|
||||||
context,
|
|
||||||
).pop(false),
|
|
||||||
child: Text('cancel'.tr()),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed:
|
|
||||||
() => Navigator.of(
|
|
||||||
context,
|
|
||||||
).pop(true),
|
|
||||||
child: Text('confirm'.tr()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (confirmed == true) {
|
// Drafts list
|
||||||
await ref
|
if (filteredDrafts.isEmpty)
|
||||||
.read(
|
Expanded(
|
||||||
composeStorageNotifierProvider.notifier,
|
child: Center(
|
||||||
)
|
child: Column(
|
||||||
.clearAllDrafts();
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
}
|
children: [
|
||||||
},
|
Icon(
|
||||||
icon: const Icon(Symbols.delete_sweep),
|
Symbols.draft,
|
||||||
label: Text('clearAll'.tr()),
|
size: 64,
|
||||||
),
|
color: colorScheme.onSurface.withOpacity(0.3),
|
||||||
),
|
),
|
||||||
],
|
const Gap(16),
|
||||||
|
Text(
|
||||||
|
searchQuery.value.isEmpty
|
||||||
|
? 'noDrafts'.tr()
|
||||||
|
: 'noSearchResults'.tr(),
|
||||||
|
style: theme.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: colorScheme.onSurface.withOpacity(0.6),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: filteredDrafts.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final draft = filteredDrafts[index];
|
||||||
|
return _DraftItem(
|
||||||
|
draft: draft,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
onDraftSelected?.call(draft.id);
|
||||||
|
},
|
||||||
|
onDelete: () async {
|
||||||
|
await ref
|
||||||
|
.read(composeStorageNotifierProvider.notifier)
|
||||||
|
.deleteDraft(draft.id);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Clear all button
|
||||||
|
if (filteredDrafts.isNotEmpty) ...[
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
final confirmed = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) => AlertDialog(
|
||||||
|
title: Text('clearAllDrafts'.tr()),
|
||||||
|
content: Text('clearAllDraftsConfirm'.tr()),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed:
|
||||||
|
() => Navigator.of(context).pop(false),
|
||||||
|
child: Text('cancel'.tr()),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed:
|
||||||
|
() => Navigator.of(context).pop(true),
|
||||||
|
child: Text('confirm'.tr()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirmed == true) {
|
||||||
|
await ref
|
||||||
|
.read(composeStorageNotifierProvider.notifier)
|
||||||
|
.clearAllDrafts();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Symbols.delete_sweep),
|
||||||
|
label: Text('clearAll'.tr()),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user