diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index ec4051e..1528157 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -410,6 +410,8 @@ "articleDrafts": "Article drafts", "postDrafts": "Post drafts", "saveDraft": "Save draft", + "draftSaved": "Draft saved", + "draftSaveFailed": "Failed to save draft", "clearAllDrafts": "Clear All Drafts", "clearAllDraftsConfirm": "Are you sure you want to delete all drafts? This action cannot be undone.", "clearAll": "Clear All", @@ -441,6 +443,7 @@ "contactMethodDelete": "Delete Contact", "contactMethodNew": "New Contact Method", "contactMethodContentEmpty": "Contact content cannot be empty", + "postContentEmpty": "Post content cannot be empty", "contactMethodVerificationSent": "Verification code sent to your contact method", "contactMethodVerificationNeeded": "The contact method is added, but not verified yet. You can verify it by tapping it and select verify.", "accountContactMethod": "Contact Methods", diff --git a/assets/i18n/zh-CN.json b/assets/i18n/zh-CN.json index 81a718e..a5d5266 100644 --- a/assets/i18n/zh-CN.json +++ b/assets/i18n/zh-CN.json @@ -319,5 +319,21 @@ "processingPayment": "处理付款中...", "pleaseWait": "请稍候", "paymentFailed": "付款失败,请重试。", - "paymentSuccess": "付款成功完成!" + "paymentSuccess": "付款成功完成!", + "drafts": "草稿", + "noDrafts": "暂无草稿", + "articleDrafts": "文章草稿", + "postDrafts": "帖子草稿", + "saveDraft": "保存草稿", + "draftSaved": "草稿已保存", + "draftSaveFailed": "保存草稿失败", + "clearAllDrafts": "清空所有草稿", + "clearAllDraftsConfirm": "确定要删除所有草稿吗?此操作无法撤销。", + "clearAll": "清空全部", + "untitled": "无标题", + "noContent": "无内容", + "justNow": "刚刚", + "minutesAgo": "{} 分钟前", + "hoursAgo": "{} 小时前", + "postContentEmpty": "帖子内容不能为空" } \ No newline at end of file diff --git a/assets/i18n/zh-TW.json b/assets/i18n/zh-TW.json index d74b8e4..3aea04e 100644 --- a/assets/i18n/zh-TW.json +++ b/assets/i18n/zh-TW.json @@ -334,5 +334,21 @@ "membershipFeatureAllNova": "所有新星功能", "membershipFeatureExclusiveContent": "獨家內容", "membershipFeatureVipSupport": "VIP 支援", - "membershipCurrentBadge": "目前" + "membershipCurrentBadge": "目前", + "drafts": "草稿", + "noDrafts": "暫無草稿", + "articleDrafts": "文章草稿", + "postDrafts": "貼文草稿", + "saveDraft": "儲存草稿", + "draftSaved": "草稿已儲存", + "draftSaveFailed": "儲存草稿失敗", + "clearAllDrafts": "清空所有草稿", + "clearAllDraftsConfirm": "確定要刪除所有草稿嗎?此操作無法復原。", + "clearAll": "清空全部", + "untitled": "無標題", + "noContent": "無內容", + "justNow": "剛剛", + "minutesAgo": "{} 分鐘前", + "hoursAgo": "{} 小時前", + "postContentEmpty": "貼文內容不能為空" } \ No newline at end of file diff --git a/lib/database/draft.dart b/lib/database/draft.dart index 95cfa52..e0fe29d 100644 --- a/lib/database/draft.dart +++ b/lib/database/draft.dart @@ -1,26 +1,10 @@ import 'package:drift/drift.dart'; -class ComposeDrafts extends Table { +class PostDrafts extends Table { TextColumn get id => text()(); - TextColumn get title => text().withDefault(const Constant(''))(); - TextColumn get description => text().withDefault(const Constant(''))(); - TextColumn get content => text().withDefault(const Constant(''))(); - TextColumn get attachmentIds => text().withDefault(const Constant('[]'))(); // JSON array as string - IntColumn get visibility => integer().withDefault(const Constant(0))(); // 0=public, 1=unlisted, 2=friends, 3=selected, 4=private + TextColumn get post => text()(); // Store SnPost model as JSON string DateTimeColumn get lastModified => dateTime()(); @override Set get primaryKey => {id}; } - -class ArticleDrafts extends Table { - TextColumn get id => text()(); - TextColumn get title => text().withDefault(const Constant(''))(); - TextColumn get description => text().withDefault(const Constant(''))(); - TextColumn get content => text().withDefault(const Constant(''))(); - IntColumn get visibility => integer().withDefault(const Constant(0))(); // 0=public, 1=unlisted, 2=friends, 3=private - DateTimeColumn get lastModified => dateTime()(); - - @override - Set get primaryKey => {id}; -} \ No newline at end of file diff --git a/lib/database/drift_db.dart b/lib/database/drift_db.dart index 3748f6c..5963525 100644 --- a/lib/database/drift_db.dart +++ b/lib/database/drift_db.dart @@ -2,16 +2,17 @@ import 'dart:convert'; import 'package:drift/drift.dart'; import 'package:island/database/message.dart'; import 'package:island/database/draft.dart'; +import 'package:island/models/post.dart'; part 'drift_db.g.dart'; // Define the database -@DriftDatabase(tables: [ChatMessages, ComposeDrafts, ArticleDrafts]) +@DriftDatabase(tables: [ChatMessages, PostDrafts]) class AppDatabase extends _$AppDatabase { AppDatabase(super.e); @override - int get schemaVersion => 3; + int get schemaVersion => 4; @override MigrationStrategy get migration => MigrationStrategy( @@ -23,10 +24,9 @@ class AppDatabase extends _$AppDatabase { // Add isRead column with default value false await m.addColumn(chatMessages, chatMessages.isRead); } - if (from < 3) { - // Add draft tables - await m.createTable(composeDrafts); - await m.createTable(articleDrafts); + if (from < 4) { + // Drop old draft tables if they exist + await m.createTable(postDrafts); } }, ); @@ -98,51 +98,23 @@ class AppDatabase extends _$AppDatabase { ); } - // Methods for compose drafts - Future> getAllComposeDrafts() { - return (select(composeDrafts) - ..orderBy([(d) => OrderingTerm.desc(d.lastModified)])) - .get(); + // Methods for post drafts + Future> getAllPostDrafts() async { + final drafts = await select(postDrafts).get(); + return drafts + .map((draft) => SnPost.fromJson(jsonDecode(draft.post))) + .toList(); } - Future getComposeDraft(String id) { - return (select(composeDrafts)..where((d) => d.id.equals(id))) - .getSingleOrNull(); + Future addPostDraft(PostDraftsCompanion entry) async { + await into(postDrafts).insert(entry, mode: InsertMode.replace); } - Future saveComposeDraft(ComposeDraftsCompanion draft) { - return into(composeDrafts).insert(draft, mode: InsertMode.insertOrReplace); + Future deletePostDraft(String id) async { + await (delete(postDrafts)..where((tbl) => tbl.id.equals(id))).go(); } - Future deleteComposeDraft(String id) { - return (delete(composeDrafts)..where((d) => d.id.equals(id))).go(); - } - - Future clearAllComposeDrafts() { - return delete(composeDrafts).go(); - } - - // Methods for article drafts - Future> getAllArticleDrafts() { - return (select(articleDrafts) - ..orderBy([(d) => OrderingTerm.desc(d.lastModified)])) - .get(); - } - - Future getArticleDraft(String id) { - return (select(articleDrafts)..where((d) => d.id.equals(id))) - .getSingleOrNull(); - } - - Future saveArticleDraft(ArticleDraftsCompanion draft) { - return into(articleDrafts).insert(draft, mode: InsertMode.insertOrReplace); - } - - Future deleteArticleDraft(String id) { - return (delete(articleDrafts)..where((d) => d.id.equals(id))).go(); - } - - Future clearAllArticleDrafts() { - return delete(articleDrafts).go(); + Future clearAllPostDrafts() async { + await delete(postDrafts).go(); } } diff --git a/lib/database/drift_db.g.dart b/lib/database/drift_db.g.dart index 4403baa..d26a862 100644 --- a/lib/database/drift_db.g.dart +++ b/lib/database/drift_db.g.dart @@ -569,12 +569,12 @@ class ChatMessagesCompanion extends UpdateCompanion { } } -class $ComposeDraftsTable extends ComposeDrafts - with TableInfo<$ComposeDraftsTable, ComposeDraft> { +class $PostDraftsTable extends PostDrafts + with TableInfo<$PostDraftsTable, PostDraft> { @override final GeneratedDatabase attachedDatabase; final String? _alias; - $ComposeDraftsTable(this.attachedDatabase, [this._alias]); + $PostDraftsTable(this.attachedDatabase, [this._alias]); static const VerificationMeta _idMeta = const VerificationMeta('id'); @override late final GeneratedColumn id = GeneratedColumn( @@ -584,63 +584,14 @@ class $ComposeDraftsTable extends ComposeDrafts type: DriftSqlType.string, requiredDuringInsert: true, ); - static const VerificationMeta _titleMeta = const VerificationMeta('title'); + static const VerificationMeta _postMeta = const VerificationMeta('post'); @override - late final GeneratedColumn title = GeneratedColumn( - 'title', + late final GeneratedColumn post = GeneratedColumn( + 'post', aliasedName, false, type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant(''), - ); - static const VerificationMeta _descriptionMeta = const VerificationMeta( - 'description', - ); - @override - late final GeneratedColumn description = GeneratedColumn( - 'description', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant(''), - ); - static const VerificationMeta _contentMeta = const VerificationMeta( - 'content', - ); - @override - late final GeneratedColumn content = GeneratedColumn( - 'content', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant(''), - ); - static const VerificationMeta _attachmentIdsMeta = const VerificationMeta( - 'attachmentIds', - ); - @override - late final GeneratedColumn attachmentIds = GeneratedColumn( - 'attachment_ids', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant('[]'), - ); - static const VerificationMeta _visibilityMeta = const VerificationMeta( - 'visibility', - ); - @override - late final GeneratedColumn visibility = GeneratedColumn( - 'visibility', - aliasedName, - false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const Constant(0), + requiredDuringInsert: true, ); static const VerificationMeta _lastModifiedMeta = const VerificationMeta( 'lastModified', @@ -654,23 +605,15 @@ class $ComposeDraftsTable extends ComposeDrafts requiredDuringInsert: true, ); @override - List get $columns => [ - id, - title, - description, - content, - attachmentIds, - visibility, - lastModified, - ]; + List get $columns => [id, post, lastModified]; @override String get aliasedName => _alias ?? actualTableName; @override String get actualTableName => $name; - static const String $name = 'compose_drafts'; + static const String $name = 'post_drafts'; @override VerificationContext validateIntegrity( - Insertable instance, { + Insertable instance, { bool isInserting = false, }) { final context = VerificationContext(); @@ -680,41 +623,13 @@ class $ComposeDraftsTable extends ComposeDrafts } else if (isInserting) { context.missing(_idMeta); } - if (data.containsKey('title')) { + if (data.containsKey('post')) { context.handle( - _titleMeta, - 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('attachment_ids')) { - context.handle( - _attachmentIdsMeta, - attachmentIds.isAcceptableOrUnknown( - data['attachment_ids']!, - _attachmentIdsMeta, - ), - ); - } - if (data.containsKey('visibility')) { - context.handle( - _visibilityMeta, - visibility.isAcceptableOrUnknown(data['visibility']!, _visibilityMeta), + _postMeta, + post.isAcceptableOrUnknown(data['post']!, _postMeta), ); + } else if (isInserting) { + context.missing(_postMeta); } if (data.containsKey('last_modified')) { context.handle( @@ -733,38 +648,18 @@ class $ComposeDraftsTable extends ComposeDrafts @override Set get $primaryKey => {id}; @override - ComposeDraft map(Map data, {String? tablePrefix}) { + PostDraft map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return ComposeDraft( + return PostDraft( id: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}id'], )!, - title: + post: 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'], - )!, - attachmentIds: - attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}attachment_ids'], - )!, - visibility: - attachedDatabase.typeMapping.read( - DriftSqlType.int, - data['${effectivePrefix}visibility'], + data['${effectivePrefix}post'], )!, lastModified: attachedDatabase.typeMapping.read( @@ -775,65 +670,45 @@ class $ComposeDraftsTable extends ComposeDrafts } @override - $ComposeDraftsTable createAlias(String alias) { - return $ComposeDraftsTable(attachedDatabase, alias); + $PostDraftsTable createAlias(String alias) { + return $PostDraftsTable(attachedDatabase, alias); } } -class ComposeDraft extends DataClass implements Insertable { +class PostDraft extends DataClass implements Insertable { final String id; - final String title; - final String description; - final String content; - final String attachmentIds; - final int visibility; + final String post; final DateTime lastModified; - const ComposeDraft({ + const PostDraft({ required this.id, - required this.title, - required this.description, - required this.content, - required this.attachmentIds, - required this.visibility, + required this.post, required this.lastModified, }); @override Map toColumns(bool nullToAbsent) { final map = {}; map['id'] = Variable(id); - map['title'] = Variable(title); - map['description'] = Variable(description); - map['content'] = Variable(content); - map['attachment_ids'] = Variable(attachmentIds); - map['visibility'] = Variable(visibility); + map['post'] = Variable(post); map['last_modified'] = Variable(lastModified); return map; } - ComposeDraftsCompanion toCompanion(bool nullToAbsent) { - return ComposeDraftsCompanion( + PostDraftsCompanion toCompanion(bool nullToAbsent) { + return PostDraftsCompanion( id: Value(id), - title: Value(title), - description: Value(description), - content: Value(content), - attachmentIds: Value(attachmentIds), - visibility: Value(visibility), + post: Value(post), lastModified: Value(lastModified), ); } - factory ComposeDraft.fromJson( + factory PostDraft.fromJson( Map json, { ValueSerializer? serializer, }) { serializer ??= driftRuntimeOptions.defaultSerializer; - return ComposeDraft( + return PostDraft( id: serializer.fromJson(json['id']), - title: serializer.fromJson(json['title']), - description: serializer.fromJson(json['description']), - content: serializer.fromJson(json['content']), - attachmentIds: serializer.fromJson(json['attachmentIds']), - visibility: serializer.fromJson(json['visibility']), + post: serializer.fromJson(json['post']), lastModified: serializer.fromJson(json['lastModified']), ); } @@ -842,45 +717,21 @@ class ComposeDraft extends DataClass implements Insertable { serializer ??= driftRuntimeOptions.defaultSerializer; return { 'id': serializer.toJson(id), - 'title': serializer.toJson(title), - 'description': serializer.toJson(description), - 'content': serializer.toJson(content), - 'attachmentIds': serializer.toJson(attachmentIds), - 'visibility': serializer.toJson(visibility), + 'post': serializer.toJson(post), 'lastModified': serializer.toJson(lastModified), }; } - ComposeDraft copyWith({ - String? id, - String? title, - String? description, - String? content, - String? attachmentIds, - int? visibility, - DateTime? lastModified, - }) => ComposeDraft( - id: id ?? this.id, - title: title ?? this.title, - description: description ?? this.description, - content: content ?? this.content, - attachmentIds: attachmentIds ?? this.attachmentIds, - visibility: visibility ?? this.visibility, - lastModified: lastModified ?? this.lastModified, - ); - ComposeDraft copyWithCompanion(ComposeDraftsCompanion data) { - return ComposeDraft( + PostDraft copyWith({String? id, String? post, DateTime? lastModified}) => + PostDraft( + id: id ?? this.id, + post: post ?? this.post, + lastModified: lastModified ?? this.lastModified, + ); + PostDraft copyWithCompanion(PostDraftsCompanion data) { + return PostDraft( id: data.id.present ? data.id.value : this.id, - 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, - attachmentIds: - data.attachmentIds.present - ? data.attachmentIds.value - : this.attachmentIds, - visibility: - data.visibility.present ? data.visibility.value : this.visibility, + post: data.post.present ? data.post.value : this.post, lastModified: data.lastModified.present ? data.lastModified.value @@ -890,110 +741,67 @@ class ComposeDraft extends DataClass implements Insertable { @override String toString() { - return (StringBuffer('ComposeDraft(') + return (StringBuffer('PostDraft(') ..write('id: $id, ') - ..write('title: $title, ') - ..write('description: $description, ') - ..write('content: $content, ') - ..write('attachmentIds: $attachmentIds, ') - ..write('visibility: $visibility, ') + ..write('post: $post, ') ..write('lastModified: $lastModified') ..write(')')) .toString(); } @override - int get hashCode => Object.hash( - id, - title, - description, - content, - attachmentIds, - visibility, - lastModified, - ); + int get hashCode => Object.hash(id, post, lastModified); @override bool operator ==(Object other) => identical(this, other) || - (other is ComposeDraft && + (other is PostDraft && other.id == this.id && - other.title == this.title && - other.description == this.description && - other.content == this.content && - other.attachmentIds == this.attachmentIds && - other.visibility == this.visibility && + other.post == this.post && other.lastModified == this.lastModified); } -class ComposeDraftsCompanion extends UpdateCompanion { +class PostDraftsCompanion extends UpdateCompanion { final Value id; - final Value title; - final Value description; - final Value content; - final Value attachmentIds; - final Value visibility; + final Value post; final Value lastModified; final Value rowid; - const ComposeDraftsCompanion({ + const PostDraftsCompanion({ this.id = const Value.absent(), - this.title = const Value.absent(), - this.description = const Value.absent(), - this.content = const Value.absent(), - this.attachmentIds = const Value.absent(), - this.visibility = const Value.absent(), + this.post = const Value.absent(), this.lastModified = const Value.absent(), this.rowid = const Value.absent(), }); - ComposeDraftsCompanion.insert({ + PostDraftsCompanion.insert({ required String id, - this.title = const Value.absent(), - this.description = const Value.absent(), - this.content = const Value.absent(), - this.attachmentIds = const Value.absent(), - this.visibility = const Value.absent(), + required String post, required DateTime lastModified, this.rowid = const Value.absent(), }) : id = Value(id), + post = Value(post), lastModified = Value(lastModified); - static Insertable custom({ + static Insertable custom({ Expression? id, - Expression? title, - Expression? description, - Expression? content, - Expression? attachmentIds, - Expression? visibility, + Expression? post, Expression? lastModified, Expression? rowid, }) { return RawValuesInsertable({ if (id != null) 'id': id, - if (title != null) 'title': title, - if (description != null) 'description': description, - if (content != null) 'content': content, - if (attachmentIds != null) 'attachment_ids': attachmentIds, - if (visibility != null) 'visibility': visibility, + if (post != null) 'post': post, if (lastModified != null) 'last_modified': lastModified, if (rowid != null) 'rowid': rowid, }); } - ComposeDraftsCompanion copyWith({ + PostDraftsCompanion copyWith({ Value? id, - Value? title, - Value? description, - Value? content, - Value? attachmentIds, - Value? visibility, + Value? post, Value? lastModified, Value? rowid, }) { - return ComposeDraftsCompanion( + return PostDraftsCompanion( id: id ?? this.id, - title: title ?? this.title, - description: description ?? this.description, - content: content ?? this.content, - attachmentIds: attachmentIds ?? this.attachmentIds, - visibility: visibility ?? this.visibility, + post: post ?? this.post, lastModified: lastModified ?? this.lastModified, rowid: rowid ?? this.rowid, ); @@ -1005,20 +813,8 @@ class ComposeDraftsCompanion extends UpdateCompanion { if (id.present) { map['id'] = Variable(id.value); } - if (title.present) { - map['title'] = Variable(title.value); - } - if (description.present) { - map['description'] = Variable(description.value); - } - if (content.present) { - map['content'] = Variable(content.value); - } - if (attachmentIds.present) { - map['attachment_ids'] = Variable(attachmentIds.value); - } - if (visibility.present) { - map['visibility'] = Variable(visibility.value); + if (post.present) { + map['post'] = Variable(post.value); } if (lastModified.present) { map['last_modified'] = Variable(lastModified.value); @@ -1031,430 +827,9 @@ class ComposeDraftsCompanion extends UpdateCompanion { @override String toString() { - return (StringBuffer('ComposeDraftsCompanion(') + return (StringBuffer('PostDraftsCompanion(') ..write('id: $id, ') - ..write('title: $title, ') - ..write('description: $description, ') - ..write('content: $content, ') - ..write('attachmentIds: $attachmentIds, ') - ..write('visibility: $visibility, ') - ..write('lastModified: $lastModified, ') - ..write('rowid: $rowid') - ..write(')')) - .toString(); - } -} - -class $ArticleDraftsTable extends ArticleDrafts - with TableInfo<$ArticleDraftsTable, ArticleDraft> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $ArticleDraftsTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _idMeta = const VerificationMeta('id'); - @override - late final GeneratedColumn id = GeneratedColumn( - 'id', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - ); - static const VerificationMeta _titleMeta = const VerificationMeta('title'); - @override - late final GeneratedColumn title = GeneratedColumn( - 'title', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant(''), - ); - static const VerificationMeta _descriptionMeta = const VerificationMeta( - 'description', - ); - @override - late final GeneratedColumn description = GeneratedColumn( - 'description', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant(''), - ); - static const VerificationMeta _contentMeta = const VerificationMeta( - 'content', - ); - @override - late final GeneratedColumn content = GeneratedColumn( - 'content', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: false, - defaultValue: const Constant(''), - ); - static const VerificationMeta _visibilityMeta = const VerificationMeta( - 'visibility', - ); - @override - late final GeneratedColumn visibility = GeneratedColumn( - 'visibility', - aliasedName, - false, - type: DriftSqlType.int, - requiredDuringInsert: false, - defaultValue: const Constant(0), - ); - static const VerificationMeta _lastModifiedMeta = const VerificationMeta( - 'lastModified', - ); - @override - late final GeneratedColumn lastModified = GeneratedColumn( - 'last_modified', - aliasedName, - false, - type: DriftSqlType.dateTime, - requiredDuringInsert: true, - ); - @override - List get $columns => [ - id, - title, - description, - content, - visibility, - lastModified, - ]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'article_drafts'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('id')) { - context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); - } else if (isInserting) { - context.missing(_idMeta); - } - if (data.containsKey('title')) { - context.handle( - _titleMeta, - 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('last_modified')) { - context.handle( - _lastModifiedMeta, - lastModified.isAcceptableOrUnknown( - data['last_modified']!, - _lastModifiedMeta, - ), - ); - } else if (isInserting) { - context.missing(_lastModifiedMeta); - } - return context; - } - - @override - Set get $primaryKey => {id}; - @override - ArticleDraft map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return ArticleDraft( - id: - attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}id'], - )!, - 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( - DriftSqlType.int, - data['${effectivePrefix}visibility'], - )!, - lastModified: - attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, - data['${effectivePrefix}last_modified'], - )!, - ); - } - - @override - $ArticleDraftsTable createAlias(String alias) { - return $ArticleDraftsTable(attachedDatabase, alias); - } -} - -class ArticleDraft extends DataClass implements Insertable { - final String id; - final String title; - final String description; - final String content; - final int visibility; - final DateTime lastModified; - const ArticleDraft({ - required this.id, - required this.title, - required this.description, - required this.content, - required this.visibility, - required this.lastModified, - }); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['id'] = Variable(id); - map['title'] = Variable(title); - map['description'] = Variable(description); - map['content'] = Variable(content); - map['visibility'] = Variable(visibility); - map['last_modified'] = Variable(lastModified); - return map; - } - - ArticleDraftsCompanion toCompanion(bool nullToAbsent) { - return ArticleDraftsCompanion( - id: Value(id), - title: Value(title), - description: Value(description), - content: Value(content), - visibility: Value(visibility), - lastModified: Value(lastModified), - ); - } - - factory ArticleDraft.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return ArticleDraft( - id: serializer.fromJson(json['id']), - title: serializer.fromJson(json['title']), - description: serializer.fromJson(json['description']), - content: serializer.fromJson(json['content']), - visibility: serializer.fromJson(json['visibility']), - lastModified: serializer.fromJson(json['lastModified']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'title': serializer.toJson(title), - 'description': serializer.toJson(description), - 'content': serializer.toJson(content), - 'visibility': serializer.toJson(visibility), - 'lastModified': serializer.toJson(lastModified), - }; - } - - ArticleDraft copyWith({ - String? id, - String? title, - String? description, - String? content, - int? visibility, - DateTime? lastModified, - }) => ArticleDraft( - id: id ?? this.id, - title: title ?? this.title, - description: description ?? this.description, - content: content ?? this.content, - visibility: visibility ?? this.visibility, - lastModified: lastModified ?? this.lastModified, - ); - ArticleDraft copyWithCompanion(ArticleDraftsCompanion data) { - return ArticleDraft( - id: data.id.present ? data.id.value : this.id, - 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, - lastModified: - data.lastModified.present - ? data.lastModified.value - : this.lastModified, - ); - } - - @override - String toString() { - return (StringBuffer('ArticleDraft(') - ..write('id: $id, ') - ..write('title: $title, ') - ..write('description: $description, ') - ..write('content: $content, ') - ..write('visibility: $visibility, ') - ..write('lastModified: $lastModified') - ..write(')')) - .toString(); - } - - @override - int get hashCode => - Object.hash(id, title, description, content, visibility, lastModified); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is ArticleDraft && - other.id == this.id && - other.title == this.title && - other.description == this.description && - other.content == this.content && - other.visibility == this.visibility && - other.lastModified == this.lastModified); -} - -class ArticleDraftsCompanion extends UpdateCompanion { - final Value id; - final Value title; - final Value description; - final Value content; - final Value visibility; - final Value lastModified; - final Value rowid; - const ArticleDraftsCompanion({ - this.id = const Value.absent(), - this.title = const Value.absent(), - this.description = const Value.absent(), - this.content = const Value.absent(), - this.visibility = const Value.absent(), - this.lastModified = const Value.absent(), - this.rowid = const Value.absent(), - }); - ArticleDraftsCompanion.insert({ - required String id, - this.title = const Value.absent(), - this.description = const Value.absent(), - this.content = const Value.absent(), - this.visibility = const Value.absent(), - required DateTime lastModified, - this.rowid = const Value.absent(), - }) : id = Value(id), - lastModified = Value(lastModified); - static Insertable custom({ - Expression? id, - Expression? title, - Expression? description, - Expression? content, - Expression? visibility, - Expression? lastModified, - Expression? rowid, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (title != null) 'title': title, - if (description != null) 'description': description, - if (content != null) 'content': content, - if (visibility != null) 'visibility': visibility, - if (lastModified != null) 'last_modified': lastModified, - if (rowid != null) 'rowid': rowid, - }); - } - - ArticleDraftsCompanion copyWith({ - Value? id, - Value? title, - Value? description, - Value? content, - Value? visibility, - Value? lastModified, - Value? rowid, - }) { - return ArticleDraftsCompanion( - id: id ?? this.id, - title: title ?? this.title, - description: description ?? this.description, - content: content ?? this.content, - visibility: visibility ?? this.visibility, - lastModified: lastModified ?? this.lastModified, - rowid: rowid ?? this.rowid, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (title.present) { - map['title'] = Variable(title.value); - } - if (description.present) { - map['description'] = Variable(description.value); - } - if (content.present) { - map['content'] = Variable(content.value); - } - if (visibility.present) { - map['visibility'] = Variable(visibility.value); - } - if (lastModified.present) { - map['last_modified'] = Variable(lastModified.value); - } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('ArticleDraftsCompanion(') - ..write('id: $id, ') - ..write('title: $title, ') - ..write('description: $description, ') - ..write('content: $content, ') - ..write('visibility: $visibility, ') + ..write('post: $post, ') ..write('lastModified: $lastModified, ') ..write('rowid: $rowid') ..write(')')) @@ -1466,16 +841,14 @@ abstract class _$AppDatabase extends GeneratedDatabase { _$AppDatabase(QueryExecutor e) : super(e); $AppDatabaseManager get managers => $AppDatabaseManager(this); late final $ChatMessagesTable chatMessages = $ChatMessagesTable(this); - late final $ComposeDraftsTable composeDrafts = $ComposeDraftsTable(this); - late final $ArticleDraftsTable articleDrafts = $ArticleDraftsTable(this); + late final $PostDraftsTable postDrafts = $PostDraftsTable(this); @override Iterable> get allTables => allSchemaEntities.whereType>(); @override List get allSchemaEntities => [ chatMessages, - composeDrafts, - articleDrafts, + postDrafts, ]; } @@ -1764,32 +1137,24 @@ typedef $$ChatMessagesTableProcessedTableManager = ChatMessage, PrefetchHooks Function() >; -typedef $$ComposeDraftsTableCreateCompanionBuilder = - ComposeDraftsCompanion Function({ +typedef $$PostDraftsTableCreateCompanionBuilder = + PostDraftsCompanion Function({ required String id, - Value title, - Value description, - Value content, - Value attachmentIds, - Value visibility, + required String post, required DateTime lastModified, Value rowid, }); -typedef $$ComposeDraftsTableUpdateCompanionBuilder = - ComposeDraftsCompanion Function({ +typedef $$PostDraftsTableUpdateCompanionBuilder = + PostDraftsCompanion Function({ Value id, - Value title, - Value description, - Value content, - Value attachmentIds, - Value visibility, + Value post, Value lastModified, Value rowid, }); -class $$ComposeDraftsTableFilterComposer - extends Composer<_$AppDatabase, $ComposeDraftsTable> { - $$ComposeDraftsTableFilterComposer({ +class $$PostDraftsTableFilterComposer + extends Composer<_$AppDatabase, $PostDraftsTable> { + $$PostDraftsTableFilterComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -1801,28 +1166,8 @@ class $$ComposeDraftsTableFilterComposer builder: (column) => ColumnFilters(column), ); - ColumnFilters get title => $composableBuilder( - column: $table.title, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get description => $composableBuilder( - column: $table.description, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get content => $composableBuilder( - column: $table.content, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get attachmentIds => $composableBuilder( - column: $table.attachmentIds, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get visibility => $composableBuilder( - column: $table.visibility, + ColumnFilters get post => $composableBuilder( + column: $table.post, builder: (column) => ColumnFilters(column), ); @@ -1832,9 +1177,9 @@ class $$ComposeDraftsTableFilterComposer ); } -class $$ComposeDraftsTableOrderingComposer - extends Composer<_$AppDatabase, $ComposeDraftsTable> { - $$ComposeDraftsTableOrderingComposer({ +class $$PostDraftsTableOrderingComposer + extends Composer<_$AppDatabase, $PostDraftsTable> { + $$PostDraftsTableOrderingComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -1846,28 +1191,8 @@ class $$ComposeDraftsTableOrderingComposer builder: (column) => ColumnOrderings(column), ); - ColumnOrderings get title => $composableBuilder( - column: $table.title, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get description => $composableBuilder( - column: $table.description, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get content => $composableBuilder( - column: $table.content, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get attachmentIds => $composableBuilder( - column: $table.attachmentIds, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get visibility => $composableBuilder( - column: $table.visibility, + ColumnOrderings get post => $composableBuilder( + column: $table.post, builder: (column) => ColumnOrderings(column), ); @@ -1877,9 +1202,9 @@ class $$ComposeDraftsTableOrderingComposer ); } -class $$ComposeDraftsTableAnnotationComposer - extends Composer<_$AppDatabase, $ComposeDraftsTable> { - $$ComposeDraftsTableAnnotationComposer({ +class $$PostDraftsTableAnnotationComposer + extends Composer<_$AppDatabase, $PostDraftsTable> { + $$PostDraftsTableAnnotationComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -1889,26 +1214,8 @@ class $$ComposeDraftsTableAnnotationComposer GeneratedColumn get id => $composableBuilder(column: $table.id, builder: (column) => column); - GeneratedColumn get title => - $composableBuilder(column: $table.title, builder: (column) => column); - - GeneratedColumn get description => $composableBuilder( - column: $table.description, - builder: (column) => column, - ); - - GeneratedColumn get content => - $composableBuilder(column: $table.content, builder: (column) => column); - - GeneratedColumn get attachmentIds => $composableBuilder( - column: $table.attachmentIds, - builder: (column) => column, - ); - - GeneratedColumn get visibility => $composableBuilder( - column: $table.visibility, - builder: (column) => column, - ); + GeneratedColumn get post => + $composableBuilder(column: $table.post, builder: (column) => column); GeneratedColumn get lastModified => $composableBuilder( column: $table.lastModified, @@ -1916,76 +1223,56 @@ class $$ComposeDraftsTableAnnotationComposer ); } -class $$ComposeDraftsTableTableManager +class $$PostDraftsTableTableManager extends RootTableManager< _$AppDatabase, - $ComposeDraftsTable, - ComposeDraft, - $$ComposeDraftsTableFilterComposer, - $$ComposeDraftsTableOrderingComposer, - $$ComposeDraftsTableAnnotationComposer, - $$ComposeDraftsTableCreateCompanionBuilder, - $$ComposeDraftsTableUpdateCompanionBuilder, + $PostDraftsTable, + PostDraft, + $$PostDraftsTableFilterComposer, + $$PostDraftsTableOrderingComposer, + $$PostDraftsTableAnnotationComposer, + $$PostDraftsTableCreateCompanionBuilder, + $$PostDraftsTableUpdateCompanionBuilder, ( - ComposeDraft, - BaseReferences<_$AppDatabase, $ComposeDraftsTable, ComposeDraft>, + PostDraft, + BaseReferences<_$AppDatabase, $PostDraftsTable, PostDraft>, ), - ComposeDraft, + PostDraft, PrefetchHooks Function() > { - $$ComposeDraftsTableTableManager(_$AppDatabase db, $ComposeDraftsTable table) + $$PostDraftsTableTableManager(_$AppDatabase db, $PostDraftsTable table) : super( TableManagerState( db: db, table: table, createFilteringComposer: - () => $$ComposeDraftsTableFilterComposer($db: db, $table: table), + () => $$PostDraftsTableFilterComposer($db: db, $table: table), createOrderingComposer: - () => - $$ComposeDraftsTableOrderingComposer($db: db, $table: table), + () => $$PostDraftsTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: - () => $$ComposeDraftsTableAnnotationComposer( - $db: db, - $table: table, - ), + () => $$PostDraftsTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ Value id = const Value.absent(), - Value title = const Value.absent(), - Value description = const Value.absent(), - Value content = const Value.absent(), - Value attachmentIds = const Value.absent(), - Value visibility = const Value.absent(), + Value post = const Value.absent(), Value lastModified = const Value.absent(), Value rowid = const Value.absent(), - }) => ComposeDraftsCompanion( + }) => PostDraftsCompanion( id: id, - title: title, - description: description, - content: content, - attachmentIds: attachmentIds, - visibility: visibility, + post: post, lastModified: lastModified, rowid: rowid, ), createCompanionCallback: ({ required String id, - Value title = const Value.absent(), - Value description = const Value.absent(), - Value content = const Value.absent(), - Value attachmentIds = const Value.absent(), - Value visibility = const Value.absent(), + required String post, required DateTime lastModified, Value rowid = const Value.absent(), - }) => ComposeDraftsCompanion.insert( + }) => PostDraftsCompanion.insert( id: id, - title: title, - description: description, - content: content, - attachmentIds: attachmentIds, - visibility: visibility, + post: post, lastModified: lastModified, rowid: rowid, ), @@ -2004,257 +1291,18 @@ class $$ComposeDraftsTableTableManager ); } -typedef $$ComposeDraftsTableProcessedTableManager = +typedef $$PostDraftsTableProcessedTableManager = ProcessedTableManager< _$AppDatabase, - $ComposeDraftsTable, - ComposeDraft, - $$ComposeDraftsTableFilterComposer, - $$ComposeDraftsTableOrderingComposer, - $$ComposeDraftsTableAnnotationComposer, - $$ComposeDraftsTableCreateCompanionBuilder, - $$ComposeDraftsTableUpdateCompanionBuilder, - ( - ComposeDraft, - BaseReferences<_$AppDatabase, $ComposeDraftsTable, ComposeDraft>, - ), - ComposeDraft, - PrefetchHooks Function() - >; -typedef $$ArticleDraftsTableCreateCompanionBuilder = - ArticleDraftsCompanion Function({ - required String id, - Value title, - Value description, - Value content, - Value visibility, - required DateTime lastModified, - Value rowid, - }); -typedef $$ArticleDraftsTableUpdateCompanionBuilder = - ArticleDraftsCompanion Function({ - Value id, - Value title, - Value description, - Value content, - Value visibility, - Value lastModified, - Value rowid, - }); - -class $$ArticleDraftsTableFilterComposer - extends Composer<_$AppDatabase, $ArticleDraftsTable> { - $$ArticleDraftsTableFilterComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnFilters get id => $composableBuilder( - column: $table.id, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get title => $composableBuilder( - column: $table.title, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get description => $composableBuilder( - column: $table.description, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get content => $composableBuilder( - column: $table.content, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get visibility => $composableBuilder( - column: $table.visibility, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get lastModified => $composableBuilder( - column: $table.lastModified, - builder: (column) => ColumnFilters(column), - ); -} - -class $$ArticleDraftsTableOrderingComposer - extends Composer<_$AppDatabase, $ArticleDraftsTable> { - $$ArticleDraftsTableOrderingComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnOrderings get id => $composableBuilder( - column: $table.id, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get title => $composableBuilder( - column: $table.title, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get description => $composableBuilder( - column: $table.description, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get content => $composableBuilder( - column: $table.content, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get visibility => $composableBuilder( - column: $table.visibility, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get lastModified => $composableBuilder( - column: $table.lastModified, - builder: (column) => ColumnOrderings(column), - ); -} - -class $$ArticleDraftsTableAnnotationComposer - extends Composer<_$AppDatabase, $ArticleDraftsTable> { - $$ArticleDraftsTableAnnotationComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - GeneratedColumn get id => - $composableBuilder(column: $table.id, builder: (column) => column); - - GeneratedColumn get title => - $composableBuilder(column: $table.title, builder: (column) => column); - - GeneratedColumn get description => $composableBuilder( - column: $table.description, - builder: (column) => column, - ); - - GeneratedColumn get content => - $composableBuilder(column: $table.content, builder: (column) => column); - - GeneratedColumn get visibility => $composableBuilder( - column: $table.visibility, - builder: (column) => column, - ); - - GeneratedColumn get lastModified => $composableBuilder( - column: $table.lastModified, - builder: (column) => column, - ); -} - -class $$ArticleDraftsTableTableManager - extends - RootTableManager< - _$AppDatabase, - $ArticleDraftsTable, - ArticleDraft, - $$ArticleDraftsTableFilterComposer, - $$ArticleDraftsTableOrderingComposer, - $$ArticleDraftsTableAnnotationComposer, - $$ArticleDraftsTableCreateCompanionBuilder, - $$ArticleDraftsTableUpdateCompanionBuilder, - ( - ArticleDraft, - BaseReferences<_$AppDatabase, $ArticleDraftsTable, ArticleDraft>, - ), - ArticleDraft, - PrefetchHooks Function() - > { - $$ArticleDraftsTableTableManager(_$AppDatabase db, $ArticleDraftsTable table) - : super( - TableManagerState( - db: db, - table: table, - createFilteringComposer: - () => $$ArticleDraftsTableFilterComposer($db: db, $table: table), - createOrderingComposer: - () => - $$ArticleDraftsTableOrderingComposer($db: db, $table: table), - createComputedFieldComposer: - () => $$ArticleDraftsTableAnnotationComposer( - $db: db, - $table: table, - ), - updateCompanionCallback: - ({ - Value id = const Value.absent(), - Value title = const Value.absent(), - Value description = const Value.absent(), - Value content = const Value.absent(), - Value visibility = const Value.absent(), - Value lastModified = const Value.absent(), - Value rowid = const Value.absent(), - }) => ArticleDraftsCompanion( - id: id, - title: title, - description: description, - content: content, - visibility: visibility, - lastModified: lastModified, - rowid: rowid, - ), - createCompanionCallback: - ({ - required String id, - Value title = const Value.absent(), - Value description = const Value.absent(), - Value content = const Value.absent(), - Value visibility = const Value.absent(), - required DateTime lastModified, - Value rowid = const Value.absent(), - }) => ArticleDraftsCompanion.insert( - id: id, - title: title, - description: description, - content: content, - visibility: visibility, - lastModified: lastModified, - rowid: rowid, - ), - withReferenceMapper: - (p0) => - p0 - .map( - (e) => ( - e.readTable(table), - BaseReferences(db, table, e), - ), - ) - .toList(), - prefetchHooksCallback: null, - ), - ); -} - -typedef $$ArticleDraftsTableProcessedTableManager = - ProcessedTableManager< - _$AppDatabase, - $ArticleDraftsTable, - ArticleDraft, - $$ArticleDraftsTableFilterComposer, - $$ArticleDraftsTableOrderingComposer, - $$ArticleDraftsTableAnnotationComposer, - $$ArticleDraftsTableCreateCompanionBuilder, - $$ArticleDraftsTableUpdateCompanionBuilder, - ( - ArticleDraft, - BaseReferences<_$AppDatabase, $ArticleDraftsTable, ArticleDraft>, - ), - ArticleDraft, + $PostDraftsTable, + PostDraft, + $$PostDraftsTableFilterComposer, + $$PostDraftsTableOrderingComposer, + $$PostDraftsTableAnnotationComposer, + $$PostDraftsTableCreateCompanionBuilder, + $$PostDraftsTableUpdateCompanionBuilder, + (PostDraft, BaseReferences<_$AppDatabase, $PostDraftsTable, PostDraft>), + PostDraft, PrefetchHooks Function() >; @@ -2263,8 +1311,6 @@ class $AppDatabaseManager { $AppDatabaseManager(this._db); $$ChatMessagesTableTableManager get chatMessages => $$ChatMessagesTableTableManager(_db, _db.chatMessages); - $$ComposeDraftsTableTableManager get composeDrafts => - $$ComposeDraftsTableTableManager(_db, _db.composeDrafts); - $$ArticleDraftsTableTableManager get articleDrafts => - $$ArticleDraftsTableTableManager(_db, _db.articleDrafts); + $$PostDraftsTableTableManager get postDrafts => + $$PostDraftsTableTableManager(_db, _db.postDrafts); } diff --git a/lib/models/post.dart b/lib/models/post.dart index d1ae308..350c724 100644 --- a/lib/models/post.dart +++ b/lib/models/post.dart @@ -9,36 +9,36 @@ part 'post.g.dart'; sealed class SnPost with _$SnPost { const factory SnPost({ required String id, - required String? title, - required String? description, - required String? language, - required DateTime? editedAt, - required DateTime publishedAt, - required int visibility, - required String? content, - required int type, - required Map? meta, - required int viewsUnique, - required int viewsTotal, - required int upvotes, - required int downvotes, - required int repliesCount, - required String? threadedPostId, - required SnPost? threadedPost, - required String? repliedPostId, - required SnPost? repliedPost, - required String? forwardedPostId, - required SnPost? forwardedPost, - required List attachments, - required SnPublisher publisher, + String? title, + String? description, + String? language, + DateTime? editedAt, + @Default(null) DateTime? publishedAt, + @Default(0) int visibility, + String? content, + @Default(0) int type, + Map? meta, + @Default(0) int viewsUnique, + @Default(0) int viewsTotal, + @Default(0) int upvotes, + @Default(0) int downvotes, + @Default(0) int repliesCount, + String? threadedPostId, + SnPost? threadedPost, + String? repliedPostId, + SnPost? repliedPost, + String? forwardedPostId, + SnPost? forwardedPost, + @Default([]) List attachments, + @Default(SnPublisher()) SnPublisher publisher, @Default({}) Map reactionsCount, - required List reactions, - required List tags, - required List categories, - required List collections, - required DateTime createdAt, - required DateTime updatedAt, - required DateTime? deletedAt, + @Default([]) List reactions, + @Default([]) List tags, + @Default([]) List categories, + @Default([]) List collections, + @Default(null) DateTime? createdAt, + @Default(null) DateTime? updatedAt, + DateTime? deletedAt, @Default(false) bool isTruncated, }) = _SnPost; @@ -48,20 +48,20 @@ sealed class SnPost with _$SnPost { @freezed sealed class SnPublisher with _$SnPublisher { const factory SnPublisher({ - required String id, - required int type, - required String name, - required String nick, + @Default('') String id, + @Default(0) int type, + @Default('') String name, + @Default('') String nick, @Default('') String bio, - required SnCloudFile? picture, - required SnCloudFile? background, - required SnAccount? account, - required String? accountId, - required DateTime createdAt, - required DateTime updatedAt, - required DateTime? deletedAt, - required String? realmId, - required SnVerificationMark? verification, + SnCloudFile? picture, + SnCloudFile? background, + SnAccount? account, + String? accountId, + @Default(null) DateTime? createdAt, + @Default(null) DateTime? updatedAt, + DateTime? deletedAt, + String? realmId, + SnVerificationMark? verification, }) = _SnPublisher; factory SnPublisher.fromJson(Map json) => diff --git a/lib/models/post.freezed.dart b/lib/models/post.freezed.dart index ed78355..193127b 100644 --- a/lib/models/post.freezed.dart +++ b/lib/models/post.freezed.dart @@ -16,7 +16,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$SnPost { - String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime get publishedAt; int get visibility; String? get content; int get type; Map? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; List get attachments; SnPublisher get publisher; Map get reactionsCount; List get reactions; List get tags; List get categories; List get collections; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; bool get isTruncated; + String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; int get type; Map? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; List get attachments; SnPublisher get publisher; Map get reactionsCount; List get reactions; List get tags; List get categories; List get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated; /// Create a copy of SnPost /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -49,7 +49,7 @@ abstract mixin class $SnPostCopyWith<$Res> { factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl; @useResult $Res call({ - String id, String? title, String? description, String? language, DateTime? editedAt, DateTime publishedAt, int visibility, String? content, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List attachments, SnPublisher publisher, Map reactionsCount, List reactions, List tags, List categories, List collections, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, bool isTruncated + String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List attachments, SnPublisher publisher, Map reactionsCount, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated }); @@ -66,15 +66,15 @@ class _$SnPostCopyWithImpl<$Res> /// Create a copy of SnPost /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = null,Object? visibility = null,Object? content = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? isTruncated = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable as String?,editedAt: freezed == editedAt ? _self.editedAt : editedAt // ignore: cast_nullable_to_non_nullable -as DateTime?,publishedAt: null == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable -as DateTime,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable +as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,meta: freezed == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable @@ -96,9 +96,9 @@ as Map,reactions: null == reactions ? _self.reactions : reactions / as List,tags: null == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable as List,categories: null == categories ? _self.categories : categories // ignore: cast_nullable_to_non_nullable as List,collections: null == collections ? _self.collections : collections // ignore: cast_nullable_to_non_nullable -as List,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable -as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable -as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable +as List,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime?,isTruncated: null == isTruncated ? _self.isTruncated : isTruncated // ignore: cast_nullable_to_non_nullable as bool, )); @@ -156,7 +156,7 @@ $SnPublisherCopyWith<$Res> get publisher { @JsonSerializable() class _SnPost implements SnPost { - const _SnPost({required this.id, required this.title, required this.description, required this.language, required this.editedAt, required this.publishedAt, required this.visibility, required this.content, required this.type, required final Map? meta, required this.viewsUnique, required this.viewsTotal, required this.upvotes, required this.downvotes, required this.repliesCount, required this.threadedPostId, required this.threadedPost, required this.repliedPostId, required this.repliedPost, required this.forwardedPostId, required this.forwardedPost, required final List attachments, required this.publisher, final Map reactionsCount = const {}, required final List reactions, required final List tags, required final List categories, required final List collections, required this.createdAt, required this.updatedAt, required this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; + const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.type = 0, final Map? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, final List attachments = const [], this.publisher = const SnPublisher(), final Map reactionsCount = const {}, final List reactions = const [], final List tags = const [], final List categories = const [], final List collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections; factory _SnPost.fromJson(Map json) => _$SnPostFromJson(json); @override final String id; @@ -164,10 +164,10 @@ class _SnPost implements SnPost { @override final String? description; @override final String? language; @override final DateTime? editedAt; -@override final DateTime publishedAt; -@override final int visibility; +@override@JsonKey() final DateTime? publishedAt; +@override@JsonKey() final int visibility; @override final String? content; -@override final int type; +@override@JsonKey() final int type; final Map? _meta; @override Map? get meta { final value = _meta; @@ -177,11 +177,11 @@ class _SnPost implements SnPost { return EqualUnmodifiableMapView(value); } -@override final int viewsUnique; -@override final int viewsTotal; -@override final int upvotes; -@override final int downvotes; -@override final int repliesCount; +@override@JsonKey() final int viewsUnique; +@override@JsonKey() final int viewsTotal; +@override@JsonKey() final int upvotes; +@override@JsonKey() final int downvotes; +@override@JsonKey() final int repliesCount; @override final String? threadedPostId; @override final SnPost? threadedPost; @override final String? repliedPostId; @@ -189,13 +189,13 @@ class _SnPost implements SnPost { @override final String? forwardedPostId; @override final SnPost? forwardedPost; final List _attachments; -@override List get attachments { +@override@JsonKey() List get attachments { if (_attachments is EqualUnmodifiableListView) return _attachments; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_attachments); } -@override final SnPublisher publisher; +@override@JsonKey() final SnPublisher publisher; final Map _reactionsCount; @override@JsonKey() Map get reactionsCount { if (_reactionsCount is EqualUnmodifiableMapView) return _reactionsCount; @@ -204,35 +204,35 @@ class _SnPost implements SnPost { } final List _reactions; -@override List get reactions { +@override@JsonKey() List get reactions { if (_reactions is EqualUnmodifiableListView) return _reactions; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_reactions); } final List _tags; -@override List get tags { +@override@JsonKey() List get tags { if (_tags is EqualUnmodifiableListView) return _tags; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_tags); } final List _categories; -@override List get categories { +@override@JsonKey() List get categories { if (_categories is EqualUnmodifiableListView) return _categories; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_categories); } final List _collections; -@override List get collections { +@override@JsonKey() List get collections { if (_collections is EqualUnmodifiableListView) return _collections; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_collections); } -@override final DateTime createdAt; -@override final DateTime updatedAt; +@override@JsonKey() final DateTime? createdAt; +@override@JsonKey() final DateTime? updatedAt; @override final DateTime? deletedAt; @override@JsonKey() final bool isTruncated; @@ -269,7 +269,7 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> { factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl; @override @useResult $Res call({ - String id, String? title, String? description, String? language, DateTime? editedAt, DateTime publishedAt, int visibility, String? content, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List attachments, SnPublisher publisher, Map reactionsCount, List reactions, List tags, List categories, List collections, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, bool isTruncated + String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, int type, Map? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List attachments, SnPublisher publisher, Map reactionsCount, List reactions, List tags, List categories, List collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated }); @@ -286,15 +286,15 @@ class __$SnPostCopyWithImpl<$Res> /// Create a copy of SnPost /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = null,Object? visibility = null,Object? content = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? isTruncated = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) { return _then(_SnPost( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable as String?,editedAt: freezed == editedAt ? _self.editedAt : editedAt // ignore: cast_nullable_to_non_nullable -as DateTime?,publishedAt: null == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable -as DateTime,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable +as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,meta: freezed == meta ? _self._meta : meta // ignore: cast_nullable_to_non_nullable @@ -316,9 +316,9 @@ as Map,reactions: null == reactions ? _self._reactions : reactions as List,tags: null == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable as List,categories: null == categories ? _self._categories : categories // ignore: cast_nullable_to_non_nullable as List,collections: null == collections ? _self._collections : collections // ignore: cast_nullable_to_non_nullable -as List,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable -as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable -as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable +as List,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime?,isTruncated: null == isTruncated ? _self.isTruncated : isTruncated // ignore: cast_nullable_to_non_nullable as bool, )); @@ -376,7 +376,7 @@ $SnPublisherCopyWith<$Res> get publisher { /// @nodoc mixin _$SnPublisher { - String get id; int get type; String get name; String get nick; String get bio; SnCloudFile? get picture; SnCloudFile? get background; SnAccount? get account; String? get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String? get realmId; SnVerificationMark? get verification; + String get id; int get type; String get name; String get nick; String get bio; SnCloudFile? get picture; SnCloudFile? get background; SnAccount? get account; String? get accountId; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; String? get realmId; SnVerificationMark? get verification; /// Create a copy of SnPublisher /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -409,7 +409,7 @@ abstract mixin class $SnPublisherCopyWith<$Res> { factory $SnPublisherCopyWith(SnPublisher value, $Res Function(SnPublisher) _then) = _$SnPublisherCopyWithImpl; @useResult $Res call({ - String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification + String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification }); @@ -426,7 +426,7 @@ class _$SnPublisherCopyWithImpl<$Res> /// Create a copy of SnPublisher /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable @@ -437,9 +437,9 @@ as String,picture: freezed == picture ? _self.picture : picture // ignore: cast_ as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable as SnCloudFile?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable as SnAccount?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable -as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable -as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable -as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable as SnVerificationMark?, @@ -501,20 +501,20 @@ $SnVerificationMarkCopyWith<$Res>? get verification { @JsonSerializable() class _SnPublisher implements SnPublisher { - const _SnPublisher({required this.id, required this.type, required this.name, required this.nick, this.bio = '', required this.picture, required this.background, required this.account, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt, required this.realmId, required this.verification}); + const _SnPublisher({this.id = '', this.type = 0, this.name = '', this.nick = '', this.bio = '', this.picture, this.background, this.account, this.accountId, this.createdAt = null, this.updatedAt = null, this.deletedAt, this.realmId, this.verification}); factory _SnPublisher.fromJson(Map json) => _$SnPublisherFromJson(json); -@override final String id; -@override final int type; -@override final String name; -@override final String nick; +@override@JsonKey() final String id; +@override@JsonKey() final int type; +@override@JsonKey() final String name; +@override@JsonKey() final String nick; @override@JsonKey() final String bio; @override final SnCloudFile? picture; @override final SnCloudFile? background; @override final SnAccount? account; @override final String? accountId; -@override final DateTime createdAt; -@override final DateTime updatedAt; +@override@JsonKey() final DateTime? createdAt; +@override@JsonKey() final DateTime? updatedAt; @override final DateTime? deletedAt; @override final String? realmId; @override final SnVerificationMark? verification; @@ -552,7 +552,7 @@ abstract mixin class _$SnPublisherCopyWith<$Res> implements $SnPublisherCopyWith factory _$SnPublisherCopyWith(_SnPublisher value, $Res Function(_SnPublisher) _then) = __$SnPublisherCopyWithImpl; @override @useResult $Res call({ - String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification + String id, int type, String name, String nick, String bio, SnCloudFile? picture, SnCloudFile? background, SnAccount? account, String? accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, String? realmId, SnVerificationMark? verification }); @@ -569,7 +569,7 @@ class __$SnPublisherCopyWithImpl<$Res> /// Create a copy of SnPublisher /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? type = null,Object? name = null,Object? nick = null,Object? bio = null,Object? picture = freezed,Object? background = freezed,Object? account = freezed,Object? accountId = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? realmId = freezed,Object? verification = freezed,}) { return _then(_SnPublisher( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable @@ -580,9 +580,9 @@ as String,picture: freezed == picture ? _self.picture : picture // ignore: cast_ as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable as SnCloudFile?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable as SnAccount?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable -as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable -as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable -as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable as String?,verification: freezed == verification ? _self.verification : verification // ignore: cast_nullable_to_non_nullable as SnVerificationMark?, diff --git a/lib/models/post.g.dart b/lib/models/post.g.dart index 18a9226..22b2304 100644 --- a/lib/models/post.g.dart +++ b/lib/models/post.g.dart @@ -15,16 +15,19 @@ _SnPost _$SnPostFromJson(Map json) => _SnPost( json['edited_at'] == null ? null : DateTime.parse(json['edited_at'] as String), - publishedAt: DateTime.parse(json['published_at'] as String), - visibility: (json['visibility'] as num).toInt(), + publishedAt: + json['published_at'] == null + ? null + : DateTime.parse(json['published_at'] as String), + visibility: (json['visibility'] as num?)?.toInt() ?? 0, content: json['content'] as String?, - type: (json['type'] as num).toInt(), + type: (json['type'] as num?)?.toInt() ?? 0, meta: json['meta'] as Map?, - viewsUnique: (json['views_unique'] as num).toInt(), - viewsTotal: (json['views_total'] as num).toInt(), - upvotes: (json['upvotes'] as num).toInt(), - downvotes: (json['downvotes'] as num).toInt(), - repliesCount: (json['replies_count'] as num).toInt(), + viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0, + viewsTotal: (json['views_total'] as num?)?.toInt() ?? 0, + upvotes: (json['upvotes'] as num?)?.toInt() ?? 0, + downvotes: (json['downvotes'] as num?)?.toInt() ?? 0, + repliesCount: (json['replies_count'] as num?)?.toInt() ?? 0, threadedPostId: json['threaded_post_id'] as String?, threadedPost: json['threaded_post'] == null @@ -41,21 +44,31 @@ _SnPost _$SnPostFromJson(Map json) => _SnPost( ? null : SnPost.fromJson(json['forwarded_post'] as Map), attachments: - (json['attachments'] as List) - .map((e) => SnCloudFile.fromJson(e as Map)) - .toList(), - publisher: SnPublisher.fromJson(json['publisher'] as Map), + (json['attachments'] as List?) + ?.map((e) => SnCloudFile.fromJson(e as Map)) + .toList() ?? + const [], + publisher: + json['publisher'] == null + ? const SnPublisher() + : SnPublisher.fromJson(json['publisher'] as Map), reactionsCount: (json['reactions_count'] as Map?)?.map( (k, e) => MapEntry(k, (e as num).toInt()), ) ?? const {}, - reactions: json['reactions'] as List, - tags: json['tags'] as List, - categories: json['categories'] as List, - collections: json['collections'] as List, - createdAt: DateTime.parse(json['created_at'] as String), - updatedAt: DateTime.parse(json['updated_at'] as String), + reactions: json['reactions'] as List? ?? const [], + tags: json['tags'] as List? ?? const [], + categories: json['categories'] as List? ?? const [], + collections: json['collections'] as List? ?? const [], + createdAt: + json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: + json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), deletedAt: json['deleted_at'] == null ? null @@ -69,7 +82,7 @@ Map _$SnPostToJson(_SnPost instance) => { 'description': instance.description, 'language': instance.language, 'edited_at': instance.editedAt?.toIso8601String(), - 'published_at': instance.publishedAt.toIso8601String(), + 'published_at': instance.publishedAt?.toIso8601String(), 'visibility': instance.visibility, 'content': instance.content, 'type': instance.type, @@ -92,17 +105,17 @@ Map _$SnPostToJson(_SnPost instance) => { 'tags': instance.tags, 'categories': instance.categories, 'collections': instance.collections, - 'created_at': instance.createdAt.toIso8601String(), - 'updated_at': instance.updatedAt.toIso8601String(), + 'created_at': instance.createdAt?.toIso8601String(), + 'updated_at': instance.updatedAt?.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(), 'is_truncated': instance.isTruncated, }; _SnPublisher _$SnPublisherFromJson(Map json) => _SnPublisher( - id: json['id'] as String, - type: (json['type'] as num).toInt(), - name: json['name'] as String, - nick: json['nick'] as String, + id: json['id'] as String? ?? '', + type: (json['type'] as num?)?.toInt() ?? 0, + name: json['name'] as String? ?? '', + nick: json['nick'] as String? ?? '', bio: json['bio'] as String? ?? '', picture: json['picture'] == null @@ -117,8 +130,14 @@ _SnPublisher _$SnPublisherFromJson(Map json) => _SnPublisher( ? null : SnAccount.fromJson(json['account'] as Map), accountId: json['account_id'] as String?, - createdAt: DateTime.parse(json['created_at'] as String), - updatedAt: DateTime.parse(json['updated_at'] as String), + createdAt: + json['created_at'] == null + ? null + : DateTime.parse(json['created_at'] as String), + updatedAt: + json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String), deletedAt: json['deleted_at'] == null ? null @@ -143,8 +162,8 @@ Map _$SnPublisherToJson(_SnPublisher instance) => 'background': instance.background?.toJson(), 'account': instance.account?.toJson(), 'account_id': instance.accountId, - 'created_at': instance.createdAt.toIso8601String(), - 'updated_at': instance.updatedAt.toIso8601String(), + 'created_at': instance.createdAt?.toIso8601String(), + 'updated_at': instance.updatedAt?.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(), 'realm_id': instance.realmId, 'verification': instance.verification?.toJson(), diff --git a/lib/pods/theme.dart b/lib/pods/theme.dart index 0380245..421ecc1 100644 --- a/lib/pods/theme.dart +++ b/lib/pods/theme.dart @@ -102,6 +102,7 @@ Future createAppTheme( ), snackBarTheme: SnackBarThemeData( behavior: useM3 ? SnackBarBehavior.floating : SnackBarBehavior.fixed, + width: 560, ), appBarTheme: AppBarTheme( centerTitle: true, diff --git a/lib/screens/account/event_calendar.dart b/lib/screens/account/event_calendar.dart index a4046c5..83093f4 100644 --- a/lib/screens/account/event_calendar.dart +++ b/lib/screens/account/event_calendar.dart @@ -61,7 +61,7 @@ class EventCalanderScreen extends HookConsumerWidget { child: Column( children: [ Card( - margin: EdgeInsets.all(16), + margin: EdgeInsets.only(left: 16, right: 16, top: 16), child: Column( children: [ // Use the reusable EventCalendarWidget @@ -77,7 +77,6 @@ class EventCalanderScreen extends HookConsumerWidget { ), // Add the fortune graph widget - const Divider(height: 1), FortuneGraphWidget( events: events, constrainWidth: true, diff --git a/lib/screens/posts/compose.dart b/lib/screens/posts/compose.dart index 60b057a..c9d738e 100644 --- a/lib/screens/posts/compose.dart +++ b/lib/screens/posts/compose.dart @@ -62,8 +62,6 @@ class PostComposeScreen extends HookConsumerWidget { @QueryParam('type') this.type, }); - - @override Widget build(BuildContext context, WidgetRef ref) { // Determine the compose type: auto-detect from edited post or use query parameter @@ -96,7 +94,7 @@ class PostComposeScreen extends HookConsumerWidget { useEffect(() { if (originalPost == null) { // Only auto-save for new posts, not edits - state.startAutoSave(ref); + state.startAutoSave(ref, postType: 0); } return () => state.stopAutoSave(); }, [state]); @@ -118,14 +116,14 @@ class PostComposeScreen extends HookConsumerWidget { final drafts = ref.read(composeStorageNotifierProvider); if (drafts.isNotEmpty) { final mostRecentDraft = drafts.values.reduce( - (a, b) => a.lastModified.isAfter(b.lastModified) ? a : b, + (a, b) => (a.updatedAt ?? DateTime(0)).isAfter(b.updatedAt ?? DateTime(0)) ? a : b, ); // Only load if the draft has meaningful content - if (!mostRecentDraft.isEmpty) { - state.titleController.text = mostRecentDraft.title; - state.descriptionController.text = mostRecentDraft.description; - state.contentController.text = mostRecentDraft.content; + if (mostRecentDraft.content?.isNotEmpty == true || mostRecentDraft.title?.isNotEmpty == true) { + state.titleController.text = mostRecentDraft.title ?? ''; + state.descriptionController.text = mostRecentDraft.description ?? ''; + state.contentController.text = mostRecentDraft.content ?? ''; state.visibility.value = mostRecentDraft.visibility; } } @@ -162,9 +160,10 @@ class PostComposeScreen extends HookConsumerWidget { Widget buildWideAttachmentGrid() { return GridView.builder( shrinkWrap: true, + padding: EdgeInsets.zero, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, + crossAxisCount: 2, crossAxisSpacing: 8, mainAxisSpacing: 8, ), @@ -245,17 +244,16 @@ class PostComposeScreen extends HookConsumerWidget { isScrollControlled: true, builder: (context) => DraftManagerSheet( - isArticle: false, onDraftSelected: (draftId) { final draft = ref.read( composeStorageNotifierProvider, )[draftId]; if (draft != null) { - state.titleController.text = draft.title; + state.titleController.text = draft.title ?? ''; state.descriptionController.text = - draft.description; - state.contentController.text = draft.content; + draft.description ?? ''; + state.contentController.text = draft.content ?? ''; state.visibility.value = draft.visibility; } }, @@ -320,7 +318,7 @@ class PostComposeScreen extends HookConsumerWidget { // Main content area Expanded( child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 480), + constraints: const BoxConstraints(maxWidth: 560), child: Row( spacing: 12, crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/screens/posts/compose_article.dart b/lib/screens/posts/compose_article.dart index 560a257..421111d 100644 --- a/lib/screens/posts/compose_article.dart +++ b/lib/screens/posts/compose_article.dart @@ -1,5 +1,5 @@ import 'dart:async'; -import 'dart:developer'; + import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -9,6 +9,7 @@ import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/file.dart'; import 'package:island/models/post.dart'; + import 'package:island/screens/creators/publishers.dart'; import 'package:island/services/responsive.dart'; import 'package:island/widgets/app_scaffold.dart'; @@ -21,6 +22,7 @@ import 'package:island/widgets/post/compose_settings_sheet.dart'; import 'package:island/services/compose_storage_db.dart'; import 'package:island/widgets/post/publishers_modal.dart'; import 'package:island/widgets/post/draft_manager.dart'; + import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -71,7 +73,7 @@ class ArticleComposeScreen extends HookConsumerWidget { if (originalPost == null) { // Only auto-save for new articles, not edits autoSaveTimer = Timer.periodic(const Duration(seconds: 3), (_) { - _saveArticleDraft(ref, state); + ComposeLogic.saveDraftWithoutUpload(ref, state, postType: 1); }); } return () { @@ -79,7 +81,7 @@ class ArticleComposeScreen extends HookConsumerWidget { state.stopAutoSave(); // Save final draft before disposing if (originalPost == null) { - _saveArticleDraft(ref, state); + ComposeLogic.saveDraftWithoutUpload(ref, state, postType: 1); } ComposeLogic.dispose(state); autoSaveTimer?.cancel(); @@ -100,17 +102,22 @@ class ArticleComposeScreen extends HookConsumerWidget { useEffect(() { if (originalPost == null) { // Try to load the most recent article draft - final drafts = ref.read(articleStorageNotifierProvider); + final drafts = ref.read(composeStorageNotifierProvider); if (drafts.isNotEmpty) { final mostRecentDraft = drafts.values.reduce( - (a, b) => a.lastModified.isAfter(b.lastModified) ? a : b, + (a, b) => + (a.updatedAt ?? DateTime(0)).isAfter(b.updatedAt ?? DateTime(0)) + ? a + : b, ); // Only load if the draft has meaningful content - if (!mostRecentDraft.isEmpty) { - state.titleController.text = mostRecentDraft.title; - state.descriptionController.text = mostRecentDraft.description; - state.contentController.text = mostRecentDraft.content; + if (mostRecentDraft.content?.isNotEmpty == true || + mostRecentDraft.title?.isNotEmpty == true) { + state.titleController.text = mostRecentDraft.title ?? ''; + state.descriptionController.text = + mostRecentDraft.description ?? ''; + state.contentController.text = mostRecentDraft.content ?? ''; state.visibility.value = mostRecentDraft.visibility; } } @@ -356,7 +363,7 @@ class ArticleComposeScreen extends HookConsumerWidget { return PopScope( onPopInvoked: (_) { if (originalPost == null) { - _saveArticleDraft(ref, state); + ComposeLogic.saveDraftWithoutUpload(ref, state, postType: 1); } }, child: AppScaffold( @@ -383,17 +390,17 @@ class ArticleComposeScreen extends HookConsumerWidget { isScrollControlled: true, builder: (context) => DraftManagerSheet( - isArticle: true, onDraftSelected: (draftId) { final draft = ref.read( - articleStorageNotifierProvider, + composeStorageNotifierProvider, )[draftId]; if (draft != null) { - state.titleController.text = draft.title; + state.titleController.text = draft.title ?? ''; state.descriptionController.text = - draft.description; - state.contentController.text = draft.content; + draft.description ?? ''; + state.contentController.text = + draft.content ?? ''; state.visibility.value = draft.visibility; } }, @@ -404,7 +411,7 @@ class ArticleComposeScreen extends HookConsumerWidget { ), IconButton( icon: const Icon(Symbols.save), - onPressed: () => _saveArticleDraft(ref, state), + onPressed: () => ComposeLogic.saveDraft(ref, state, postType: 1), tooltip: 'saveDraft'.tr(), ), IconButton( @@ -524,7 +531,7 @@ class ArticleComposeScreen extends HookConsumerWidget { if (isPaste && isModifierPressed) { ComposeLogic.handlePaste(state); } else if (isSave && isModifierPressed) { - _saveArticleDraft(ref, state); + ComposeLogic.saveDraft(ref, state, postType: 1); } else if (isSubmit && isModifierPressed && !state.submitting.value) { ComposeLogic.performAction( ref, @@ -537,23 +544,5 @@ class ArticleComposeScreen extends HookConsumerWidget { } // Helper method to save article draft - Future _saveArticleDraft(WidgetRef ref, ComposeState state) async { - try { - final draft = ArticleDraftModel( - id: state.draftId, - title: state.titleController.text, - description: state.descriptionController.text, - content: state.contentController.text, - visibility: state.visibility.value, - lastModified: DateTime.now(), - ); - - await ref.read(articleStorageNotifierProvider.notifier).saveDraft(draft); - } catch (e) { - log('[ArticleCompose] Failed to save draft, error: $e'); - // Silently fail for auto-save to avoid disrupting user experience - } - } - } diff --git a/lib/services/compose_storage_db.dart b/lib/services/compose_storage_db.dart index fdf8110..121994d 100644 --- a/lib/services/compose_storage_db.dart +++ b/lib/services/compose_storage_db.dart @@ -1,183 +1,16 @@ import 'dart:convert'; import 'package:drift/drift.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:island/database/drift_db.dart'; +import 'package:island/models/post.dart'; import 'package:island/pods/database.dart'; -import 'package:island/services/file.dart'; -import 'package:island/models/file.dart'; -import 'package:island/pods/config.dart'; -import 'package:island/pods/network.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'compose_storage_db.g.dart'; -class ComposeDraftModel { - final String id; - final String title; - final String description; - final String content; - final List attachments; - final int visibility; - final DateTime lastModified; - - ComposeDraftModel({ - required this.id, - required this.title, - required this.description, - required this.content, - required this.attachments, - required this.visibility, - required this.lastModified, - }); - - Map toJson() => { - 'id': id, - 'title': title, - 'description': description, - 'content': content, - 'attachments': attachments.map((e) => e.toJson()).toList(), - 'visibility': visibility, - 'lastModified': lastModified.toIso8601String(), - }; - - factory ComposeDraftModel.fromJson(Map json) => ComposeDraftModel( - id: json['id'] as String, - title: json['title'] as String? ?? '', - description: json['description'] as String? ?? '', - content: json['content'] as String? ?? '', - attachments: (json['attachments'] as List? ?? []) - .map((e) => UniversalFile.fromJson(e as Map)) - .toList(), - visibility: json['visibility'] as int? ?? 0, - lastModified: DateTime.parse(json['lastModified'] as String), - ); - - factory ComposeDraftModel.fromDbRow(ComposeDraft row) => ComposeDraftModel( - id: row.id, - title: row.title, - description: row.description, - content: row.content, - attachments: (jsonDecode(row.attachmentIds) as List) - .map((e) => UniversalFile.fromJson(e as Map)) - .toList(), - visibility: row.visibility, - lastModified: row.lastModified, - ); - - ComposeDraftsCompanion toDbCompanion() => ComposeDraftsCompanion( - id: Value(id), - title: Value(title), - description: Value(description), - content: Value(content), - attachmentIds: Value(jsonEncode(attachments.map((e) => e.toJson()).toList())), - visibility: Value(visibility), - lastModified: Value(lastModified), - ); - - ComposeDraftModel copyWith({ - String? id, - String? title, - String? description, - String? content, - List? attachments, - int? visibility, - DateTime? lastModified, - }) { - return ComposeDraftModel( - id: id ?? this.id, - title: title ?? this.title, - description: description ?? this.description, - content: content ?? this.content, - attachments: attachments ?? this.attachments, - visibility: visibility ?? this.visibility, - lastModified: lastModified ?? this.lastModified, - ); - } - - bool get isEmpty => - title.isEmpty && - description.isEmpty && - content.isEmpty && - attachments.isEmpty; -} - -class ArticleDraftModel { - final String id; - final String title; - final String description; - final String content; - final int visibility; - final DateTime lastModified; - - ArticleDraftModel({ - required this.id, - required this.title, - required this.description, - required this.content, - required this.visibility, - required this.lastModified, - }); - - Map toJson() => { - 'id': id, - 'title': title, - 'description': description, - 'content': content, - 'visibility': visibility, - 'lastModified': lastModified.toIso8601String(), - }; - - factory ArticleDraftModel.fromJson(Map json) => ArticleDraftModel( - id: json['id'] as String, - title: json['title'] as String? ?? '', - description: json['description'] as String? ?? '', - content: json['content'] as String? ?? '', - visibility: json['visibility'] as int? ?? 0, - lastModified: DateTime.parse(json['lastModified'] as String), - ); - - factory ArticleDraftModel.fromDbRow(ArticleDraft row) => ArticleDraftModel( - id: row.id, - title: row.title, - description: row.description, - content: row.content, - visibility: row.visibility, - lastModified: row.lastModified, - ); - - ArticleDraftsCompanion toDbCompanion() => ArticleDraftsCompanion( - id: Value(id), - title: Value(title), - description: Value(description), - content: Value(content), - visibility: Value(visibility), - lastModified: Value(lastModified), - ); - - ArticleDraftModel copyWith({ - String? id, - String? title, - String? description, - String? content, - int? visibility, - DateTime? lastModified, - }) { - return ArticleDraftModel( - id: id ?? this.id, - title: title ?? this.title, - description: description ?? this.description, - content: content ?? this.content, - visibility: visibility ?? this.visibility, - lastModified: lastModified ?? this.lastModified, - ); - } - - bool get isEmpty => title.isEmpty && description.isEmpty && content.isEmpty; -} - @riverpod class ComposeStorageNotifier extends _$ComposeStorageNotifier { @override - Map build() { + Map build() { _loadDrafts(); return {}; } @@ -185,10 +18,9 @@ class ComposeStorageNotifier extends _$ComposeStorageNotifier { void _loadDrafts() async { try { final database = ref.read(databaseProvider); - final dbDrafts = await database.getAllComposeDrafts(); - final drafts = {}; - for (final dbDraft in dbDrafts) { - final draft = ComposeDraftModel.fromDbRow(dbDraft); + final dbDrafts = await database.getAllPostDrafts(); + final drafts = {}; + for (final draft in dbDrafts) { drafts[draft.id] = draft; } state = drafts; @@ -198,52 +30,22 @@ class ComposeStorageNotifier extends _$ComposeStorageNotifier { } } - Future saveDraft(ComposeDraftModel draft) async { - if (draft.isEmpty) { - await deleteDraft(draft.id); - return; - } - - // Upload all attachments that are not yet uploaded - final uploadedAttachments = []; - final serverUrl = ref.read(serverUrlProvider); - final token = ref.read(tokenProvider); - - for (final attachment in draft.attachments) { - if (!attachment.isOnCloud) { - try { - final completer = putMediaToCloud( - fileData: attachment, - atk: token?.token ?? '', - baseUrl: serverUrl, - ); - final uploadedFile = await completer.future; - if (uploadedFile != null) { - uploadedAttachments.add(UniversalFile.fromAttachment(uploadedFile)); - } else { - uploadedAttachments.add(attachment); - } - } catch (e) { - // If upload fails, keep the original file - uploadedAttachments.add(attachment); - } - } else { - uploadedAttachments.add(attachment); - } - } - - final updatedDraft = draft.copyWith( - attachments: uploadedAttachments, - lastModified: DateTime.now(), - ); + Future saveDraft(SnPost draft) async { + final updatedDraft = draft.copyWith(updatedAt: DateTime.now()); state = {...state, updatedDraft.id: updatedDraft}; - + try { final database = ref.read(databaseProvider); - await database.saveComposeDraft(updatedDraft.toDbCompanion()); + await database.addPostDraft( + PostDraftsCompanion( + id: Value(updatedDraft.id), + post: Value(jsonEncode(updatedDraft.toJson())), + lastModified: Value(updatedDraft.updatedAt ?? DateTime.now()), + ), + ); } catch (e) { // Revert state on error - final newState = Map.from(state); + final newState = Map.from(state); newState.remove(updatedDraft.id); state = newState; rethrow; @@ -252,13 +54,13 @@ class ComposeStorageNotifier extends _$ComposeStorageNotifier { Future deleteDraft(String id) async { final oldDraft = state[id]; - final newState = Map.from(state); + final newState = Map.from(state); newState.remove(id); state = newState; - + try { final database = ref.read(databaseProvider); - await database.deleteComposeDraft(id); + await database.deletePostDraft(id); } catch (e) { // Revert state on error if (oldDraft != null) { @@ -268,22 +70,22 @@ class ComposeStorageNotifier extends _$ComposeStorageNotifier { } } - ComposeDraftModel? getDraft(String id) { + SnPost? getDraft(String id) { return state[id]; } - List getAllDrafts() { + List getAllDrafts() { final drafts = state.values.toList(); - drafts.sort((a, b) => b.lastModified.compareTo(a.lastModified)); + drafts.sort((a, b) => b.updatedAt!.compareTo(a.updatedAt!)); return drafts; } Future clearAllDrafts() async { state = {}; - + try { final database = ref.read(databaseProvider); - await database.clearAllComposeDrafts(); + await database.clearAllPostDrafts(); } catch (e) { // If clearing fails, we might want to reload from database _loadDrafts(); @@ -291,90 +93,3 @@ class ComposeStorageNotifier extends _$ComposeStorageNotifier { } } } - -@riverpod -class ArticleStorageNotifier extends _$ArticleStorageNotifier { - @override - Map build() { - _loadDrafts(); - return {}; - } - - void _loadDrafts() async { - try { - final database = ref.read(databaseProvider); - final dbDrafts = await database.getAllArticleDrafts(); - final drafts = {}; - for (final dbDraft in dbDrafts) { - final draft = ArticleDraftModel.fromDbRow(dbDraft); - drafts[draft.id] = draft; - } - state = drafts; - } catch (e) { - // If there's an error loading drafts, start with empty state - state = {}; - } - } - - Future saveDraft(ArticleDraftModel draft) async { - if (draft.isEmpty) { - await deleteDraft(draft.id); - return; - } - - final updatedDraft = draft.copyWith(lastModified: DateTime.now()); - state = {...state, updatedDraft.id: updatedDraft}; - - try { - final database = ref.read(databaseProvider); - await database.saveArticleDraft(updatedDraft.toDbCompanion()); - } catch (e) { - // Revert state on error - final newState = Map.from(state); - newState.remove(updatedDraft.id); - state = newState; - rethrow; - } - } - - Future deleteDraft(String id) async { - final oldDraft = state[id]; - final newState = Map.from(state); - newState.remove(id); - state = newState; - - try { - final database = ref.read(databaseProvider); - await database.deleteArticleDraft(id); - } catch (e) { - // Revert state on error - if (oldDraft != null) { - state = {...state, id: oldDraft}; - } - rethrow; - } - } - - ArticleDraftModel? getDraft(String id) { - return state[id]; - } - - List getAllDrafts() { - final drafts = state.values.toList(); - drafts.sort((a, b) => b.lastModified.compareTo(a.lastModified)); - return drafts; - } - - Future clearAllDrafts() async { - state = {}; - - try { - final database = ref.read(databaseProvider); - await database.clearAllArticleDrafts(); - } catch (e) { - // If clearing fails, we might want to reload from database - _loadDrafts(); - rethrow; - } - } -} \ No newline at end of file diff --git a/lib/services/compose_storage_db.g.dart b/lib/services/compose_storage_db.g.dart index 654fafe..051438a 100644 --- a/lib/services/compose_storage_db.g.dart +++ b/lib/services/compose_storage_db.g.dart @@ -7,13 +7,13 @@ part of 'compose_storage_db.dart'; // ************************************************************************** String _$composeStorageNotifierHash() => - r'fcdb006dca44d30916a20804922e93d0caad49ca'; + r'3de7a01a93d999d45a32fb68617b77f194589686'; /// See also [ComposeStorageNotifier]. @ProviderFor(ComposeStorageNotifier) final composeStorageNotifierProvider = AutoDisposeNotifierProvider< ComposeStorageNotifier, - Map + Map >.internal( ComposeStorageNotifier.new, name: r'composeStorageNotifierProvider', @@ -25,28 +25,6 @@ final composeStorageNotifierProvider = AutoDisposeNotifierProvider< allTransitiveDependencies: null, ); -typedef _$ComposeStorageNotifier = - AutoDisposeNotifier>; -String _$articleStorageNotifierHash() => - r'21ee0f8ee87528bebf8f5f4b0b2892cd8058e230'; - -/// See also [ArticleStorageNotifier]. -@ProviderFor(ArticleStorageNotifier) -final articleStorageNotifierProvider = AutoDisposeNotifierProvider< - ArticleStorageNotifier, - Map ->.internal( - ArticleStorageNotifier.new, - name: r'articleStorageNotifierProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$articleStorageNotifierHash, - dependencies: null, - allTransitiveDependencies: null, -); - -typedef _$ArticleStorageNotifier = - AutoDisposeNotifier>; +typedef _$ComposeStorageNotifier = AutoDisposeNotifier>; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/widgets/post/compose_shared.dart b/lib/widgets/post/compose_shared.dart index 238e90c..8d25b3c 100644 --- a/lib/widgets/post/compose_shared.dart +++ b/lib/widgets/post/compose_shared.dart @@ -1,7 +1,6 @@ -import 'dart:developer'; - import 'package:collection/collection.dart'; import 'package:dio/dio.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -15,6 +14,7 @@ import 'package:island/services/compose_storage_db.dart'; import 'package:island/widgets/alert.dart'; import 'package:pasteboard/pasteboard.dart'; import 'dart:async'; +import 'dart:developer'; class ComposeState { final ValueNotifier> attachments; @@ -40,10 +40,10 @@ class ComposeState { required this.draftId, }); - void startAutoSave(WidgetRef ref) { + void startAutoSave(WidgetRef ref, {int postType = 0}) { _autoSaveTimer?.cancel(); _autoSaveTimer = Timer.periodic(const Duration(seconds: 3), (_) { - ComposeLogic.saveDraft(ref, this); + ComposeLogic.saveDraftWithoutUpload(ref, this, postType: postType); }); } @@ -96,9 +96,11 @@ class ComposeLogic { ); } - static ComposeState createStateFromDraft(ComposeDraftModel draft) { + static ComposeState createStateFromDraft(SnPost draft) { return ComposeState( - attachments: ValueNotifier>([]), + attachments: ValueNotifier>( + draft.attachments.map((e) => UniversalFile.fromAttachment(e)).toList(), + ), titleController: TextEditingController(text: draft.title), descriptionController: TextEditingController(text: draft.description), contentController: TextEditingController(text: draft.content), @@ -110,29 +112,247 @@ class ComposeLogic { ); } + static Future saveDraft(WidgetRef ref, ComposeState state, {int postType = 0}) async { + final hasContent = + state.titleController.text.trim().isNotEmpty || + state.descriptionController.text.trim().isNotEmpty || + state.contentController.text.trim().isNotEmpty; + final hasAttachments = state.attachments.value.isNotEmpty; + if (!hasContent && !hasAttachments) { + return; // Don't save empty posts + } - static Future saveDraft(WidgetRef ref, ComposeState state) async { try { - // Check if the auto-save timer is still active (widget not disposed) if (state._autoSaveTimer == null) { - return; // Widget has been disposed, don't save + return; } - final draft = ComposeDraftModel( + // Upload any local attachments first + final baseUrl = ref.watch(serverUrlProvider); + final token = await getToken(ref.watch(tokenProvider)); + if (token == null) throw ArgumentError('Token is null'); + + for (int i = 0; i < state.attachments.value.length; i++) { + final attachment = state.attachments.value[i]; + if (attachment.data is! SnCloudFile) { + try { + final cloudFile = + await putMediaToCloud( + fileData: attachment, + atk: token, + baseUrl: baseUrl, + filename: attachment.data.name ?? (postType == 1 ? 'Article media' : 'Post media'), + mimetype: + attachment.data.mimeType ?? + ComposeLogic.getMimeTypeFromFileType(attachment.type), + ).future; + if (cloudFile != null) { + // Update attachments list with cloud file + final clone = List.of(state.attachments.value); + clone[i] = UniversalFile(data: cloudFile, type: attachment.type); + state.attachments.value = clone; + } + } catch (err) { + log('[ComposeLogic] Failed to upload attachment: $err'); + // Continue with other attachments even if one fails + } + } + } + + final draft = SnPost( id: state.draftId, title: state.titleController.text, description: state.descriptionController.text, - content: state.contentController.text, - attachments: state.attachments.value, + language: null, + editedAt: null, + publishedAt: DateTime.now(), visibility: state.visibility.value, - lastModified: DateTime.now(), + content: state.contentController.text, + type: postType, + meta: null, + viewsUnique: 0, + viewsTotal: 0, + upvotes: 0, + downvotes: 0, + repliesCount: 0, + threadedPostId: null, + threadedPost: null, + repliedPostId: null, + repliedPost: null, + forwardedPostId: null, + forwardedPost: null, + attachments: + state.attachments.value + .map((e) => e.data) + .whereType() + .toList(), + publisher: SnPublisher( + id: '', + type: 0, + name: '', + nick: '', + picture: null, + background: null, + account: null, + accountId: null, + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: null, + realmId: null, + verification: null, + ), + reactions: [], + tags: [], + categories: [], + collections: [], + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: null, ); await ref.read(composeStorageNotifierProvider.notifier).saveDraft(draft); } catch (e) { log('[ComposeLogic] Failed to save draft, error: $e'); - // Silently fail for auto-save to avoid disrupting user experience + } + } + + static Future saveDraftWithoutUpload(WidgetRef ref, ComposeState state, {int postType = 0}) async { + final hasContent = + state.titleController.text.trim().isNotEmpty || + state.descriptionController.text.trim().isNotEmpty || + state.contentController.text.trim().isNotEmpty; + final hasAttachments = state.attachments.value.isNotEmpty; + + if (!hasContent && !hasAttachments) { + return; // Don't save empty posts + } + + try { + if (state._autoSaveTimer == null) { + return; + } + + final draft = SnPost( + id: state.draftId, + title: state.titleController.text, + description: state.descriptionController.text, + language: null, + editedAt: null, + publishedAt: DateTime.now(), + visibility: state.visibility.value, + content: state.contentController.text, + type: postType, + meta: null, + viewsUnique: 0, + viewsTotal: 0, + upvotes: 0, + downvotes: 0, + repliesCount: 0, + threadedPostId: null, + threadedPost: null, + repliedPostId: null, + repliedPost: null, + forwardedPostId: null, + forwardedPost: null, + attachments: + state.attachments.value + .map((e) => e.data) + .whereType() + .toList(), + publisher: SnPublisher( + id: '', + type: 0, + name: '', + nick: '', + picture: null, + background: null, + account: null, + accountId: null, + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: null, + realmId: null, + verification: null, + ), + reactions: [], + tags: [], + categories: [], + collections: [], + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: null, + ); + + await ref.read(composeStorageNotifierProvider.notifier).saveDraft(draft); + } catch (e) { + log('[ComposeLogic] Failed to save draft without upload, error: $e'); + } + } + + static Future saveDraftManually( + WidgetRef ref, + ComposeState state, + BuildContext context, + ) async { + try { + final draft = SnPost( + id: state.draftId, + title: state.titleController.text, + description: state.descriptionController.text, + language: null, + editedAt: null, + publishedAt: DateTime.now(), + visibility: state.visibility.value, + content: state.contentController.text, + type: 0, + meta: null, + viewsUnique: 0, + viewsTotal: 0, + upvotes: 0, + downvotes: 0, + repliesCount: 0, + threadedPostId: null, + threadedPost: null, + repliedPostId: null, + repliedPost: null, + forwardedPostId: null, + forwardedPost: null, + attachments: [], // TODO: Handle attachments + publisher: SnPublisher( + id: '', + type: 0, + name: '', + nick: '', + picture: null, + background: null, + account: null, + accountId: null, + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: null, + realmId: null, + verification: null, + ), + reactions: [], + tags: [], + categories: [], + collections: [], + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: null, + ); + + await ref.read(composeStorageNotifierProvider.notifier).saveDraft(draft); + + if (context.mounted) { + showSnackBar(context, 'draftSaved'.tr()); + } + } catch (e) { + log('[ComposeLogic] Failed to save draft manually, error: $e'); + if (context.mounted) { + showSnackBar(context, 'draftSaveFailed'.tr()); + } } } @@ -146,7 +366,7 @@ class ComposeLogic { } } - static Future loadDraft(WidgetRef ref, String draftId) async { + static Future loadDraft(WidgetRef ref, String draftId) async { try { return ref .read(composeStorageNotifierProvider.notifier) @@ -282,6 +502,20 @@ class ComposeLogic { }) async { if (state.submitting.value) return; + // Don't submit empty posts (no content and no attachments) + final hasContent = + state.titleController.text.trim().isNotEmpty || + state.descriptionController.text.trim().isNotEmpty || + state.contentController.text.trim().isNotEmpty; + final hasAttachments = state.attachments.value.isNotEmpty; + + if (!hasContent && !hasAttachments) { + if (context.mounted) { + showSnackBar(context, 'postContentEmpty'.tr()); + } + return; // Don't submit empty posts + } + try { state.submitting.value = true; @@ -329,7 +563,7 @@ class ComposeLogic { if (postType == 1) { // Delete article draft await ref - .read(articleStorageNotifierProvider.notifier) + .read(composeStorageNotifierProvider.notifier) .deleteDraft(state.draftId); } else { // Delete regular post draft @@ -381,7 +615,7 @@ class ComposeLogic { if (isPaste && isModifierPressed) { handlePaste(state); } else if (isSave && isModifierPressed) { - saveDraft(ref, state); + saveDraftManually(ref, state, context); } else if (isSubmit && isModifierPressed && !state.submitting.value) { performAction( ref, diff --git a/lib/widgets/post/draft_manager.dart b/lib/widgets/post/draft_manager.dart index 1a915ec..0784d03 100644 --- a/lib/widgets/post/draft_manager.dart +++ b/lib/widgets/post/draft_manager.dart @@ -7,208 +7,168 @@ import 'package:island/services/compose_storage_db.dart'; import 'package:material_symbols_icons/symbols.dart'; class DraftManagerSheet extends HookConsumerWidget { - final bool isArticle; final Function(String draftId)? onDraftSelected; - const DraftManagerSheet({ - super.key, - this.isArticle = false, - this.onDraftSelected, - }); + const DraftManagerSheet({super.key, this.onDraftSelected}); @override Widget build(BuildContext context, WidgetRef ref) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; + final isLoading = useState(true); - final drafts = - isArticle - ? ref.watch(articleStorageNotifierProvider) - : ref.watch(composeStorageNotifierProvider); + final drafts = ref.watch(composeStorageNotifierProvider); - final sortedDrafts = useMemoized(() { - if (isArticle) { - final draftList = drafts.values.cast().toList(); - draftList.sort((a, b) => b.lastModified.compareTo(a.lastModified)); - return draftList; - } else { - final draftList = drafts.values.cast().toList(); - draftList.sort((a, b) => b.lastModified.compareTo(a.lastModified)); - return draftList; - } + // Track loading state based on drafts being loaded + useEffect(() { + // Set loading to false after drafts are loaded + // We consider drafts loaded when the provider has been initialized + Future.microtask(() { + if (isLoading.value) { + isLoading.value = false; + } + }); + return null; }, [drafts]); + final sortedDrafts = useMemoized( + () { + final draftList = drafts.values.toList(); + draftList.sort((a, b) => b.updatedAt!.compareTo(a.updatedAt!)); + return draftList; + }, + [ + drafts.length, + drafts.values.map((e) => e.updatedAt!.millisecondsSinceEpoch).join(), + ], + ); + return Scaffold( - appBar: AppBar( - title: Text(isArticle ? 'articleDrafts'.tr() : 'postDrafts'.tr()), - ), - body: Column( - children: [ - if (sortedDrafts.isEmpty) - Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Symbols.draft, - size: 64, - color: colorScheme.onSurface.withOpacity(0.3), + appBar: AppBar(title: Text('drafts'.tr())), + body: + isLoading.value + ? const Center(child: CircularProgressIndicator()) + : Column( + children: [ + if (sortedDrafts.isEmpty) + Expanded( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Symbols.draft, + size: 64, + color: colorScheme.onSurface.withOpacity(0.3), + ), + const Gap(16), + Text( + 'noDrafts'.tr(), + 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); + }, + ); + }, + ), ), - const Gap(16), - Text( - 'noDrafts'.tr(), - style: theme.textTheme.bodyLarge?.copyWith( - color: colorScheme.onSurface.withOpacity(0.6), + if (sortedDrafts.isNotEmpty) ...[ + const Divider(), + Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Expanded( + child: OutlinedButton.icon( + onPressed: () async { + final confirmed = await showDialog( + 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()), + ), + ), + ], ), ), ], - ), - ), - ) - else - Expanded( - child: ListView.builder( - itemCount: sortedDrafts.length, - itemBuilder: (context, index) { - final draft = sortedDrafts[index]; - return _DraftItem( - draft: draft, - isArticle: isArticle, - onTap: () { - Navigator.of(context).pop(); - final draftId = - isArticle - ? (draft as ArticleDraftModel).id - : (draft as ComposeDraftModel).id; - onDraftSelected?.call(draftId); - }, - onDelete: () async { - final draftId = - isArticle - ? (draft as ArticleDraftModel).id - : (draft as ComposeDraftModel).id; - if (isArticle) { - await ref - .read(articleStorageNotifierProvider.notifier) - .deleteDraft(draftId); - } else { - await ref - .read(composeStorageNotifierProvider.notifier) - .deleteDraft(draftId); - } - }, - ); - }, - ), - ), - if (sortedDrafts.isNotEmpty) ...[ - const Divider(), - Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Expanded( - child: OutlinedButton.icon( - onPressed: () async { - final confirmed = await showDialog( - 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) { - if (isArticle) { - await ref - .read(articleStorageNotifierProvider.notifier) - .clearAllDrafts(); - } else { - await ref - .read(composeStorageNotifierProvider.notifier) - .clearAllDrafts(); - } - } - }, - icon: const Icon(Symbols.delete_sweep), - label: Text('clearAll'.tr()), - ), - ), ], ), - ), - ], - ], - ), ); } } class _DraftItem extends StatelessWidget { - final dynamic draft; // ComposeDraft or ArticleDraft - final bool isArticle; + final dynamic draft; final VoidCallback? onTap; final VoidCallback? onDelete; - const _DraftItem({ - required this.draft, - required this.isArticle, - this.onTap, - this.onDelete, - }); + const _DraftItem({required this.draft, this.onTap, this.onDelete}); @override Widget build(BuildContext context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; - final String title; - final String content; - final DateTime lastModified; - final String visibility; - - if (isArticle) { - final articleDraft = draft as ArticleDraftModel; - title = - articleDraft.title.isNotEmpty ? articleDraft.title : 'untitled'.tr(); - content = - articleDraft.content.isNotEmpty - ? articleDraft.content - : (articleDraft.description.isNotEmpty - ? articleDraft.description - : 'noContent'.tr()); - lastModified = articleDraft.lastModified; - visibility = _parseArticleVisibility(articleDraft.visibility); - } else { - final postDraft = draft as ComposeDraftModel; - title = postDraft.title.isNotEmpty ? postDraft.title : 'untitled'.tr(); - content = - postDraft.content.isNotEmpty - ? postDraft.content - : (postDraft.description.isNotEmpty - ? postDraft.description - : 'noContent'.tr()); - lastModified = postDraft.lastModified; - visibility = _parseArticleVisibility(postDraft.visibility); - } - + final title = draft.title ?? 'untitled'.tr(); + final content = draft.content ?? (draft.description ?? 'noContent'.tr()); final preview = content.length > 100 ? '${content.substring(0, 100)}...' : content; - final timeAgo = _formatTimeAgo(lastModified); + final timeAgo = _formatTimeAgo(draft.updatedAt!); + final visibility = _parseVisibility(draft.visibility); return Card( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), @@ -223,7 +183,7 @@ class _DraftItem extends StatelessWidget { Row( children: [ Icon( - isArticle ? Symbols.article : Symbols.post_add, + draft.type == 1 ? Symbols.article : Symbols.post_add, size: 20, color: colorScheme.primary, ), @@ -316,7 +276,7 @@ class _DraftItem extends StatelessWidget { } } - String _parseArticleVisibility(int visibility) { + String _parseVisibility(int visibility) { switch (visibility) { case 0: return 'public'.tr(); diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index d52c6f4..9732c05 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -162,8 +162,8 @@ class PostItem extends HookConsumerWidget { Spacer(), Text( isFullPost - ? item.publishedAt.formatSystem() - : item.publishedAt.formatRelative(context), + ? item.publishedAt?.formatSystem() ?? '' + : item.publishedAt?.formatRelative(context) ?? '', ).fontSize(11).alignment(Alignment.bottomRight), const Gap(4), ], @@ -213,12 +213,14 @@ class PostItem extends HookConsumerWidget { content: item.content!, linesMargin: item.type == 0 - ? EdgeInsets.only(bottom: 4) + ? EdgeInsets.only(bottom: 8) : null, ), // Show truncation hint if post is truncated if (item.isTruncated && !isFullPost) - _PostTruncateHint(), + _PostTruncateHint().padding( + bottom: item.attachments.isNotEmpty ? 8 : null, + ), if ((item.repliedPost != null || item.forwardedPost != null) && showReferencePost) @@ -234,7 +236,7 @@ class PostItem extends HookConsumerWidget { MediaQuery.of(context).size.width * 0.9, kWideScreenWidth - 160, ), - ).padding(top: 4), + ), // Render embed links if (item.meta?['embeds'] != null) ...((item.meta!['embeds'] as List) @@ -248,7 +250,8 @@ class PostItem extends HookConsumerWidget { MediaQuery.of(context).size.width * 0.85, kWideScreenWidth - 160, ), - ).padding(top: 4), + margin: EdgeInsets.only(top: 8), + ), )), ], ), @@ -323,7 +326,6 @@ Widget _buildReferencePost(BuildContext context, SnPost item) { final isReply = item.repliedPost != null; return Container( - margin: const EdgeInsets.only(top: 8, bottom: 8), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceVariant.withOpacity(0.5), diff --git a/lib/widgets/post/post_item_creator.dart b/lib/widgets/post/post_item_creator.dart index d27cf48..380cfd2 100644 --- a/lib/widgets/post/post_item_creator.dart +++ b/lib/widgets/post/post_item_creator.dart @@ -153,7 +153,7 @@ class PostItemCreator extends HookConsumerWidget { ), const Gap(8), Text( - item.publishedAt.formatSystem(), + item.publishedAt?.formatSystem() ?? '', style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.secondary, @@ -291,7 +291,7 @@ class PostItemCreator extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'Created: ${item.createdAt.formatSystem()}', + 'Created: ${item.createdAt?.formatSystem() ?? ''}', style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.secondary,