Add asset upload models and apis
This commit is contained in:
parent
69d69d0aa4
commit
b6ade63caf
7 changed files with 536 additions and 0 deletions
137
lib/apis/record_api.dart
Normal file
137
lib/apis/record_api.dart
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:contacts_plus_plus/auxiliary.dart';
|
||||||
|
import 'package:contacts_plus_plus/models/message.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import 'package:contacts_plus_plus/clients/api_client.dart';
|
||||||
|
import 'package:contacts_plus_plus/models/records/asset_upload_data.dart';
|
||||||
|
import 'package:contacts_plus_plus/models/records/neos_db_asset.dart';
|
||||||
|
import 'package:contacts_plus_plus/models/records/preprocess_status.dart';
|
||||||
|
import 'package:contacts_plus_plus/models/records/record.dart';
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
|
||||||
|
class AssetApi {
|
||||||
|
static Future<List<Record>> getRecordsAt(ApiClient client, {required String path}) async {
|
||||||
|
final response = await client.get("/users/${client.userId}/records?path=$path");
|
||||||
|
ApiClient.checkResponse(response);
|
||||||
|
final body = jsonDecode(response.body) as List;
|
||||||
|
return body.map((e) => Record.fromMap(e)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<PreprocessStatus> preprocessRecord(ApiClient client, {required Record record}) async {
|
||||||
|
final response = await client.post(
|
||||||
|
"/users/${record.ownerId}/records/${record.id}/preprocess", body: jsonEncode(record.toMap()));
|
||||||
|
ApiClient.checkResponse(response);
|
||||||
|
final body = jsonDecode(response.body);
|
||||||
|
return PreprocessStatus.fromMap(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<PreprocessStatus> getPreprocessStatus(ApiClient client,
|
||||||
|
{required PreprocessStatus preprocessStatus}) async {
|
||||||
|
final response = await client.get(
|
||||||
|
"/users/${preprocessStatus.ownerId}/records/${preprocessStatus.recordId}/preprocess/${preprocessStatus.id}"
|
||||||
|
);
|
||||||
|
ApiClient.checkResponse(response);
|
||||||
|
final body = jsonDecode(response.body);
|
||||||
|
return PreprocessStatus.fromMap(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<AssetUploadData> beginUploadAsset(ApiClient client, {required NeosDBAsset asset}) async {
|
||||||
|
final response = await client.post("/users/${client.userId}/assets/${asset.hash}/chunks?bytes=${asset.bytes}");
|
||||||
|
ApiClient.checkResponse(response);
|
||||||
|
final body = jsonDecode(response.body);
|
||||||
|
final res = AssetUploadData.fromMap(body);
|
||||||
|
if (res.uploadState == UploadState.failed) throw body;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> upsertRecord(ApiClient client, {required Record record}) async {
|
||||||
|
final body = jsonEncode(record.toMap());
|
||||||
|
final response = await client.put("/users/${client.userId}/records/${record.id}", body: body);
|
||||||
|
ApiClient.checkResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String> uploadAsset(ApiClient client, {required NeosDBAsset asset, required Uint8List data}) async {
|
||||||
|
final request = http.MultipartRequest(
|
||||||
|
"POST",
|
||||||
|
ApiClient.buildFullUri("/users/${client.userId}/assets/${asset.hash}"),
|
||||||
|
)
|
||||||
|
..files.add(http.MultipartFile.fromBytes("file", data));
|
||||||
|
final response = await request.send();
|
||||||
|
final body = jsonDecode(await response.stream.bytesToString());
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> finishUpload(ApiClient client, {required NeosDBAsset asset}) async {
|
||||||
|
final response = await client.patch("/users/${client.userId}/assets/${asset.hash}/chunks");
|
||||||
|
ApiClient.checkResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Record> uploadFile(ApiClient client, {required File file, required String machineId}) async {
|
||||||
|
final data = await file.readAsBytes();
|
||||||
|
final asset = NeosDBAsset.fromData(data);
|
||||||
|
final assetUri = "neosdb://$machineId/${asset.hash}${extension(file.path)}";
|
||||||
|
final combinedRecordId = RecordId(id: Record.generateId(), ownerId: client.userId, isValid: true);
|
||||||
|
final record = Record(
|
||||||
|
id: 0,
|
||||||
|
recordId: combinedRecordId.id.toString(),
|
||||||
|
combinedRecordId: combinedRecordId,
|
||||||
|
assetUri: assetUri,
|
||||||
|
name: basenameWithoutExtension(file.path),
|
||||||
|
tags: [
|
||||||
|
"message_item",
|
||||||
|
"message_id:${Message.generateId()}"
|
||||||
|
],
|
||||||
|
recordType: RecordType.texture,
|
||||||
|
thumbnailUri: assetUri,
|
||||||
|
isPublic: false,
|
||||||
|
isForPatreons: false,
|
||||||
|
isListed: false,
|
||||||
|
neosDBManifest: [
|
||||||
|
asset,
|
||||||
|
],
|
||||||
|
globalVersion: 0,
|
||||||
|
localVersion: 1,
|
||||||
|
lastModifyingUserId: client.userId,
|
||||||
|
lastModifyingMachineId: machineId,
|
||||||
|
lastModificationTime: DateTime.now().toUtc(),
|
||||||
|
creationTime: DateTime.now().toUtc(),
|
||||||
|
ownerId: client.userId,
|
||||||
|
isSynced: false,
|
||||||
|
fetchedOn: DateTimeX.one,
|
||||||
|
path: '',
|
||||||
|
description: '',
|
||||||
|
manifest: [
|
||||||
|
assetUri
|
||||||
|
],
|
||||||
|
url: "neosrec://${client.userId}/${combinedRecordId.id}",
|
||||||
|
isValidOwnerId: true,
|
||||||
|
isValidRecordId: true,
|
||||||
|
visits: 0,
|
||||||
|
rating: 0,
|
||||||
|
randomOrder: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
var status = await preprocessRecord(client, record: record);
|
||||||
|
while (status.state == RecordPreprocessState.preprocessing) {
|
||||||
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
status = await getPreprocessStatus(client, preprocessStatus: status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.state != RecordPreprocessState.success) {
|
||||||
|
throw "Record Preprocessing failed: ${status.failReason}";
|
||||||
|
}
|
||||||
|
|
||||||
|
final uploadData = await beginUploadAsset(client, asset: asset);
|
||||||
|
if (uploadData.uploadState == UploadState.failed) {
|
||||||
|
throw "Asset upload failed: ${uploadData.uploadState.name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
await uploadAsset(client, asset: asset, data: data);
|
||||||
|
await finishUpload(client, asset: asset);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,3 +86,8 @@ extension Format on Duration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension DateTimeX on DateTime {
|
||||||
|
static DateTime epoch = DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
|
static DateTime one = DateTime(1);
|
||||||
|
}
|
34
lib/models/records/asset_diff.dart
Normal file
34
lib/models/records/asset_diff.dart
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
class AssetDiff {
|
||||||
|
final String hash;
|
||||||
|
final int bytes;
|
||||||
|
final Diff state;
|
||||||
|
final bool isUploaded;
|
||||||
|
|
||||||
|
const AssetDiff({required this.hash, required this.bytes, required this.state, required this.isUploaded});
|
||||||
|
|
||||||
|
factory AssetDiff.fromMap(Map map) {
|
||||||
|
return AssetDiff(
|
||||||
|
hash: map["hash"],
|
||||||
|
bytes: map["bytes"],
|
||||||
|
state: Diff.fromInt(map["state"]),
|
||||||
|
isUploaded: map["isUploaded"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Diff {
|
||||||
|
added,
|
||||||
|
unchanged,
|
||||||
|
removed;
|
||||||
|
|
||||||
|
factory Diff.fromInt(int? idx) {
|
||||||
|
return Diff.values[idx ?? 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
factory Diff.fromString(String? text) {
|
||||||
|
return Diff.values.firstWhere((element) => element.name.toLowerCase() == text?.toLowerCase(),
|
||||||
|
orElse: () => Diff.unchanged,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
46
lib/models/records/asset_upload_data.dart
Normal file
46
lib/models/records/asset_upload_data.dart
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
enum UploadState {
|
||||||
|
uploadingChunks,
|
||||||
|
finalizing,
|
||||||
|
uploaded,
|
||||||
|
failed,
|
||||||
|
unknown;
|
||||||
|
|
||||||
|
factory UploadState.fromString(String? text) {
|
||||||
|
return UploadState.values.firstWhere((element) => element.name.toLowerCase() == text?.toLowerCase(),
|
||||||
|
orElse: () => UploadState.unknown,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssetUploadData {
|
||||||
|
final String signature;
|
||||||
|
final String variant;
|
||||||
|
final String ownerId;
|
||||||
|
final int totalBytes;
|
||||||
|
final int chunkSize;
|
||||||
|
final int totalChunks;
|
||||||
|
final UploadState uploadState;
|
||||||
|
|
||||||
|
const AssetUploadData({
|
||||||
|
required this.signature,
|
||||||
|
required this.variant,
|
||||||
|
required this.ownerId,
|
||||||
|
required this.totalBytes,
|
||||||
|
required this.chunkSize,
|
||||||
|
required this.totalChunks,
|
||||||
|
required this.uploadState,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory AssetUploadData.fromMap(Map map) {
|
||||||
|
return AssetUploadData(
|
||||||
|
signature: map["signature"],
|
||||||
|
variant: map["variant"] ?? "",
|
||||||
|
ownerId: map["ownerId"] ?? "",
|
||||||
|
totalBytes: map["totalBytes"] ?? -1,
|
||||||
|
chunkSize: map["chunkSize"] ?? -1,
|
||||||
|
totalChunks: map["totalChunks"] ?? -1,
|
||||||
|
uploadState: UploadState.fromString(map["uploadStat"]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
26
lib/models/records/neos_db_asset.dart
Normal file
26
lib/models/records/neos_db_asset.dart
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
|
||||||
|
class NeosDBAsset {
|
||||||
|
final String hash;
|
||||||
|
final int bytes;
|
||||||
|
|
||||||
|
const NeosDBAsset({required this.hash, required this.bytes});
|
||||||
|
|
||||||
|
factory NeosDBAsset.fromMap(Map map) {
|
||||||
|
return NeosDBAsset(hash: map["hash"] ?? "", bytes: map["bytes"] ?? -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory NeosDBAsset.fromData(Uint8List data) {
|
||||||
|
final digest = sha256.convert(data);
|
||||||
|
return NeosDBAsset(hash: digest.toString().replaceAll("-", "").toLowerCase(), bytes: data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map toMap() {
|
||||||
|
return {
|
||||||
|
"hash": hash,
|
||||||
|
"bytes": bytes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
41
lib/models/records/preprocess_status.dart
Normal file
41
lib/models/records/preprocess_status.dart
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import 'package:contacts_plus_plus/models/records/asset_diff.dart';
|
||||||
|
|
||||||
|
enum RecordPreprocessState
|
||||||
|
{
|
||||||
|
preprocessing,
|
||||||
|
success,
|
||||||
|
failed;
|
||||||
|
|
||||||
|
factory RecordPreprocessState.fromString(String? text) {
|
||||||
|
return RecordPreprocessState.values.firstWhere((element) => element.name.toLowerCase() == text?.toLowerCase(),
|
||||||
|
orElse: () => RecordPreprocessState.failed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PreprocessStatus {
|
||||||
|
final String id;
|
||||||
|
final String ownerId;
|
||||||
|
final String recordId;
|
||||||
|
final RecordPreprocessState state;
|
||||||
|
final num progress;
|
||||||
|
final String failReason;
|
||||||
|
final List<AssetDiff> resultDiffs;
|
||||||
|
|
||||||
|
const PreprocessStatus({required this.id, required this.ownerId, required this.recordId, required this.state,
|
||||||
|
required this.progress, required this.failReason, required this.resultDiffs,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory PreprocessStatus.fromMap(Map map) {
|
||||||
|
return PreprocessStatus(
|
||||||
|
id: map["id"],
|
||||||
|
ownerId: map["ownerId"],
|
||||||
|
recordId: map["recordId"],
|
||||||
|
state: RecordPreprocessState.fromString(map["state"]),
|
||||||
|
progress: map["progress"],
|
||||||
|
failReason: map["failReason"] ?? "",
|
||||||
|
resultDiffs: (map["resultDiffs"] as List? ?? []).map((e) => AssetDiff.fromMap(e)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
247
lib/models/records/record.dart
Normal file
247
lib/models/records/record.dart
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
import 'package:contacts_plus_plus/auxiliary.dart';
|
||||||
|
import 'package:contacts_plus_plus/models/records/neos_db_asset.dart';
|
||||||
|
import 'package:contacts_plus_plus/string_formatter.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
enum RecordType {
|
||||||
|
unknown,
|
||||||
|
link,
|
||||||
|
object,
|
||||||
|
directory,
|
||||||
|
texture,
|
||||||
|
audio;
|
||||||
|
|
||||||
|
factory RecordType.fromName(String? name) {
|
||||||
|
return RecordType.values.firstWhere((element) => element.name.toLowerCase() == name?.toLowerCase().trim(), orElse: () => RecordType.unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RecordId {
|
||||||
|
final String? id;
|
||||||
|
final String? ownerId;
|
||||||
|
final bool isValid;
|
||||||
|
|
||||||
|
const RecordId({required this.id, required this.ownerId, required this.isValid});
|
||||||
|
|
||||||
|
factory RecordId.fromMap(Map? map) {
|
||||||
|
return RecordId(id: map?["id"], ownerId: map?["ownerId"], isValid: map?["isValid"] ?? false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map toMap() {
|
||||||
|
return {
|
||||||
|
"id": id,
|
||||||
|
"ownerId": ownerId,
|
||||||
|
"isValid": isValid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Record {
|
||||||
|
final int id;
|
||||||
|
final RecordId combinedRecordId;
|
||||||
|
final String recordId;
|
||||||
|
final String ownerId;
|
||||||
|
final String assetUri;
|
||||||
|
final int globalVersion;
|
||||||
|
final int localVersion;
|
||||||
|
final String lastModifyingUserId;
|
||||||
|
final String lastModifyingMachineId;
|
||||||
|
final bool isSynced;
|
||||||
|
final DateTime fetchedOn;
|
||||||
|
final String name;
|
||||||
|
final FormatNode formattedName;
|
||||||
|
final String description;
|
||||||
|
final RecordType recordType;
|
||||||
|
final List<String> tags;
|
||||||
|
final String path;
|
||||||
|
final String thumbnailUri;
|
||||||
|
final bool isPublic;
|
||||||
|
final bool isForPatreons;
|
||||||
|
final bool isListed;
|
||||||
|
final DateTime lastModificationTime;
|
||||||
|
final DateTime creationTime;
|
||||||
|
final int visits;
|
||||||
|
final int rating;
|
||||||
|
final int randomOrder;
|
||||||
|
final List<String> manifest;
|
||||||
|
final List<NeosDBAsset> neosDBManifest;
|
||||||
|
final String url;
|
||||||
|
final bool isValidOwnerId;
|
||||||
|
final bool isValidRecordId;
|
||||||
|
|
||||||
|
Record({
|
||||||
|
required this.id,
|
||||||
|
required this.combinedRecordId,
|
||||||
|
required this.recordId,
|
||||||
|
required this.isSynced,
|
||||||
|
required this.fetchedOn,
|
||||||
|
required this.path,
|
||||||
|
required this.ownerId,
|
||||||
|
required this.assetUri,
|
||||||
|
required this.name,
|
||||||
|
required this.description,
|
||||||
|
required this.tags,
|
||||||
|
required this.recordType,
|
||||||
|
required this.thumbnailUri,
|
||||||
|
required this.isPublic,
|
||||||
|
required this.isListed,
|
||||||
|
required this.isForPatreons,
|
||||||
|
required this.lastModificationTime,
|
||||||
|
required this.neosDBManifest,
|
||||||
|
required this.lastModifyingUserId,
|
||||||
|
required this.lastModifyingMachineId,
|
||||||
|
required this.creationTime,
|
||||||
|
required this.manifest,
|
||||||
|
required this.url,
|
||||||
|
required this.isValidOwnerId,
|
||||||
|
required this.isValidRecordId,
|
||||||
|
required this.globalVersion,
|
||||||
|
required this.localVersion,
|
||||||
|
required this.visits,
|
||||||
|
required this.rating,
|
||||||
|
required this.randomOrder,
|
||||||
|
}) : formattedName = FormatNode.fromText(name);
|
||||||
|
|
||||||
|
factory Record.fromMap(Map map) {
|
||||||
|
return Record(
|
||||||
|
id: map["id"] ?? 0,
|
||||||
|
combinedRecordId: RecordId.fromMap(map["combinedRecordId"]),
|
||||||
|
recordId: map["recordId"],
|
||||||
|
ownerId: map["ownerId"] ?? "",
|
||||||
|
assetUri: map["assetUri"] ?? "",
|
||||||
|
globalVersion: map["globalVersion"] ?? 0,
|
||||||
|
localVersion: map["localVersion"] ?? 0,
|
||||||
|
name: map["name"] ?? "",
|
||||||
|
description: map["description"] ?? "",
|
||||||
|
tags: (map["tags"] as List? ?? []).map((e) => e.toString()).toList(),
|
||||||
|
recordType: RecordType.fromName(map["recordType"]),
|
||||||
|
thumbnailUri: map["thumbnailUri"] ?? "",
|
||||||
|
isPublic: map["isPublic"] ?? false,
|
||||||
|
isForPatreons: map["isForPatreons"] ?? false,
|
||||||
|
isListed: map["isListed"] ?? false,
|
||||||
|
lastModificationTime: DateTime.tryParse(map["lastModificationTime"]) ?? DateTimeX.epoch,
|
||||||
|
neosDBManifest: (map["neosDBManifest"] as List? ?? []).map((e) => NeosDBAsset.fromMap(e)).toList(),
|
||||||
|
lastModifyingUserId: map["lastModifyingUserId"] ?? "",
|
||||||
|
lastModifyingMachineId: map["lastModifyingMachineId"] ?? "",
|
||||||
|
creationTime: DateTime.tryParse(map["lastModificationTime"]) ?? DateTimeX.epoch,
|
||||||
|
isSynced: map["isSynced"] ?? false,
|
||||||
|
fetchedOn: DateTime.tryParse(map["fetchedOn"]) ?? DateTimeX.epoch,
|
||||||
|
path: map["path"] ?? "",
|
||||||
|
manifest: (map["neosDBManifest"] as List? ?? []).map((e) => e.toString()).toList(),
|
||||||
|
url: map["url"] ?? "",
|
||||||
|
isValidOwnerId: map["isValidOwnerId"] ?? "",
|
||||||
|
isValidRecordId: map["isValidRecordId"] ?? "",
|
||||||
|
visits: map["visits"] ?? 0,
|
||||||
|
rating: map["rating"] ?? 0,
|
||||||
|
randomOrder: map["randomOrder"] ?? 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Record copyWith({
|
||||||
|
int? id,
|
||||||
|
String? ownerId,
|
||||||
|
String? recordId,
|
||||||
|
String? assetUri,
|
||||||
|
int? globalVersion,
|
||||||
|
int? localVersion,
|
||||||
|
String? name,
|
||||||
|
TextSpan? formattedName,
|
||||||
|
String? description,
|
||||||
|
List<String>? tags,
|
||||||
|
RecordType? recordType,
|
||||||
|
String? thumbnailUri,
|
||||||
|
bool? isPublic,
|
||||||
|
bool? isForPatreons,
|
||||||
|
bool? isListed,
|
||||||
|
bool? isDeleted,
|
||||||
|
DateTime? lastModificationTime,
|
||||||
|
List<NeosDBAsset>? neosDBManifest,
|
||||||
|
String? lastModifyingUserId,
|
||||||
|
String? lastModifyingMachineId,
|
||||||
|
DateTime? creationTime,
|
||||||
|
RecordId? combinedRecordId,
|
||||||
|
bool? isSynced,
|
||||||
|
DateTime? fetchedOn,
|
||||||
|
String? path,
|
||||||
|
List<String>? manifest,
|
||||||
|
String? url,
|
||||||
|
bool? isValidOwnerId,
|
||||||
|
bool? isValidRecordId,
|
||||||
|
int? visits,
|
||||||
|
int? rating,
|
||||||
|
int? randomOrder,
|
||||||
|
}) {
|
||||||
|
return Record(
|
||||||
|
id: id ?? this.id,
|
||||||
|
ownerId: ownerId ?? this.ownerId,
|
||||||
|
recordId: recordId ?? this.recordId,
|
||||||
|
assetUri: assetUri ?? this.assetUri,
|
||||||
|
globalVersion: globalVersion ?? this.globalVersion,
|
||||||
|
localVersion: localVersion ?? this.localVersion,
|
||||||
|
name: name ?? this.name,
|
||||||
|
description: description ?? this.description,
|
||||||
|
tags: tags ?? this.tags,
|
||||||
|
recordType: recordType ?? this.recordType,
|
||||||
|
thumbnailUri: thumbnailUri ?? this.thumbnailUri,
|
||||||
|
isPublic: isPublic ?? this.isPublic,
|
||||||
|
isForPatreons: isForPatreons ?? this.isForPatreons,
|
||||||
|
isListed: isListed ?? this.isListed,
|
||||||
|
lastModificationTime: lastModificationTime ?? this.lastModificationTime,
|
||||||
|
neosDBManifest: neosDBManifest ?? this.neosDBManifest,
|
||||||
|
lastModifyingUserId: lastModifyingUserId ?? this.lastModifyingUserId,
|
||||||
|
lastModifyingMachineId: lastModifyingMachineId ?? this.lastModifyingMachineId,
|
||||||
|
creationTime: creationTime ?? this.creationTime,
|
||||||
|
combinedRecordId: combinedRecordId ?? this.combinedRecordId,
|
||||||
|
isSynced: isSynced ?? this.isSynced,
|
||||||
|
fetchedOn: fetchedOn ?? this.fetchedOn,
|
||||||
|
path: path ?? this.path,
|
||||||
|
manifest: manifest ?? this.manifest,
|
||||||
|
url: url ?? this.url,
|
||||||
|
isValidOwnerId: isValidOwnerId ?? this.isValidOwnerId,
|
||||||
|
isValidRecordId: isValidRecordId ?? this.isValidRecordId,
|
||||||
|
visits: visits ?? this.visits,
|
||||||
|
rating: rating ?? this.rating,
|
||||||
|
randomOrder: randomOrder ?? this.randomOrder,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map toMap() {
|
||||||
|
return {
|
||||||
|
"id": id,
|
||||||
|
"ownerId": ownerId,
|
||||||
|
"recordId": recordId,
|
||||||
|
"assetUri": assetUri,
|
||||||
|
"globalVersion": globalVersion,
|
||||||
|
"localVersion": localVersion,
|
||||||
|
"name": name,
|
||||||
|
"description": description,
|
||||||
|
"tags": tags,
|
||||||
|
"recordType": recordType.name,
|
||||||
|
"thumbnailUri": thumbnailUri,
|
||||||
|
"isPublic": isPublic,
|
||||||
|
"isForPatreons": isForPatreons,
|
||||||
|
"isListed": isListed,
|
||||||
|
"lastModificationTime": lastModificationTime.toUtc().toIso8601String(),
|
||||||
|
"neosDBManifest": neosDBManifest.map((e) => e.toMap()).toList(),
|
||||||
|
"lastModifyingUserId": lastModifyingUserId,
|
||||||
|
"lastModifyingMachineId": lastModifyingMachineId,
|
||||||
|
"creationTime": creationTime.toUtc().toIso8601String(),
|
||||||
|
"combinedRecordId": combinedRecordId.toMap(),
|
||||||
|
"isSynced": isSynced,
|
||||||
|
"fetchedOn": fetchedOn.toUtc().toIso8601String(),
|
||||||
|
"path": path,
|
||||||
|
"manifest": manifest,
|
||||||
|
"url": url,
|
||||||
|
"isValidOwnerId": isValidOwnerId,
|
||||||
|
"isValidRecordId": isValidRecordId,
|
||||||
|
"visits": visits,
|
||||||
|
"rating": rating,
|
||||||
|
"randomOrder": randomOrder,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static String generateId() {
|
||||||
|
return "R-${const Uuid().v4()}";
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue