wip backup and restore
This commit is contained in:
parent
fd8193b889
commit
4b359a7db0
36 changed files with 2230 additions and 351 deletions
|
|
@ -7,9 +7,23 @@ class Category {
|
|||
Id? id;
|
||||
String? name;
|
||||
bool? forManga;
|
||||
Category({
|
||||
this.id = Isar.autoIncrement,
|
||||
required this.name,
|
||||
required this.forManga
|
||||
});
|
||||
Category(
|
||||
{this.id = Isar.autoIncrement,
|
||||
required this.name,
|
||||
required this.forManga});
|
||||
|
||||
Category.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
forManga = json['forManga'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['name'] = name;
|
||||
data['forManga'] = forManga;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ part 'chapter.g.dart';
|
|||
class Chapter {
|
||||
Id? id;
|
||||
|
||||
int? mangaId;
|
||||
|
||||
String? name;
|
||||
|
||||
String? url;
|
||||
|
|
@ -28,6 +30,7 @@ class Chapter {
|
|||
|
||||
Chapter(
|
||||
{this.id = Isar.autoIncrement,
|
||||
required this.mangaId,
|
||||
required this.name,
|
||||
this.url = '',
|
||||
this.dateUpload = '',
|
||||
|
|
@ -36,4 +39,32 @@ class Chapter {
|
|||
this.isRead = false,
|
||||
this.lastPageRead = '',
|
||||
this.archivePath = ''});
|
||||
|
||||
Chapter.fromJson(Map<String, dynamic> json) {
|
||||
archivePath = json['archivePath'];
|
||||
dateUpload = json['dateUpload'];
|
||||
id = json['id'];
|
||||
isBookmarked = json['isBookmarked'];
|
||||
isRead = json['isRead'];
|
||||
lastPageRead = json['lastPageRead'];
|
||||
mangaId = json['mangaId'];
|
||||
name = json['name'];
|
||||
scanlator = json['scanlator'];
|
||||
url = json['url'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['archivePath'] = archivePath;
|
||||
data['dateUpload'] = dateUpload;
|
||||
data['id'] = id;
|
||||
data['isBookmarked'] = isBookmarked;
|
||||
data['isRead'] = isRead;
|
||||
data['lastPageRead'] = lastPageRead;
|
||||
data['mangaId'] = mangaId;
|
||||
data['name'] = name;
|
||||
data['scanlator'] = scanlator;
|
||||
data['url'] = url;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,18 +42,23 @@ const ChapterSchema = CollectionSchema(
|
|||
name: r'lastPageRead',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
r'mangaId': PropertySchema(
|
||||
id: 5,
|
||||
name: r'mangaId',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 6,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'scanlator': PropertySchema(
|
||||
id: 6,
|
||||
id: 7,
|
||||
name: r'scanlator',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'url': PropertySchema(
|
||||
id: 7,
|
||||
id: 8,
|
||||
name: r'url',
|
||||
type: IsarType.string,
|
||||
)
|
||||
|
|
@ -135,9 +140,10 @@ void _chapterSerialize(
|
|||
writer.writeBool(offsets[2], object.isBookmarked);
|
||||
writer.writeBool(offsets[3], object.isRead);
|
||||
writer.writeString(offsets[4], object.lastPageRead);
|
||||
writer.writeString(offsets[5], object.name);
|
||||
writer.writeString(offsets[6], object.scanlator);
|
||||
writer.writeString(offsets[7], object.url);
|
||||
writer.writeLong(offsets[5], object.mangaId);
|
||||
writer.writeString(offsets[6], object.name);
|
||||
writer.writeString(offsets[7], object.scanlator);
|
||||
writer.writeString(offsets[8], object.url);
|
||||
}
|
||||
|
||||
Chapter _chapterDeserialize(
|
||||
|
|
@ -153,9 +159,10 @@ Chapter _chapterDeserialize(
|
|||
isBookmarked: reader.readBoolOrNull(offsets[2]),
|
||||
isRead: reader.readBoolOrNull(offsets[3]),
|
||||
lastPageRead: reader.readStringOrNull(offsets[4]),
|
||||
name: reader.readStringOrNull(offsets[5]),
|
||||
scanlator: reader.readStringOrNull(offsets[6]),
|
||||
url: reader.readStringOrNull(offsets[7]),
|
||||
mangaId: reader.readLongOrNull(offsets[5]),
|
||||
name: reader.readStringOrNull(offsets[6]),
|
||||
scanlator: reader.readStringOrNull(offsets[7]),
|
||||
url: reader.readStringOrNull(offsets[8]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -178,11 +185,13 @@ P _chapterDeserializeProp<P>(
|
|||
case 4:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 5:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 6:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 7:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 8:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
|
|
@ -840,6 +849,75 @@ extension ChapterQueryFilter
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterFilterCondition> mangaIdIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'mangaId',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterFilterCondition> mangaIdIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'mangaId',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterFilterCondition> mangaIdEqualTo(
|
||||
int? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'mangaId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterFilterCondition> mangaIdGreaterThan(
|
||||
int? value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'mangaId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterFilterCondition> mangaIdLessThan(
|
||||
int? value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'mangaId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterFilterCondition> mangaIdBetween(
|
||||
int? lower,
|
||||
int? upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'mangaId',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterFilterCondition> nameIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -1359,6 +1437,18 @@ extension ChapterQuerySortBy on QueryBuilder<Chapter, Chapter, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterSortBy> sortByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterSortBy> sortByMangaIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterSortBy> sortByName() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'name', Sort.asc);
|
||||
|
|
@ -1470,6 +1560,18 @@ extension ChapterQuerySortThenBy
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterSortBy> thenByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterSortBy> thenByMangaIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QAfterSortBy> thenByName() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'name', Sort.asc);
|
||||
|
|
@ -1542,6 +1644,12 @@ extension ChapterQueryWhereDistinct
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QDistinct> distinctByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'mangaId');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, Chapter, QDistinct> distinctByName(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
|
@ -1602,6 +1710,12 @@ extension ChapterQueryProperty
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, int?, QQueryOperations> mangaIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'mangaId');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Chapter, String?, QQueryOperations> nameProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'name');
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ class Download {
|
|||
|
||||
int? chapterId;
|
||||
|
||||
int? mangaId;
|
||||
|
||||
int? succeeded;
|
||||
|
||||
int? failed;
|
||||
|
|
@ -27,6 +29,7 @@ class Download {
|
|||
Download({
|
||||
this.id = Isar.autoIncrement,
|
||||
required this.chapterId,
|
||||
required this.mangaId,
|
||||
required this.succeeded,
|
||||
required this.failed,
|
||||
required this.total,
|
||||
|
|
@ -34,4 +37,29 @@ class Download {
|
|||
required this.taskIds,
|
||||
required this.isStartDownload,
|
||||
});
|
||||
Download.fromJson(Map<String, dynamic> json) {
|
||||
chapterId = json['chapterId'];
|
||||
failed = json['failed'];
|
||||
id = json['id'];
|
||||
isDownload = json['isDownload'];
|
||||
isStartDownload = json['isStartDownload'];
|
||||
mangaId = json['mangaId'];
|
||||
succeeded = json['succeeded'];
|
||||
taskIds = json['taskIds'].cast<String>();
|
||||
total = json['total'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['chapterId'] = chapterId;
|
||||
data['failed'] = failed;
|
||||
data['id'] = id;
|
||||
data['isDownload'] = isDownload;
|
||||
data['isStartDownload'] = isStartDownload;
|
||||
data['mangaId'] = mangaId;
|
||||
data['succeeded'] = succeeded;
|
||||
data['taskIds'] = taskIds;
|
||||
data['total'] = total;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,18 +37,23 @@ const DownloadSchema = CollectionSchema(
|
|||
name: r'isStartDownload',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'succeeded': PropertySchema(
|
||||
r'mangaId': PropertySchema(
|
||||
id: 4,
|
||||
name: r'mangaId',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'succeeded': PropertySchema(
|
||||
id: 5,
|
||||
name: r'succeeded',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'taskIds': PropertySchema(
|
||||
id: 5,
|
||||
id: 6,
|
||||
name: r'taskIds',
|
||||
type: IsarType.stringList,
|
||||
),
|
||||
r'total': PropertySchema(
|
||||
id: 6,
|
||||
id: 7,
|
||||
name: r'total',
|
||||
type: IsarType.long,
|
||||
)
|
||||
|
|
@ -105,9 +110,10 @@ void _downloadSerialize(
|
|||
writer.writeLong(offsets[1], object.failed);
|
||||
writer.writeBool(offsets[2], object.isDownload);
|
||||
writer.writeBool(offsets[3], object.isStartDownload);
|
||||
writer.writeLong(offsets[4], object.succeeded);
|
||||
writer.writeStringList(offsets[5], object.taskIds);
|
||||
writer.writeLong(offsets[6], object.total);
|
||||
writer.writeLong(offsets[4], object.mangaId);
|
||||
writer.writeLong(offsets[5], object.succeeded);
|
||||
writer.writeStringList(offsets[6], object.taskIds);
|
||||
writer.writeLong(offsets[7], object.total);
|
||||
}
|
||||
|
||||
Download _downloadDeserialize(
|
||||
|
|
@ -122,9 +128,10 @@ Download _downloadDeserialize(
|
|||
id: id,
|
||||
isDownload: reader.readBoolOrNull(offsets[2]),
|
||||
isStartDownload: reader.readBoolOrNull(offsets[3]),
|
||||
succeeded: reader.readLongOrNull(offsets[4]),
|
||||
taskIds: reader.readStringList(offsets[5]),
|
||||
total: reader.readLongOrNull(offsets[6]),
|
||||
mangaId: reader.readLongOrNull(offsets[4]),
|
||||
succeeded: reader.readLongOrNull(offsets[5]),
|
||||
taskIds: reader.readStringList(offsets[6]),
|
||||
total: reader.readLongOrNull(offsets[7]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -147,8 +154,10 @@ P _downloadDeserializeProp<P>(
|
|||
case 4:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 5:
|
||||
return (reader.readStringList(offset)) as P;
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 6:
|
||||
return (reader.readStringList(offset)) as P;
|
||||
case 7:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
|
|
@ -506,6 +515,75 @@ extension DownloadQueryFilter
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterFilterCondition> mangaIdIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'mangaId',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterFilterCondition> mangaIdIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'mangaId',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterFilterCondition> mangaIdEqualTo(
|
||||
int? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'mangaId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterFilterCondition> mangaIdGreaterThan(
|
||||
int? value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'mangaId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterFilterCondition> mangaIdLessThan(
|
||||
int? value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'mangaId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterFilterCondition> mangaIdBetween(
|
||||
int? lower,
|
||||
int? upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'mangaId',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterFilterCondition> succeededIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -949,6 +1027,18 @@ extension DownloadQuerySortBy on QueryBuilder<Download, Download, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterSortBy> sortByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterSortBy> sortByMangaIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterSortBy> sortBySucceeded() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'succeeded', Sort.asc);
|
||||
|
|
@ -1036,6 +1126,18 @@ extension DownloadQuerySortThenBy
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterSortBy> thenByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterSortBy> thenByMangaIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QAfterSortBy> thenBySucceeded() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'succeeded', Sort.asc);
|
||||
|
|
@ -1087,6 +1189,12 @@ extension DownloadQueryWhereDistinct
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QDistinct> distinctByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'mangaId');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, Download, QDistinct> distinctBySucceeded() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'succeeded');
|
||||
|
|
@ -1138,6 +1246,12 @@ extension DownloadQueryProperty
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, int?, QQueryOperations> mangaIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'mangaId');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Download, int?, QQueryOperations> succeededProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'succeeded');
|
||||
|
|
|
|||
|
|
@ -6,12 +6,40 @@ part 'history.g.dart';
|
|||
@Name("History")
|
||||
class History {
|
||||
Id? id;
|
||||
|
||||
int? mangaId;
|
||||
|
||||
int? chapterId;
|
||||
|
||||
bool? isManga;
|
||||
|
||||
final chapter = IsarLink<Chapter>();
|
||||
|
||||
String? date;
|
||||
|
||||
History({
|
||||
this.id = Isar.autoIncrement,
|
||||
required this.isManga,
|
||||
required this.chapterId,
|
||||
required this.mangaId,
|
||||
required this.date,
|
||||
});
|
||||
|
||||
History.fromJson(Map<String, dynamic> json) {
|
||||
chapterId = json['chapterId'];
|
||||
date = json['date'];
|
||||
id = json['id'];
|
||||
isManga = json['isManga'];
|
||||
mangaId = json['mangaId'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['chapterId'] = chapterId;
|
||||
data['date'] = date;
|
||||
data['id'] = id;
|
||||
data['isManga'] = isManga;
|
||||
data['mangaId'] = mangaId;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,23 @@ const HistorySchema = CollectionSchema(
|
|||
name: r'History',
|
||||
id: 1676981785059398080,
|
||||
properties: {
|
||||
r'date': PropertySchema(
|
||||
r'chapterId': PropertySchema(
|
||||
id: 0,
|
||||
name: r'chapterId',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'date': PropertySchema(
|
||||
id: 1,
|
||||
name: r'date',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'isManga': PropertySchema(
|
||||
id: 2,
|
||||
name: r'isManga',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'mangaId': PropertySchema(
|
||||
id: 1,
|
||||
id: 3,
|
||||
name: r'mangaId',
|
||||
type: IsarType.long,
|
||||
)
|
||||
|
|
@ -70,8 +80,10 @@ void _historySerialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
writer.writeString(offsets[0], object.date);
|
||||
writer.writeLong(offsets[1], object.mangaId);
|
||||
writer.writeLong(offsets[0], object.chapterId);
|
||||
writer.writeString(offsets[1], object.date);
|
||||
writer.writeBool(offsets[2], object.isManga);
|
||||
writer.writeLong(offsets[3], object.mangaId);
|
||||
}
|
||||
|
||||
History _historyDeserialize(
|
||||
|
|
@ -81,9 +93,11 @@ History _historyDeserialize(
|
|||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = History(
|
||||
date: reader.readStringOrNull(offsets[0]),
|
||||
chapterId: reader.readLongOrNull(offsets[0]),
|
||||
date: reader.readStringOrNull(offsets[1]),
|
||||
id: id,
|
||||
mangaId: reader.readLongOrNull(offsets[1]),
|
||||
isManga: reader.readBoolOrNull(offsets[2]),
|
||||
mangaId: reader.readLongOrNull(offsets[3]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -96,8 +110,12 @@ P _historyDeserializeProp<P>(
|
|||
) {
|
||||
switch (propertyId) {
|
||||
case 0:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 1:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 2:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 3:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
|
|
@ -194,6 +212,75 @@ extension HistoryQueryWhere on QueryBuilder<History, History, QWhereClause> {
|
|||
|
||||
extension HistoryQueryFilter
|
||||
on QueryBuilder<History, History, QFilterCondition> {
|
||||
QueryBuilder<History, History, QAfterFilterCondition> chapterIdIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'chapterId',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> chapterIdIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'chapterId',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> chapterIdEqualTo(
|
||||
int? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'chapterId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> chapterIdGreaterThan(
|
||||
int? value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'chapterId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> chapterIdLessThan(
|
||||
int? value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'chapterId',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> chapterIdBetween(
|
||||
int? lower,
|
||||
int? upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'chapterId',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> dateIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -408,6 +495,32 @@ extension HistoryQueryFilter
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> isMangaIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'isManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> isMangaIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'isManga',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> isMangaEqualTo(
|
||||
bool? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'isManga',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterFilterCondition> mangaIdIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -498,6 +611,18 @@ extension HistoryQueryLinks
|
|||
}
|
||||
|
||||
extension HistoryQuerySortBy on QueryBuilder<History, History, QSortBy> {
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByChapterId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'chapterId', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByChapterIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'chapterId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByDate() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'date', Sort.asc);
|
||||
|
|
@ -510,6 +635,18 @@ extension HistoryQuerySortBy on QueryBuilder<History, History, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByIsMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> sortByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
|
|
@ -525,6 +662,18 @@ extension HistoryQuerySortBy on QueryBuilder<History, History, QSortBy> {
|
|||
|
||||
extension HistoryQuerySortThenBy
|
||||
on QueryBuilder<History, History, QSortThenBy> {
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByChapterId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'chapterId', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByChapterIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'chapterId', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByDate() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'date', Sort.asc);
|
||||
|
|
@ -549,6 +698,18 @@ extension HistoryQuerySortThenBy
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByIsMangaDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isManga', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QAfterSortBy> thenByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'mangaId', Sort.asc);
|
||||
|
|
@ -564,6 +725,12 @@ extension HistoryQuerySortThenBy
|
|||
|
||||
extension HistoryQueryWhereDistinct
|
||||
on QueryBuilder<History, History, QDistinct> {
|
||||
QueryBuilder<History, History, QDistinct> distinctByChapterId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'chapterId');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QDistinct> distinctByDate(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
|
@ -571,6 +738,12 @@ extension HistoryQueryWhereDistinct
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QDistinct> distinctByIsManga() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'isManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, History, QDistinct> distinctByMangaId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'mangaId');
|
||||
|
|
@ -586,12 +759,24 @@ extension HistoryQueryProperty
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, int?, QQueryOperations> chapterIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'chapterId');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, String?, QQueryOperations> dateProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'date');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, bool?, QQueryOperations> isMangaProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'isManga');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<History, int?, QQueryOperations> mangaIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'mangaId');
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ class Manga {
|
|||
String? author;
|
||||
|
||||
@enumerated
|
||||
Status status;
|
||||
late Status status;
|
||||
|
||||
bool? isManga;
|
||||
|
||||
List<String>? genre;
|
||||
|
||||
bool favorite;
|
||||
bool? favorite;
|
||||
|
||||
String? source;
|
||||
|
||||
|
|
@ -64,6 +64,50 @@ class Manga {
|
|||
this.lastRead = 0,
|
||||
this.isLocalArchive = false,
|
||||
this.customCoverImage});
|
||||
|
||||
Manga.fromJson(Map<String, dynamic> json) {
|
||||
author = json['author'];
|
||||
categories = json['categories']?.cast<int>();
|
||||
customCoverImage = json['customCoverImage']?.cast<int>();
|
||||
dateAdded = json['dateAdded'];
|
||||
description = json['description'];
|
||||
favorite = json['favorite']!;
|
||||
genre = json['genre']?.cast<String>();
|
||||
id = json['id'];
|
||||
imageUrl = json['imageUrl'];
|
||||
isLocalArchive = json['isLocalArchive'];
|
||||
isManga = json['isManga'];
|
||||
lang = json['lang'];
|
||||
lastRead = json['lastRead'];
|
||||
lastUpdate = json['lastUpdate'];
|
||||
link = json['link'];
|
||||
name = json['name'];
|
||||
source = json['source'];
|
||||
status = Status.values[json['status']];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['author'] = author;
|
||||
data['categories'] = categories;
|
||||
data['customCoverImage'] = customCoverImage;
|
||||
data['dateAdded'] = dateAdded;
|
||||
data['description'] = description;
|
||||
data['favorite'] = favorite;
|
||||
data['genre'] = genre;
|
||||
data['id'] = id;
|
||||
data['imageUrl'] = imageUrl;
|
||||
data['isLocalArchive'] = isLocalArchive;
|
||||
data['isManga'] = isManga;
|
||||
data['lang'] = lang;
|
||||
data['lastRead'] = lastRead;
|
||||
data['lastUpdate'] = lastUpdate;
|
||||
data['link'] = link;
|
||||
data['name'] = name;
|
||||
data['source'] = source;
|
||||
data['status'] = status.index;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
enum Status {
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ Manga _mangaDeserialize(
|
|||
customCoverImage: reader.readByteList(offsets[2]),
|
||||
dateAdded: reader.readLongOrNull(offsets[3]),
|
||||
description: reader.readStringOrNull(offsets[4]),
|
||||
favorite: reader.readBoolOrNull(offsets[5]) ?? false,
|
||||
favorite: reader.readBoolOrNull(offsets[5]),
|
||||
genre: reader.readStringList(offsets[6]),
|
||||
id: id,
|
||||
imageUrl: reader.readStringOrNull(offsets[7]),
|
||||
|
|
@ -274,7 +274,7 @@ P _mangaDeserializeProp<P>(
|
|||
case 4:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 5:
|
||||
return (reader.readBoolOrNull(offset) ?? false) as P;
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 6:
|
||||
return (reader.readStringList(offset)) as P;
|
||||
case 7:
|
||||
|
|
@ -1084,8 +1084,24 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> favoriteIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'favorite',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> favoriteIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'favorite',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, Manga, QAfterFilterCondition> favoriteEqualTo(
|
||||
bool value) {
|
||||
bool? value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'favorite',
|
||||
|
|
@ -2919,7 +2935,7 @@ extension MangaQueryProperty on QueryBuilder<Manga, Manga, QQueryProperty> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Manga, bool, QQueryOperations> favoriteProperty() {
|
||||
QueryBuilder<Manga, bool?, QQueryOperations> favoriteProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'favorite');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class Settings {
|
|||
Id? id;
|
||||
|
||||
@enumerated
|
||||
DisplayType displayType;
|
||||
late DisplayType displayType;
|
||||
|
||||
int? libraryFilterMangasDownloadType;
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ class Settings {
|
|||
List<Cookie>? cookiesList;
|
||||
|
||||
@enumerated
|
||||
ReaderMode defaultReaderMode;
|
||||
late ReaderMode defaultReaderMode;
|
||||
|
||||
List<PersonalReaderMode>? personalReaderModeList;
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ class Settings {
|
|||
L10nLocale? locale;
|
||||
|
||||
@enumerated
|
||||
DisplayType animeDisplayType;
|
||||
late DisplayType animeDisplayType;
|
||||
|
||||
int? libraryFilterAnimeDownloadType;
|
||||
|
||||
|
|
@ -117,17 +117,17 @@ class Settings {
|
|||
|
||||
bool? animeLibraryLocalSource;
|
||||
|
||||
SortLibraryManga? sortLibraryAnime;
|
||||
late SortLibraryManga? sortLibraryAnime;
|
||||
|
||||
int? pagePreloadAmount;
|
||||
|
||||
bool? checkForExtensionUpdates;
|
||||
|
||||
@enumerated
|
||||
ScaleType scaleType;
|
||||
late ScaleType scaleType;
|
||||
|
||||
@enumerated
|
||||
BackgroundColor backgroundColor;
|
||||
late BackgroundColor backgroundColor;
|
||||
|
||||
List<PersonalPageMode>? personalPageModeList;
|
||||
|
||||
|
|
@ -187,6 +187,208 @@ class Settings {
|
|||
this.checkForExtensionUpdates = true,
|
||||
this.backgroundColor = BackgroundColor.black,
|
||||
this.personalPageModeList});
|
||||
|
||||
Settings.fromJson(Map<String, dynamic> json) {
|
||||
animatePageTransitions = json['animatePageTransitions'];
|
||||
animeDisplayType = DisplayType.values[json['animeDisplayType']];
|
||||
animeLibraryDownloadedChapters = json['animeLibraryDownloadedChapters'];
|
||||
animeLibraryLocalSource = json['animeLibraryLocalSource'];
|
||||
animeLibraryShowCategoryTabs = json['animeLibraryShowCategoryTabs'];
|
||||
animeLibraryShowContinueReadingButton =
|
||||
json['animeLibraryShowContinueReadingButton'];
|
||||
animeLibraryShowLanguage = json['animeLibraryShowLanguage'];
|
||||
animeLibraryShowNumbersOfItems = json['animeLibraryShowNumbersOfItems'];
|
||||
autoExtensionsUpdates = json['autoExtensionsUpdates'];
|
||||
backgroundColor = BackgroundColor.values[json['backgroundColor']];
|
||||
if (json['chapterFilterBookmarkedList'] != null) {
|
||||
chapterFilterBookmarkedList =
|
||||
(json['chapterFilterBookmarkedList'] as List)
|
||||
.map((e) => ChapterFilterBookmarked.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
if (json['chapterFilterDownloadedList'] != null) {
|
||||
chapterFilterDownloadedList =
|
||||
(json['chapterFilterDownloadedList'] as List)
|
||||
.map((e) => ChapterFilterDownloaded.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
if (json['chapterFilterUnreadList'] != null) {
|
||||
chapterFilterUnreadList = (json['chapterFilterUnreadList'] as List)
|
||||
.map((e) => ChapterFilterUnread.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
if (json['chapterPageIndexList'] != null) {
|
||||
chapterPageIndexList = (json['chapterPageIndexList'] as List)
|
||||
.map((e) => ChapterPageIndex.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
if (json['chapterPageUrlsList'] != null) {
|
||||
chapterPageUrlsList = (json['chapterPageUrlsList'] as List)
|
||||
.map((e) => ChapterPageurls.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
checkForExtensionUpdates = json['checkForExtensionUpdates'];
|
||||
if (json['cookiesList'] != null) {
|
||||
cookiesList =
|
||||
(json['cookiesList'] as List).map((e) => Cookie.fromJson(e)).toList();
|
||||
}
|
||||
cropBorders = json['cropBorders'];
|
||||
dateFormat = json['dateFormat'];
|
||||
defaultReaderMode = ReaderMode.values[json['defaultReaderMode']];
|
||||
displayType = DisplayType.values[json['displayType']];
|
||||
doubleTapAnimationSpeed = json['doubleTapAnimationSpeed'];
|
||||
downloadLocation = json['downloadLocation'];
|
||||
downloadOnlyOnWifi = json['downloadOnlyOnWifi'];
|
||||
if (json['filterScanlatorList'] != null) {
|
||||
filterScanlatorList = (json['filterScanlatorList'] as List)
|
||||
.map((e) => FilterScanlator.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
flexColorSchemeBlendLevel = json['flexColorSchemeBlendLevel'];
|
||||
flexSchemeColorIndex = json['flexSchemeColorIndex'];
|
||||
id = json['id'];
|
||||
incognitoMode = json['incognitoMode'];
|
||||
libraryDownloadedChapters = json['libraryDownloadedChapters'];
|
||||
libraryFilterAnimeBookMarkedType = json['libraryFilterAnimeBookMarkedType'];
|
||||
libraryFilterAnimeDownloadType = json['libraryFilterAnimeDownloadType'];
|
||||
libraryFilterAnimeStartedType = json['libraryFilterAnimeStartedType'];
|
||||
libraryFilterAnimeUnreadType = json['libraryFilterAnimeUnreadType'];
|
||||
libraryFilterMangasBookMarkedType =
|
||||
json['libraryFilterMangasBookMarkedType'];
|
||||
libraryFilterMangasDownloadType = json['libraryFilterMangasDownloadType'];
|
||||
libraryFilterMangasStartedType = json['libraryFilterMangasStartedType'];
|
||||
libraryFilterMangasUnreadType = json['libraryFilterMangasUnreadType'];
|
||||
libraryLocalSource = json['libraryLocalSource'];
|
||||
libraryShowCategoryTabs = json['libraryShowCategoryTabs'];
|
||||
libraryShowContinueReadingButton = json['libraryShowContinueReadingButton'];
|
||||
libraryShowLanguage = json['libraryShowLanguage'];
|
||||
libraryShowNumbersOfItems = json['libraryShowNumbersOfItems'];
|
||||
locale =
|
||||
json['locale'] != null ? L10nLocale.fromJson(json['locale']) : null;
|
||||
onlyIncludePinnedSources = json['onlyIncludePinnedSources'];
|
||||
pagePreloadAmount = json['pagePreloadAmount'];
|
||||
if (json['personalPageModeList'] != null) {
|
||||
personalPageModeList = (json['personalPageModeList'] as List)
|
||||
.map((e) => PersonalPageMode.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
if (json['personalReaderModeList'] != null) {
|
||||
personalReaderModeList = (json['personalReaderModeList'] as List)
|
||||
.map((e) => PersonalReaderMode.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
pureBlackDarkMode = json['pureBlackDarkMode'];
|
||||
relativeTimesTamps = json['relativeTimesTamps'];
|
||||
saveAsCBZArchive = json['saveAsCBZArchive'];
|
||||
scaleType = ScaleType.values[json['scaleType']];
|
||||
showNSFW = json['showNSFW'];
|
||||
showPagesNumber = json['showPagesNumber'];
|
||||
if (json['sortChapterList'] != null) {
|
||||
sortChapterList = (json['sortChapterList'] as List)
|
||||
.map((e) => SortChapter.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
sortLibraryAnime = json['sortLibraryAnime'];
|
||||
sortLibraryManga = json['sortLibraryManga'] != null
|
||||
? SortLibraryManga.fromJson(json['sortLibraryManga'])
|
||||
: null;
|
||||
themeIsDark = json['themeIsDark'];
|
||||
userAgent = json['userAgent'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['animatePageTransitions'] = animatePageTransitions;
|
||||
data['animeDisplayType'] = animeDisplayType.index;
|
||||
data['animeLibraryDownloadedChapters'] = animeLibraryDownloadedChapters;
|
||||
data['animeLibraryLocalSource'] = animeLibraryLocalSource;
|
||||
data['animeLibraryShowCategoryTabs'] = animeLibraryShowCategoryTabs;
|
||||
data['animeLibraryShowContinueReadingButton'] =
|
||||
animeLibraryShowContinueReadingButton;
|
||||
data['animeLibraryShowLanguage'] = animeLibraryShowLanguage;
|
||||
data['animeLibraryShowNumbersOfItems'] = animeLibraryShowNumbersOfItems;
|
||||
data['autoExtensionsUpdates'] = autoExtensionsUpdates;
|
||||
data['backgroundColor'] = backgroundColor.index;
|
||||
if (chapterFilterBookmarkedList != null) {
|
||||
data['chapterFilterBookmarkedList'] =
|
||||
chapterFilterBookmarkedList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
if (chapterFilterDownloadedList != null) {
|
||||
data['chapterFilterDownloadedList'] =
|
||||
chapterFilterDownloadedList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
if (chapterFilterUnreadList != null) {
|
||||
data['chapterFilterUnreadList'] =
|
||||
chapterFilterUnreadList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
if (chapterPageIndexList != null) {
|
||||
data['chapterPageIndexList'] =
|
||||
chapterPageIndexList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
if (chapterPageUrlsList != null) {
|
||||
data['chapterPageUrlsList'] =
|
||||
chapterPageUrlsList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
data['checkForExtensionUpdates'] = checkForExtensionUpdates;
|
||||
data['cookiesList'] = cookiesList;
|
||||
data['cropBorders'] = cropBorders;
|
||||
data['dateFormat'] = dateFormat;
|
||||
data['defaultReaderMode'] = defaultReaderMode.index;
|
||||
data['displayType'] = displayType.index;
|
||||
data['doubleTapAnimationSpeed'] = doubleTapAnimationSpeed;
|
||||
data['downloadLocation'] = downloadLocation;
|
||||
data['downloadOnlyOnWifi'] = downloadOnlyOnWifi;
|
||||
data['filterScanlatorList'] = filterScanlatorList;
|
||||
data['flexColorSchemeBlendLevel'] = flexColorSchemeBlendLevel;
|
||||
data['flexSchemeColorIndex'] = flexSchemeColorIndex;
|
||||
data['id'] = id;
|
||||
data['incognitoMode'] = incognitoMode;
|
||||
data['libraryDownloadedChapters'] = libraryDownloadedChapters;
|
||||
data['libraryFilterAnimeBookMarkedType'] = libraryFilterAnimeBookMarkedType;
|
||||
data['libraryFilterAnimeDownloadType'] = libraryFilterAnimeDownloadType;
|
||||
data['libraryFilterAnimeStartedType'] = libraryFilterAnimeStartedType;
|
||||
data['libraryFilterAnimeUnreadType'] = libraryFilterAnimeUnreadType;
|
||||
data['libraryFilterMangasBookMarkedType'] =
|
||||
libraryFilterMangasBookMarkedType;
|
||||
data['libraryFilterMangasDownloadType'] = libraryFilterMangasDownloadType;
|
||||
data['libraryFilterMangasStartedType'] = libraryFilterMangasStartedType;
|
||||
data['libraryFilterMangasUnreadType'] = libraryFilterMangasUnreadType;
|
||||
data['libraryLocalSource'] = libraryLocalSource;
|
||||
data['libraryShowCategoryTabs'] = libraryShowCategoryTabs;
|
||||
data['libraryShowContinueReadingButton'] = libraryShowContinueReadingButton;
|
||||
data['libraryShowLanguage'] = libraryShowLanguage;
|
||||
data['libraryShowNumbersOfItems'] = libraryShowNumbersOfItems;
|
||||
if (locale != null) {
|
||||
data['locale'] = locale!.toJson();
|
||||
}
|
||||
data['onlyIncludePinnedSources'] = onlyIncludePinnedSources;
|
||||
data['pagePreloadAmount'] = pagePreloadAmount;
|
||||
if (personalPageModeList != null) {
|
||||
data['personalPageModeList'] =
|
||||
personalPageModeList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
if (personalReaderModeList != null) {
|
||||
data['personalReaderModeList'] =
|
||||
personalReaderModeList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
data['pureBlackDarkMode'] = pureBlackDarkMode;
|
||||
data['relativeTimesTamps'] = relativeTimesTamps;
|
||||
data['saveAsCBZArchive'] = saveAsCBZArchive;
|
||||
data['scaleType'] = scaleType.index;
|
||||
data['showNSFW'] = showNSFW;
|
||||
data['showPagesNumber'] = showPagesNumber;
|
||||
if (sortChapterList != null) {
|
||||
data['sortChapterList'] =
|
||||
sortChapterList!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
data['sortLibraryAnime'] = sortLibraryAnime;
|
||||
if (sortLibraryManga != null) {
|
||||
data['sortLibraryManga'] = sortLibraryManga!.toJson();
|
||||
}
|
||||
data['themeIsDark'] = themeIsDark;
|
||||
data['userAgent'] = userAgent;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
enum DisplayType {
|
||||
|
|
@ -212,6 +414,17 @@ class SortLibraryManga {
|
|||
bool? reverse;
|
||||
int? index;
|
||||
SortLibraryManga({this.reverse = false, this.index = 0});
|
||||
SortLibraryManga.fromJson(Map<String, dynamic> json) {
|
||||
index = json['index'];
|
||||
reverse = json['reverse'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['index'] = index;
|
||||
data['reverse'] = reverse;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
|
|
@ -220,6 +433,19 @@ class SortChapter {
|
|||
bool? reverse;
|
||||
int? index;
|
||||
SortChapter({this.mangaId, this.reverse = false, this.index = 1});
|
||||
SortChapter.fromJson(Map<String, dynamic> json) {
|
||||
index = json['index'];
|
||||
mangaId = json['mangaId'];
|
||||
reverse = json['reverse'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['index'] = index;
|
||||
data['mangaId'] = mangaId;
|
||||
data['reverse'] = reverse;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
|
|
@ -227,6 +453,17 @@ class ChapterFilterDownloaded {
|
|||
int? mangaId;
|
||||
int? type;
|
||||
ChapterFilterDownloaded({this.mangaId, this.type = 0});
|
||||
ChapterFilterDownloaded.fromJson(Map<String, dynamic> json) {
|
||||
mangaId = json['mangaId'];
|
||||
type = json['type'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['mangaId'] = mangaId;
|
||||
data['type'] = type;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
|
|
@ -234,6 +471,17 @@ class ChapterFilterUnread {
|
|||
int? mangaId;
|
||||
int? type;
|
||||
ChapterFilterUnread({this.mangaId, this.type = 0});
|
||||
ChapterFilterUnread.fromJson(Map<String, dynamic> json) {
|
||||
mangaId = json['mangaId'];
|
||||
type = json['type'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['mangaId'] = mangaId;
|
||||
data['type'] = type;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
|
|
@ -241,24 +489,74 @@ class ChapterFilterBookmarked {
|
|||
int? mangaId;
|
||||
int? type;
|
||||
ChapterFilterBookmarked({this.mangaId, this.type = 0});
|
||||
ChapterFilterBookmarked.fromJson(Map<String, dynamic> json) {
|
||||
mangaId = json['mangaId'];
|
||||
type = json['type'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['mangaId'] = mangaId;
|
||||
data['type'] = type;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
class ChapterPageurls {
|
||||
int? chapterId;
|
||||
List<String>? urls;
|
||||
|
||||
ChapterPageurls({this.chapterId, this.urls});
|
||||
ChapterPageurls.fromJson(Map<String, dynamic> json) {
|
||||
chapterId = json['chapterId'];
|
||||
urls = json['urls'].cast<String>();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['chapterId'] = chapterId;
|
||||
data['urls'] = urls;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
class ChapterPageIndex {
|
||||
int? chapterId;
|
||||
int? index;
|
||||
|
||||
ChapterPageIndex({this.chapterId, this.index});
|
||||
ChapterPageIndex.fromJson(Map<String, dynamic> json) {
|
||||
chapterId = json['chapterId'];
|
||||
index = json['index'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['chapterId'] = chapterId;
|
||||
data['index'] = index;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
class Cookie {
|
||||
String? idSource;
|
||||
String? cookie;
|
||||
Cookie({this.idSource, this.cookie});
|
||||
|
||||
Cookie.fromJson(Map<String, dynamic> json) {
|
||||
idSource = json['idSource'];
|
||||
cookie = json['cookie'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['idSource'] = idSource;
|
||||
data['cookie'] = cookie;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
|
|
@ -267,6 +565,19 @@ class PersonalReaderMode {
|
|||
|
||||
@enumerated
|
||||
ReaderMode readerMode = ReaderMode.vertical;
|
||||
PersonalReaderMode({this.mangaId, this.readerMode = ReaderMode.vertical});
|
||||
|
||||
PersonalReaderMode.fromJson(Map<String, dynamic> json) {
|
||||
mangaId = json['mangaId'];
|
||||
readerMode = ReaderMode.values[json['readerMode']];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['mangaId'] = mangaId;
|
||||
data['readerMode'] = readerMode.index;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
|
|
@ -275,6 +586,19 @@ class PersonalPageMode {
|
|||
|
||||
@enumerated
|
||||
PageMode pageMode = PageMode.onePage;
|
||||
PersonalPageMode({this.mangaId, this.pageMode = PageMode.onePage});
|
||||
|
||||
PersonalPageMode.fromJson(Map<String, dynamic> json) {
|
||||
mangaId = json['mangaId'];
|
||||
pageMode = PageMode.values[json['pageMode']];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['mangaId'] = mangaId;
|
||||
data['pageMode'] = pageMode.index;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
enum ReaderMode { vertical, ltr, rtl, verticalContinuous, webtoon }
|
||||
|
|
@ -285,6 +609,19 @@ enum PageMode { onePage, doubleColumm }
|
|||
class FilterScanlator {
|
||||
int? mangaId;
|
||||
List<String>? scanlators;
|
||||
|
||||
FilterScanlator({this.mangaId, this.scanlators});
|
||||
FilterScanlator.fromJson(Map<String, dynamic> json) {
|
||||
mangaId = json['mangaId'];
|
||||
scanlators = json['scanlators'].cast<String>();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['mangaId'] = mangaId;
|
||||
data['scanlators'] = scanlators;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@embedded
|
||||
|
|
@ -292,4 +629,16 @@ class L10nLocale {
|
|||
String? languageCode;
|
||||
String? countryCode;
|
||||
L10nLocale({this.languageCode, this.countryCode});
|
||||
|
||||
L10nLocale.fromJson(Map<String, dynamic> json) {
|
||||
countryCode = json['countryCode'];
|
||||
languageCode = json['languageCode'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['countryCode'] = countryCode;
|
||||
data['languageCode'] = languageCode;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7973,9 +7973,10 @@ ChapterPageurls _chapterPageurlsDeserialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = ChapterPageurls();
|
||||
object.chapterId = reader.readLongOrNull(offsets[0]);
|
||||
object.urls = reader.readStringList(offsets[1]);
|
||||
final object = ChapterPageurls(
|
||||
chapterId: reader.readLongOrNull(offsets[0]),
|
||||
urls: reader.readStringList(offsets[1]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
@ -8367,9 +8368,10 @@ ChapterPageIndex _chapterPageIndexDeserialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = ChapterPageIndex();
|
||||
object.chapterId = reader.readLongOrNull(offsets[0]);
|
||||
object.index = reader.readLongOrNull(offsets[1]);
|
||||
final object = ChapterPageIndex(
|
||||
chapterId: reader.readLongOrNull(offsets[0]),
|
||||
index: reader.readLongOrNull(offsets[1]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
@ -8604,9 +8606,10 @@ Cookie _cookieDeserialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = Cookie();
|
||||
object.cookie = reader.readStringOrNull(offsets[0]);
|
||||
object.idSource = reader.readStringOrNull(offsets[1]);
|
||||
final object = Cookie(
|
||||
cookie: reader.readStringOrNull(offsets[0]),
|
||||
idSource: reader.readStringOrNull(offsets[1]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
@ -8972,11 +8975,12 @@ PersonalReaderMode _personalReaderModeDeserialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = PersonalReaderMode();
|
||||
object.mangaId = reader.readLongOrNull(offsets[0]);
|
||||
object.readerMode = _PersonalReaderModereaderModeValueEnumMap[
|
||||
reader.readByteOrNull(offsets[1])] ??
|
||||
ReaderMode.vertical;
|
||||
final object = PersonalReaderMode(
|
||||
mangaId: reader.readLongOrNull(offsets[0]),
|
||||
readerMode: _PersonalReaderModereaderModeValueEnumMap[
|
||||
reader.readByteOrNull(offsets[1])] ??
|
||||
ReaderMode.vertical,
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
@ -9199,11 +9203,12 @@ PersonalPageMode _personalPageModeDeserialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = PersonalPageMode();
|
||||
object.mangaId = reader.readLongOrNull(offsets[0]);
|
||||
object.pageMode = _PersonalPageModepageModeValueEnumMap[
|
||||
reader.readByteOrNull(offsets[1])] ??
|
||||
PageMode.onePage;
|
||||
final object = PersonalPageMode(
|
||||
mangaId: reader.readLongOrNull(offsets[0]),
|
||||
pageMode: _PersonalPageModepageModeValueEnumMap[
|
||||
reader.readByteOrNull(offsets[1])] ??
|
||||
PageMode.onePage,
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
@ -9431,9 +9436,10 @@ FilterScanlator _filterScanlatorDeserialize(
|
|||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = FilterScanlator();
|
||||
object.mangaId = reader.readLongOrNull(offsets[0]);
|
||||
object.scanlators = reader.readStringList(offsets[1]);
|
||||
final object = FilterScanlator(
|
||||
mangaId: reader.readLongOrNull(offsets[0]),
|
||||
scanlators: reader.readStringList(offsets[1]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,24 +75,61 @@ class Source {
|
|||
this.headers = '',
|
||||
this.isManga = true,
|
||||
this.appMinVerReq = ""});
|
||||
|
||||
Source.fromJson(Map<String, dynamic> json) {
|
||||
name = json['name'];
|
||||
id = json['id'];
|
||||
apiUrl = json['apiUrl'];
|
||||
appMinVerReq = json['appMinVerReq'];
|
||||
baseUrl = json['baseUrl'];
|
||||
lang = json['lang'];
|
||||
typeSource = json['typeSource'];
|
||||
iconUrl = json['iconUrl'];
|
||||
dateFormat = json['dateFormat'];
|
||||
dateFormatLocale = json['dateFormatLocale'];
|
||||
isNsfw = json['isNsfw'];
|
||||
hasCloudflare = json['hasCloudflare'];
|
||||
headers = json['headers'];
|
||||
iconUrl = json['iconUrl'];
|
||||
id = json['id'];
|
||||
isActive = json['isActive'];
|
||||
isAdded = json['isAdded'];
|
||||
isFullData = json['isFullData'];
|
||||
isManga = json['isManga'];
|
||||
isNsfw = json['isNsfw'];
|
||||
isPinned = json['isPinned'];
|
||||
lang = json['lang'];
|
||||
lastUsed = json['lastUsed'];
|
||||
name = json['name'];
|
||||
sourceCode = json['sourceCode'];
|
||||
sourceCodeUrl = json['sourceCodeUrl'];
|
||||
apiUrl = json['apiUrl'];
|
||||
typeSource = json['typeSource'];
|
||||
version = json['version'];
|
||||
isManga = json['isManga'] ?? true;
|
||||
isFullData = json['isFullData'] ?? false;
|
||||
appMinVerReq = json['appMinVerReq'];
|
||||
versionLast = json['versionLast'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['apiUrl'] = apiUrl;
|
||||
data['appMinVerReq'] = appMinVerReq;
|
||||
data['baseUrl'] = baseUrl;
|
||||
data['dateFormat'] = dateFormat;
|
||||
data['dateFormatLocale'] = dateFormatLocale;
|
||||
data['hasCloudflare'] = hasCloudflare;
|
||||
data['headers'] = headers;
|
||||
data['iconUrl'] = iconUrl;
|
||||
data['id'] = id;
|
||||
data['isActive'] = isActive;
|
||||
data['isAdded'] = isAdded;
|
||||
data['isFullData'] = isFullData;
|
||||
data['isManga'] = isManga;
|
||||
data['isNsfw'] = isNsfw;
|
||||
data['isPinned'] = isPinned;
|
||||
data['lang'] = lang;
|
||||
data['lastUsed'] = lastUsed;
|
||||
data['name'] = name;
|
||||
data['sourceCode'] = sourceCode;
|
||||
data['sourceCodeUrl'] = sourceCodeUrl;
|
||||
data['typeSource'] = typeSource;
|
||||
data['version'] = version;
|
||||
data['versionLast'] = versionLast;
|
||||
return data;
|
||||
}
|
||||
|
||||
MSource toMSource() {
|
||||
return MSource(
|
||||
id: id,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class Track {
|
|||
int? score;
|
||||
|
||||
@enumerated
|
||||
TrackStatus status;
|
||||
late TrackStatus status;
|
||||
|
||||
int? startedReadingDate;
|
||||
|
||||
|
|
@ -45,6 +45,39 @@ class Track {
|
|||
this.startedReadingDate,
|
||||
this.finishedReadingDate,
|
||||
this.trackingUrl});
|
||||
Track.fromJson(Map<String, dynamic> json) {
|
||||
finishedReadingDate = json['finishedReadingDate'];
|
||||
id = json['id'];
|
||||
lastChapterRead = json['lastChapterRead'];
|
||||
libraryId = json['libraryId'];
|
||||
mangaId = json['mangaId'];
|
||||
mediaId = json['mediaId'];
|
||||
score = json['score'];
|
||||
startedReadingDate = json['startedReadingDate'];
|
||||
status = TrackStatus.values[json['status']];
|
||||
syncId = json['syncId'];
|
||||
title = json['title'];
|
||||
totalChapter = json['totalChapter'];
|
||||
trackingUrl = json['trackingUrl'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['finishedReadingDate'] = finishedReadingDate;
|
||||
data['id'] = id;
|
||||
data['lastChapterRead'] = lastChapterRead;
|
||||
data['libraryId'] = libraryId;
|
||||
data['mangaId'] = mangaId;
|
||||
data['mediaId'] = mediaId;
|
||||
data['score'] = score;
|
||||
data['startedReadingDate'] = startedReadingDate;
|
||||
data['status'] = status.index;
|
||||
data['syncId'] = syncId;
|
||||
data['title'] = title;
|
||||
data['totalChapter'] = totalChapter;
|
||||
data['trackingUrl'] = trackingUrl;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
enum TrackStatus {
|
||||
|
|
|
|||
|
|
@ -18,4 +18,21 @@ class TrackPreference {
|
|||
this.oAuth,
|
||||
this.prefs,
|
||||
});
|
||||
|
||||
TrackPreference.fromJson(Map<String, dynamic> json) {
|
||||
syncId = json['syncId'];
|
||||
username = json['username'];
|
||||
oAuth = json['oAuth'];
|
||||
prefs = json['prefs'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['syncId'] = syncId;
|
||||
data['username'] = username;
|
||||
data['oAuth'] = oAuth;
|
||||
data['prefs'] = prefs;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,9 @@ class AnimeStreamController {
|
|||
if (empty) {
|
||||
history = History(
|
||||
mangaId: getAnime().id,
|
||||
date: DateTime.now().millisecondsSinceEpoch.toString())
|
||||
date: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
isManga: getAnime().isManga,
|
||||
chapterId: episode.id)
|
||||
..chapter.value = episode;
|
||||
} else {
|
||||
history = (isar.historys
|
||||
|
|
|
|||
|
|
@ -253,13 +253,13 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
|
|||
height: 150,
|
||||
color: snapshot.hasData &&
|
||||
snapshot.data!.isNotEmpty &&
|
||||
snapshot.data!.first.favorite
|
||||
snapshot.data!.first.favorite!
|
||||
? Colors.black.withOpacity(0.7)
|
||||
: null,
|
||||
),
|
||||
if (snapshot.hasData &&
|
||||
snapshot.data!.isNotEmpty &&
|
||||
snapshot.data!.first.favorite)
|
||||
snapshot.data!.first.favorite!)
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
|
|
|
|||
|
|
@ -15,10 +15,7 @@ Future importArchivesFromFile(ImportArchivesFromFileRef ref, Manga? mManga,
|
|||
allowMultiple: true,
|
||||
type: FileType.custom,
|
||||
allowedExtensions: isManga
|
||||
? [
|
||||
'cbz',
|
||||
'zip',
|
||||
]
|
||||
? ['cbz', 'zip']
|
||||
: ['mp4', 'mov', 'avi', 'flv', 'wmv', 'mpeg', 'mkv']);
|
||||
if (result != null) {
|
||||
final dateNow = DateTime.now().millisecondsSinceEpoch;
|
||||
|
|
@ -53,7 +50,8 @@ Future importArchivesFromFile(ImportArchivesFromFileRef ref, Manga? mManga,
|
|||
isar.mangas.putSync(manga);
|
||||
final chapters = Chapter(
|
||||
name: isManga ? data!.$1 : name,
|
||||
archivePath: isManga ? data!.$4 : file.path)
|
||||
archivePath: isManga ? data!.$4 : file.path,
|
||||
mangaId: manga.id)
|
||||
..manga.value = manga;
|
||||
isar.chapters.putSync(chapters);
|
||||
chapters.manga.saveSync();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'local_archive.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$importArchivesFromFileHash() =>
|
||||
r'f911dfd50c20ebbfec97322dd0bf44261a025341';
|
||||
r'cbc93a01e89564117369b764d226f4943bf7ee49';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@ import 'package:isar/isar.dart';
|
|||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/providers/fetch_manga_sources.dart';
|
||||
import 'package:mangayomi/modules/main_view/providers/migration.dart';
|
||||
import 'package:mangayomi/modules/more/about/providers/check_for_update.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
import 'package:mangayomi/modules/widgets/error_text.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/router/router.dart';
|
||||
import 'package:mangayomi/utils/colors.dart';
|
||||
|
|
@ -26,236 +29,246 @@ class MainScreen extends ConsumerWidget {
|
|||
final l10n = l10nLocalizations(context)!;
|
||||
final route = GoRouter.of(context);
|
||||
ref.watch(checkForUpdateProvider(context: context));
|
||||
return Consumer(builder: (context, ref, chuld) {
|
||||
final location = ref.watch(
|
||||
routerCurrentLocationStateProvider(context),
|
||||
);
|
||||
bool isReadingScreen =
|
||||
location == '/mangareaderview' || location == '/animePlayerView';
|
||||
int currentIndex = switch (location) {
|
||||
null => 0,
|
||||
'/MangaLibrary' => 0,
|
||||
'/AnimeLibrary' => 1,
|
||||
'/history' => 2,
|
||||
'/browse' => 3,
|
||||
_ => 4,
|
||||
};
|
||||
return ref.watch(migrationProvider).when(data: (_) {
|
||||
return Consumer(builder: (context, ref, chuld) {
|
||||
final location = ref.watch(
|
||||
routerCurrentLocationStateProvider(context),
|
||||
);
|
||||
bool isReadingScreen =
|
||||
location == '/mangareaderview' || location == '/animePlayerView';
|
||||
int currentIndex = switch (location) {
|
||||
null => 0,
|
||||
'/MangaLibrary' => 0,
|
||||
'/AnimeLibrary' => 1,
|
||||
'/history' => 2,
|
||||
'/browse' => 3,
|
||||
_ => 4,
|
||||
};
|
||||
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
return Column(
|
||||
children: [
|
||||
if (!isReadingScreen)
|
||||
Material(
|
||||
child: AnimatedContainer(
|
||||
height: incognitoMode
|
||||
? Platform.isAndroid || Platform.isIOS
|
||||
? MediaQuery.of(context).padding.top * 2
|
||||
: 50
|
||||
: 0,
|
||||
curve: Curves.easeIn,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
color: primaryColor(context),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
l10n.incognito_mode,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontFamily: GoogleFonts.aBeeZee().fontFamily,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Scaffold(
|
||||
body: isTablet(context)
|
||||
? Row(
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 0),
|
||||
width: switch (isLongPressed) {
|
||||
true => 0,
|
||||
_ => switch (location) {
|
||||
null => 100,
|
||||
!= '/MangaLibrary' &&
|
||||
!= '/AnimeLibrary' &&
|
||||
!= '/history' &&
|
||||
!= '/browse' &&
|
||||
!= '/more' =>
|
||||
0,
|
||||
_ => 100,
|
||||
},
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
NavigationRailTheme(
|
||||
data: NavigationRailThemeData(
|
||||
indicatorShape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30)),
|
||||
),
|
||||
child: NavigationRail(
|
||||
labelType: NavigationRailLabelType.all,
|
||||
useIndicator: true,
|
||||
destinations: [
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.collections_bookmark),
|
||||
icon: const Icon(Icons
|
||||
.collections_bookmark_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.manga))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.video_collection),
|
||||
icon: const Icon(
|
||||
Icons.video_collection_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.anime))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(Icons.history),
|
||||
icon:
|
||||
const Icon(Icons.history_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.history))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(Icons.explore),
|
||||
icon:
|
||||
const Icon(Icons.explore_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.browse))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.more_horiz),
|
||||
icon: const Icon(
|
||||
Icons.more_horiz_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.more))),
|
||||
],
|
||||
selectedIndex: currentIndex,
|
||||
onDestinationSelected: (newIndex) {
|
||||
if (newIndex == 0) {
|
||||
route.go('/MangaLibrary');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/AnimeLibrary');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
} else if (newIndex == 3) {
|
||||
route.go('/browse');
|
||||
} else if (newIndex == 4) {
|
||||
route.go('/more');
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 7,
|
||||
top: 210,
|
||||
child: _extensionUpdateTotalNumbers(ref)),
|
||||
],
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
|
||||
return Column(
|
||||
children: [
|
||||
if (!isReadingScreen)
|
||||
Material(
|
||||
child: AnimatedContainer(
|
||||
height: incognitoMode
|
||||
? Platform.isAndroid || Platform.isIOS
|
||||
? MediaQuery.of(context).padding.top * 2
|
||||
: 50
|
||||
: 0,
|
||||
curve: Curves.easeIn,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
color: primaryColor(context),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
l10n.incognito_mode,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontFamily: GoogleFonts.aBeeZee().fontFamily,
|
||||
),
|
||||
),
|
||||
Expanded(child: child)
|
||||
],
|
||||
)
|
||||
: child,
|
||||
bottomNavigationBar: isTablet(context)
|
||||
? null
|
||||
: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 0),
|
||||
width: mediaWidth(context, 1),
|
||||
height: switch (isLongPressed) {
|
||||
true => 0,
|
||||
_ => switch (location) {
|
||||
null => null,
|
||||
!= '/MangaLibrary' &&
|
||||
!= '/AnimeLibrary' &&
|
||||
!= '/history' &&
|
||||
!= '/browse' &&
|
||||
!= '/more' =>
|
||||
0,
|
||||
_ => null,
|
||||
},
|
||||
},
|
||||
child: NavigationBarTheme(
|
||||
data: NavigationBarThemeData(
|
||||
indicatorShape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30)),
|
||||
),
|
||||
child: NavigationBar(
|
||||
animationDuration: const Duration(milliseconds: 500),
|
||||
selectedIndex: currentIndex,
|
||||
destinations: [
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.collections_bookmark),
|
||||
icon: const Icon(
|
||||
Icons.collections_bookmark_outlined),
|
||||
label: l10n.manga),
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.video_collection),
|
||||
icon:
|
||||
const Icon(Icons.video_collection_outlined),
|
||||
label: l10n.anime),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.history),
|
||||
icon: const Icon(Icons.history_outlined),
|
||||
label: l10n.history),
|
||||
Stack(
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Scaffold(
|
||||
body: isTablet(context)
|
||||
? Row(
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 0),
|
||||
width: switch (isLongPressed) {
|
||||
true => 0,
|
||||
_ => switch (location) {
|
||||
null => 100,
|
||||
!= '/MangaLibrary' &&
|
||||
!= '/AnimeLibrary' &&
|
||||
!= '/history' &&
|
||||
!= '/browse' &&
|
||||
!= '/more' =>
|
||||
0,
|
||||
_ => 100,
|
||||
},
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.explore),
|
||||
icon: const Icon(Icons.explore_outlined),
|
||||
label: l10n.browse),
|
||||
NavigationRailTheme(
|
||||
data: NavigationRailThemeData(
|
||||
indicatorShape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(30)),
|
||||
),
|
||||
child: NavigationRail(
|
||||
labelType: NavigationRailLabelType.all,
|
||||
useIndicator: true,
|
||||
destinations: [
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.collections_bookmark),
|
||||
icon: const Icon(Icons
|
||||
.collections_bookmark_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.manga))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: const Icon(
|
||||
Icons.video_collection),
|
||||
icon: const Icon(
|
||||
Icons.video_collection_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.anime))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.history),
|
||||
icon: const Icon(
|
||||
Icons.history_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.history))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.explore),
|
||||
icon: const Icon(
|
||||
Icons.explore_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.browse))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.more_horiz),
|
||||
icon: const Icon(
|
||||
Icons.more_horiz_outlined),
|
||||
label: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5),
|
||||
child: Text(l10n.more))),
|
||||
],
|
||||
selectedIndex: currentIndex,
|
||||
onDestinationSelected: (newIndex) {
|
||||
if (newIndex == 0) {
|
||||
route.go('/MangaLibrary');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/AnimeLibrary');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
} else if (newIndex == 3) {
|
||||
route.go('/browse');
|
||||
} else if (newIndex == 4) {
|
||||
route.go('/more');
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 14,
|
||||
top: 3,
|
||||
right: 7,
|
||||
top: 210,
|
||||
child: _extensionUpdateTotalNumbers(ref)),
|
||||
],
|
||||
),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.more_horiz),
|
||||
icon: const Icon(Icons.more_horiz_outlined),
|
||||
label: l10n.more),
|
||||
],
|
||||
onDestinationSelected: (newIndex) {
|
||||
if (newIndex == 0) {
|
||||
route.go('/MangaLibrary');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/AnimeLibrary');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
} else if (newIndex == 3) {
|
||||
route.go('/browse');
|
||||
} else if (newIndex == 4) {
|
||||
route.go('/more');
|
||||
}
|
||||
},
|
||||
),
|
||||
Expanded(child: child)
|
||||
],
|
||||
)
|
||||
: child,
|
||||
bottomNavigationBar: isTablet(context)
|
||||
? null
|
||||
: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 0),
|
||||
width: mediaWidth(context, 1),
|
||||
height: switch (isLongPressed) {
|
||||
true => 0,
|
||||
_ => switch (location) {
|
||||
null => null,
|
||||
!= '/MangaLibrary' &&
|
||||
!= '/AnimeLibrary' &&
|
||||
!= '/history' &&
|
||||
!= '/browse' &&
|
||||
!= '/more' =>
|
||||
0,
|
||||
_ => null,
|
||||
},
|
||||
},
|
||||
child: NavigationBarTheme(
|
||||
data: NavigationBarThemeData(
|
||||
indicatorShape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30)),
|
||||
),
|
||||
child: NavigationBar(
|
||||
animationDuration:
|
||||
const Duration(milliseconds: 500),
|
||||
selectedIndex: currentIndex,
|
||||
destinations: [
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.collections_bookmark),
|
||||
icon: const Icon(
|
||||
Icons.collections_bookmark_outlined),
|
||||
label: l10n.manga),
|
||||
NavigationDestination(
|
||||
selectedIcon:
|
||||
const Icon(Icons.video_collection),
|
||||
icon: const Icon(
|
||||
Icons.video_collection_outlined),
|
||||
label: l10n.anime),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.history),
|
||||
icon: const Icon(Icons.history_outlined),
|
||||
label: l10n.history),
|
||||
Stack(
|
||||
children: [
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.explore),
|
||||
icon: const Icon(Icons.explore_outlined),
|
||||
label: l10n.browse),
|
||||
Positioned(
|
||||
right: 14,
|
||||
top: 3,
|
||||
child: _extensionUpdateTotalNumbers(ref)),
|
||||
],
|
||||
),
|
||||
NavigationDestination(
|
||||
selectedIcon: const Icon(Icons.more_horiz),
|
||||
icon: const Icon(Icons.more_horiz_outlined),
|
||||
label: l10n.more),
|
||||
],
|
||||
onDestinationSelected: (newIndex) {
|
||||
if (newIndex == 0) {
|
||||
route.go('/MangaLibrary');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/AnimeLibrary');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
} else if (newIndex == 3) {
|
||||
route.go('/browse');
|
||||
} else if (newIndex == 4) {
|
||||
route.go('/more');
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
],
|
||||
);
|
||||
});
|
||||
}, error: (Object error, StackTrace stackTrace) {
|
||||
return ErrorText(error);
|
||||
}, loading: () {
|
||||
return const ProgressCenter();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
44
lib/modules/main_view/providers/migration.dart
Normal file
44
lib/modules/main_view/providers/migration.dart
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/download.dart';
|
||||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'migration.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<void> migration(MigrationRef ref) async {
|
||||
final chapters =
|
||||
isar.chapters.filter().idIsNotNull().mangaIdIsNull().findAllSync();
|
||||
final downloads =
|
||||
isar.downloads.filter().idIsNotNull().mangaIdIsNull().findAllSync();
|
||||
final histories = isar.historys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.chapterIdIsNull()
|
||||
.or()
|
||||
.idIsNotNull()
|
||||
.isMangaIsNull()
|
||||
.findAllSync();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
//mangaId in chapter
|
||||
for (var chapter in chapters) {
|
||||
final mangaId = chapter.manga.value!.id;
|
||||
isar.chapters.putSync(chapter..mangaId = mangaId);
|
||||
}
|
||||
//mangaId in Download
|
||||
for (var download in downloads) {
|
||||
final mangaId = download.chapter.value!.manga.value!.id;
|
||||
isar.downloads.putSync(download..mangaId = mangaId);
|
||||
}
|
||||
//chapterId and isManga in History
|
||||
for (var history in histories) {
|
||||
final chapterId = history.chapter.value!.id;
|
||||
final isManga = history.chapter.value!.manga.value!.isManga;
|
||||
isar.historys.putSync(history
|
||||
..chapterId = chapterId
|
||||
..isManga = isManga);
|
||||
}
|
||||
});
|
||||
}
|
||||
24
lib/modules/main_view/providers/migration.g.dart
Normal file
24
lib/modules/main_view/providers/migration.g.dart
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'migration.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$migrationHash() => r'c37210dc71317d8be30be363f78793ff5c9c6fd1';
|
||||
|
||||
/// See also [migration].
|
||||
@ProviderFor(migration)
|
||||
final migrationProvider = AutoDisposeFutureProvider<void>.internal(
|
||||
migration,
|
||||
name: r'migrationProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$migrationHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef MigrationRef = AutoDisposeFutureProviderRef<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
|
|
@ -373,12 +373,12 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
)),
|
||||
PopupMenuButton(itemBuilder: (context) {
|
||||
return [
|
||||
if (widget.manga!.favorite)
|
||||
if (widget.manga!.favorite!)
|
||||
PopupMenuItem<int>(
|
||||
value: 0,
|
||||
child: Text(l10n.edit_categories)),
|
||||
if (!isLocalArchive)
|
||||
if (widget.manga!.favorite)
|
||||
if (widget.manga!.favorite!)
|
||||
PopupMenuItem<int>(
|
||||
value: 1, child: Text(l10n.migrate)),
|
||||
if (!isLocalArchive)
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
)
|
||||
],
|
||||
),
|
||||
action: widget.manga.favorite
|
||||
action: widget.manga.favorite!
|
||||
? SizedBox(
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
|
|||
? DateTime.now().millisecondsSinceEpoch.toString()
|
||||
: chaps[i].dateUpload.toString(),
|
||||
scanlator: chaps[i].scanlator ?? '',
|
||||
mangaId: mangaId,
|
||||
)..manga.value = manga;
|
||||
chapters.add(chapter);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$updateMangaDetailHash() => r'634581c5e6d7c887695eaed86e920c6d8904e5f1';
|
||||
String _$updateMangaDetailHash() => r'7c528575751a4c88f3ea80edc87973dd668fba6c';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -206,19 +206,22 @@ Future<List<String>> downloadChapter(
|
|||
}
|
||||
|
||||
if (tasks.isEmpty && pageUrls.isNotEmpty) {
|
||||
final model = Download(
|
||||
savePageUrls();
|
||||
final download = Download(
|
||||
succeeded: 0,
|
||||
failed: 0,
|
||||
total: 0,
|
||||
isDownload: true,
|
||||
taskIds: pageUrls,
|
||||
isStartDownload: false,
|
||||
chapterId: chapter.id);
|
||||
chapterId: chapter.id,
|
||||
mangaId: manga.id);
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.downloads.putSync(model..chapter.value = chapter);
|
||||
isar.downloads.putSync(download..chapter.value = chapter);
|
||||
});
|
||||
} else {
|
||||
savePageUrls();
|
||||
if (isManga) {
|
||||
await FileDownloader().downloadBatch(
|
||||
tasks,
|
||||
|
|
@ -238,25 +241,25 @@ Future<List<String>> downloadChapter(
|
|||
.chapterIdEqualTo(chapter.id!)
|
||||
.isEmptySync();
|
||||
if (isEmpty) {
|
||||
final model = Download(
|
||||
succeeded: succeeded,
|
||||
failed: failed,
|
||||
total: tasks.length,
|
||||
isDownload: (succeeded == tasks.length),
|
||||
taskIds: pageUrls,
|
||||
isStartDownload: true,
|
||||
chapterId: chapter.id,
|
||||
);
|
||||
final download = Download(
|
||||
succeeded: succeeded,
|
||||
failed: failed,
|
||||
total: tasks.length,
|
||||
isDownload: (succeeded == tasks.length),
|
||||
taskIds: pageUrls,
|
||||
isStartDownload: true,
|
||||
chapterId: chapter.id,
|
||||
mangaId: manga.id);
|
||||
isar.writeTxnSync(() {
|
||||
isar.downloads.putSync(model..chapter.value = chapter);
|
||||
isar.downloads.putSync(download..chapter.value = chapter);
|
||||
});
|
||||
} else {
|
||||
final model = isar.downloads
|
||||
final download = isar.downloads
|
||||
.filter()
|
||||
.chapterIdEqualTo(chapter.id!)
|
||||
.findFirstSync()!;
|
||||
isar.writeTxnSync(() {
|
||||
isar.downloads.putSync(model
|
||||
isar.downloads.putSync(download
|
||||
..succeeded = succeeded
|
||||
..failed = failed
|
||||
..isDownload = (succeeded == tasks.length));
|
||||
|
|
@ -283,33 +286,30 @@ Future<List<String>> downloadChapter(
|
|||
.chapterIdEqualTo(chapter.id!)
|
||||
.isEmptySync();
|
||||
if (isEmpty) {
|
||||
final model = Download(
|
||||
succeeded: (progress * 100).toInt(),
|
||||
failed: 0,
|
||||
total: 100,
|
||||
isDownload: (progress == 1.0),
|
||||
taskIds: pageUrls,
|
||||
isStartDownload: true,
|
||||
chapterId: chapter.id,
|
||||
);
|
||||
final download = Download(
|
||||
succeeded: (progress * 100).toInt(),
|
||||
failed: 0,
|
||||
total: 100,
|
||||
isDownload: (progress == 1.0),
|
||||
taskIds: pageUrls,
|
||||
isStartDownload: true,
|
||||
chapterId: chapter.id,
|
||||
mangaId: manga.id);
|
||||
isar.writeTxnSync(() {
|
||||
isar.downloads.putSync(model..chapter.value = chapter);
|
||||
isar.downloads.putSync(download..chapter.value = chapter);
|
||||
});
|
||||
} else {
|
||||
final model = isar.downloads
|
||||
final download = isar.downloads
|
||||
.filter()
|
||||
.chapterIdEqualTo(chapter.id!)
|
||||
.findFirstSync()!;
|
||||
isar.writeTxnSync(() {
|
||||
isar.downloads.putSync(model
|
||||
isar.downloads.putSync(download
|
||||
..succeeded = (progress * 100).toInt()
|
||||
..failed = 0
|
||||
..isDownload = (progress == 1.0));
|
||||
});
|
||||
}
|
||||
if (progress == 1.0) {
|
||||
savePageUrls();
|
||||
}
|
||||
},
|
||||
onStatus: (status) async {
|
||||
if (status == TaskStatus.complete) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'download_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$downloadChapterHash() => r'58a9d03fdd3e4c413a33e6b0797ef7d34e21a86e';
|
||||
String _$downloadChapterHash() => r'6ae3da42911f2f4f2d382423b4063d017b7e0355';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -134,7 +134,9 @@ class ReaderController {
|
|||
if (empty) {
|
||||
history = History(
|
||||
mangaId: getManga().id,
|
||||
date: DateTime.now().millisecondsSinceEpoch.toString())
|
||||
date: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
isManga: getManga().isManga,
|
||||
chapterId: chapter.id)
|
||||
..chapter.value = chapter;
|
||||
} else {
|
||||
history = (isar.historys
|
||||
|
|
|
|||
136
lib/modules/more/backup_and_restore/backup_and_restore.dart
Normal file
136
lib/modules/more/backup_and_restore/backup_and_restore.dart
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/modules/manga/detail/widgets/chapter_filter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/modules/more/backup_and_restore/providers/backup.dart';
|
||||
import 'package:mangayomi/modules/more/backup_and_restore/providers/restore.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/utils/colors.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
|
||||
class BackupAndRestore extends ConsumerWidget {
|
||||
const BackupAndRestore({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Backup and restore"),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
final list = _getList();
|
||||
List<int> indexList = [];
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
"What do you want to backup?",
|
||||
),
|
||||
content: SizedBox(
|
||||
width: mediaWidth(context, 0.8),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTileChapterFilter(
|
||||
label: list[index],
|
||||
type: indexList.contains(index) ? 1 : 0,
|
||||
onTap: () {
|
||||
if (indexList.contains(index)) {
|
||||
setState(() {
|
||||
indexList.remove(index);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
indexList.add(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
)),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(
|
||||
l10n.cancel,
|
||||
style: TextStyle(
|
||||
color: primaryColor(context)),
|
||||
)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
String? result = await FilePicker.platform
|
||||
.getDirectoryPath();
|
||||
|
||||
if (result != null && context.mounted) {
|
||||
ref.watch(doBackUpProvider(
|
||||
list: indexList,
|
||||
path: result,
|
||||
context: context));
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
l10n.ok,
|
||||
style: TextStyle(
|
||||
color: primaryColor(context)),
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
title: const Text("Create backup"),
|
||||
subtitle: Text(
|
||||
"Can be used to restore current library",
|
||||
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
allowMultiple: false,
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['backup']);
|
||||
|
||||
if (result != null && context.mounted) {
|
||||
ref.watch(doRestoreProvider(
|
||||
path: result.files.first.path!, context: context));
|
||||
}
|
||||
},
|
||||
title: const Text("Restore backup"),
|
||||
subtitle: Text(
|
||||
"Restore library from backup file",
|
||||
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> _getList() {
|
||||
return [
|
||||
"Library entries",
|
||||
"Categories",
|
||||
"Chapters and episode",
|
||||
"Tracking",
|
||||
"History",
|
||||
"Settings",
|
||||
"Extensions"
|
||||
];
|
||||
}
|
||||
135
lib/modules/more/backup_and_restore/providers/backup.dart
Normal file
135
lib/modules/more/backup_and_restore/providers/backup.dart
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/category.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/track.dart';
|
||||
import 'package:mangayomi/models/track_preference.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
part 'backup.g.dart';
|
||||
|
||||
@riverpod
|
||||
void doBackUp(DoBackUpRef ref,
|
||||
{required List<int> list,
|
||||
required String path,
|
||||
required BuildContext context}) {
|
||||
Map<String, dynamic> datas = {};
|
||||
datas.addAll({"version": "1"});
|
||||
if (list.contains(0)) {
|
||||
final res = isar.mangas
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.favoriteEqualTo(true)
|
||||
.isLocalArchiveEqualTo(false)
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"manga": res});
|
||||
}
|
||||
if (list.contains(1)) {
|
||||
final res = isar.categorys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"categories": res});
|
||||
}
|
||||
if (list.contains(2)) {
|
||||
final res = isar.chapters
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"chapters": res});
|
||||
}
|
||||
if (list.contains(3)) {
|
||||
final res = isar.tracks
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"tracks": res});
|
||||
final res_ = isar.trackPreferences
|
||||
.filter()
|
||||
.syncIdIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"trackPreferences": res_});
|
||||
}
|
||||
if (list.contains(4)) {
|
||||
final res = isar.historys
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"history": res});
|
||||
}
|
||||
if (list.contains(5)) {
|
||||
final res = isar.settings
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"settings": res});
|
||||
}
|
||||
if (list.contains(6)) {
|
||||
final res = isar.sources
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.findAllSync()
|
||||
.map((e) => e.toJson())
|
||||
.toList();
|
||||
datas.addAll({"extensions": res});
|
||||
}
|
||||
final name =
|
||||
'mangayomi_${DateTime.now().toString().substringBefore(' ').replaceAll('-', '_')}';
|
||||
final backupFilePath = '$path/$name.backup.db';
|
||||
final file = File(backupFilePath);
|
||||
|
||||
file.writeAsStringSync(jsonEncode(datas));
|
||||
var encoder = ZipFileEncoder();
|
||||
encoder.create('$path/$name.backup');
|
||||
encoder.addFile(File(backupFilePath));
|
||||
encoder.close();
|
||||
Directory(backupFilePath).deleteSync(recursive: true);
|
||||
Navigator.pop(context);
|
||||
BotToast.showNotification(
|
||||
animationDuration: const Duration(milliseconds: 200),
|
||||
animationReverseDuration: const Duration(milliseconds: 200),
|
||||
duration: const Duration(seconds: 5),
|
||||
backButtonBehavior: BackButtonBehavior.none,
|
||||
leading: (cancel) =>
|
||||
Image.asset('assets/app_icons/icon-red.png', height: 40),
|
||||
title: (_) => const Text(
|
||||
"Backup created!",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
trailing: (_) => UnconstrainedBox(
|
||||
alignment: Alignment.topLeft,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
Share.shareXFiles([XFile('$path/$name.backup')],
|
||||
text: '$name.backup');
|
||||
},
|
||||
child: const Text('Share')),
|
||||
),
|
||||
enableSlideOff: true,
|
||||
onlyOne: true,
|
||||
crossPage: true);
|
||||
}
|
||||
190
lib/modules/more/backup_and_restore/providers/backup.g.dart
Normal file
190
lib/modules/more/backup_and_restore/providers/backup.g.dart
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'backup.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$doBackUpHash() => r'7fd1956fc443633587e33bf38efe7279518c4aa0';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// See also [doBackUp].
|
||||
@ProviderFor(doBackUp)
|
||||
const doBackUpProvider = DoBackUpFamily();
|
||||
|
||||
/// See also [doBackUp].
|
||||
class DoBackUpFamily extends Family<void> {
|
||||
/// See also [doBackUp].
|
||||
const DoBackUpFamily();
|
||||
|
||||
/// See also [doBackUp].
|
||||
DoBackUpProvider call({
|
||||
required List<int> list,
|
||||
required String path,
|
||||
required BuildContext context,
|
||||
}) {
|
||||
return DoBackUpProvider(
|
||||
list: list,
|
||||
path: path,
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
DoBackUpProvider getProviderOverride(
|
||||
covariant DoBackUpProvider provider,
|
||||
) {
|
||||
return call(
|
||||
list: provider.list,
|
||||
path: provider.path,
|
||||
context: provider.context,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'doBackUpProvider';
|
||||
}
|
||||
|
||||
/// See also [doBackUp].
|
||||
class DoBackUpProvider extends AutoDisposeProvider<void> {
|
||||
/// See also [doBackUp].
|
||||
DoBackUpProvider({
|
||||
required List<int> list,
|
||||
required String path,
|
||||
required BuildContext context,
|
||||
}) : this._internal(
|
||||
(ref) => doBackUp(
|
||||
ref as DoBackUpRef,
|
||||
list: list,
|
||||
path: path,
|
||||
context: context,
|
||||
),
|
||||
from: doBackUpProvider,
|
||||
name: r'doBackUpProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$doBackUpHash,
|
||||
dependencies: DoBackUpFamily._dependencies,
|
||||
allTransitiveDependencies: DoBackUpFamily._allTransitiveDependencies,
|
||||
list: list,
|
||||
path: path,
|
||||
context: context,
|
||||
);
|
||||
|
||||
DoBackUpProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.list,
|
||||
required this.path,
|
||||
required this.context,
|
||||
}) : super.internal();
|
||||
|
||||
final List<int> list;
|
||||
final String path;
|
||||
final BuildContext context;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
void Function(DoBackUpRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: DoBackUpProvider._internal(
|
||||
(ref) => create(ref as DoBackUpRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
list: list,
|
||||
path: path,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<void> createElement() {
|
||||
return _DoBackUpProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is DoBackUpProvider &&
|
||||
other.list == list &&
|
||||
other.path == path &&
|
||||
other.context == context;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, list.hashCode);
|
||||
hash = _SystemHash.combine(hash, path.hashCode);
|
||||
hash = _SystemHash.combine(hash, context.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin DoBackUpRef on AutoDisposeProviderRef<void> {
|
||||
/// The parameter `list` of this provider.
|
||||
List<int> get list;
|
||||
|
||||
/// The parameter `path` of this provider.
|
||||
String get path;
|
||||
|
||||
/// The parameter `context` of this provider.
|
||||
BuildContext get context;
|
||||
}
|
||||
|
||||
class _DoBackUpProviderElement extends AutoDisposeProviderElement<void>
|
||||
with DoBackUpRef {
|
||||
_DoBackUpProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
List<int> get list => (origin as DoBackUpProvider).list;
|
||||
@override
|
||||
String get path => (origin as DoBackUpProvider).path;
|
||||
@override
|
||||
BuildContext get context => (origin as DoBackUpProvider).context;
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
130
lib/modules/more/backup_and_restore/providers/restore.dart
Normal file
130
lib/modules/more/backup_and_restore/providers/restore.dart
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
import 'dart:convert';
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/category.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/history.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/track.dart';
|
||||
import 'package:mangayomi/models/track_preference.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/blend_level_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/flex_scheme_color_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/pure_black_dark_mode_state_provider.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'restore.g.dart';
|
||||
|
||||
@riverpod
|
||||
void doRestore(DoRestoreRef ref,
|
||||
{required String path, required BuildContext context}) {
|
||||
final inputStream = InputFileStream(path);
|
||||
final archive = ZipDecoder().decodeBuffer(inputStream);
|
||||
final backup = jsonDecode(utf8.decode(archive.files.first.content))
|
||||
as Map<String, dynamic>;
|
||||
if (backup['version'] == "1") {
|
||||
try {
|
||||
final manga =
|
||||
(backup["manga"] as List?)?.map((e) => Manga.fromJson(e)).toList();
|
||||
final chapters = (backup["chapters"] as List?)
|
||||
?.map((e) => Chapter.fromJson(e))
|
||||
.toList();
|
||||
final categories = (backup["categories"] as List?)
|
||||
?.map((e) => Category.fromJson(e))
|
||||
.toList();
|
||||
final track =
|
||||
(backup["tracks"] as List?)?.map((e) => Track.fromJson(e)).toList();
|
||||
final trackPreferences = (backup["trackPreferences"] as List?)
|
||||
?.map((e) => TrackPreference.fromJson(e))
|
||||
.toList();
|
||||
final history = (backup["history"] as List?)
|
||||
?.map((e) => History.fromJson(e))
|
||||
.toList();
|
||||
final settings = (backup["settings"] as List?)
|
||||
?.map((e) => Settings.fromJson(e))
|
||||
.toList();
|
||||
final extensions = (backup["extensions"] as List?)
|
||||
?.map((e) => Source.fromJson(e))
|
||||
.toList();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
isar.mangas.clearSync();
|
||||
if (manga != null) {
|
||||
isar.mangas.putAllSync(manga);
|
||||
if (chapters != null) {
|
||||
isar.chapters.clearSync();
|
||||
for (var chapter in chapters) {
|
||||
final manga = isar.mangas.getSync(chapter.mangaId!);
|
||||
if (manga != null) {
|
||||
isar.chapters.putSync(chapter..manga.value = manga);
|
||||
chapter.manga.saveSync();
|
||||
}
|
||||
}
|
||||
|
||||
isar.historys.clearSync();
|
||||
if (history != null) {
|
||||
for (var element in history) {
|
||||
final chapter = isar.chapters.getSync(element.chapterId!);
|
||||
if (chapter != null) {
|
||||
isar.historys.putSync(element..chapter.value = chapter);
|
||||
element.chapter.saveSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isar.categorys.clearSync();
|
||||
if (categories != null) {
|
||||
isar.categorys.putAllSync(categories);
|
||||
}
|
||||
}
|
||||
|
||||
isar.tracks.clearSync();
|
||||
if (track != null) {
|
||||
isar.tracks.putAllSync(track);
|
||||
}
|
||||
|
||||
isar.trackPreferences.clearSync();
|
||||
if (trackPreferences != null) {
|
||||
isar.trackPreferences.putAllSync(trackPreferences);
|
||||
}
|
||||
|
||||
isar.sources.clearSync();
|
||||
if (extensions != null) {
|
||||
isar.sources.putAllSync(extensions);
|
||||
}
|
||||
|
||||
isar.settings.clearSync();
|
||||
if (settings != null) {
|
||||
isar.settings.putAllSync(settings);
|
||||
}
|
||||
ref.invalidate(themeModeStateProvider);
|
||||
ref.invalidate(blendLevelStateProvider);
|
||||
ref.invalidate(flexSchemeColorStateProvider);
|
||||
ref.invalidate(pureBlackDarkModeStateProvider);
|
||||
ref.invalidate(l10nLocaleStateProvider);
|
||||
});
|
||||
} catch (e) {
|
||||
botToast(e.toString());
|
||||
}
|
||||
BotToast.showNotification(
|
||||
animationDuration: const Duration(milliseconds: 200),
|
||||
animationReverseDuration: const Duration(milliseconds: 200),
|
||||
duration: const Duration(seconds: 5),
|
||||
backButtonBehavior: BackButtonBehavior.none,
|
||||
leading: (_) =>
|
||||
Image.asset('assets/app_icons/icon-red.png', height: 40),
|
||||
title: (_) => const Text(
|
||||
"Backup restored!",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
enableSlideOff: true,
|
||||
onlyOne: true,
|
||||
crossPage: true);
|
||||
}
|
||||
}
|
||||
174
lib/modules/more/backup_and_restore/providers/restore.g.dart
Normal file
174
lib/modules/more/backup_and_restore/providers/restore.g.dart
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'restore.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$doRestoreHash() => r'd98ebbe829a033b9092896a76d59bf0fcf422928';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// See also [doRestore].
|
||||
@ProviderFor(doRestore)
|
||||
const doRestoreProvider = DoRestoreFamily();
|
||||
|
||||
/// See also [doRestore].
|
||||
class DoRestoreFamily extends Family<void> {
|
||||
/// See also [doRestore].
|
||||
const DoRestoreFamily();
|
||||
|
||||
/// See also [doRestore].
|
||||
DoRestoreProvider call({
|
||||
required String path,
|
||||
required BuildContext context,
|
||||
}) {
|
||||
return DoRestoreProvider(
|
||||
path: path,
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
DoRestoreProvider getProviderOverride(
|
||||
covariant DoRestoreProvider provider,
|
||||
) {
|
||||
return call(
|
||||
path: provider.path,
|
||||
context: provider.context,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'doRestoreProvider';
|
||||
}
|
||||
|
||||
/// See also [doRestore].
|
||||
class DoRestoreProvider extends AutoDisposeProvider<void> {
|
||||
/// See also [doRestore].
|
||||
DoRestoreProvider({
|
||||
required String path,
|
||||
required BuildContext context,
|
||||
}) : this._internal(
|
||||
(ref) => doRestore(
|
||||
ref as DoRestoreRef,
|
||||
path: path,
|
||||
context: context,
|
||||
),
|
||||
from: doRestoreProvider,
|
||||
name: r'doRestoreProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$doRestoreHash,
|
||||
dependencies: DoRestoreFamily._dependencies,
|
||||
allTransitiveDependencies: DoRestoreFamily._allTransitiveDependencies,
|
||||
path: path,
|
||||
context: context,
|
||||
);
|
||||
|
||||
DoRestoreProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.path,
|
||||
required this.context,
|
||||
}) : super.internal();
|
||||
|
||||
final String path;
|
||||
final BuildContext context;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
void Function(DoRestoreRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: DoRestoreProvider._internal(
|
||||
(ref) => create(ref as DoRestoreRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
path: path,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<void> createElement() {
|
||||
return _DoRestoreProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is DoRestoreProvider &&
|
||||
other.path == path &&
|
||||
other.context == context;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, path.hashCode);
|
||||
hash = _SystemHash.combine(hash, context.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin DoRestoreRef on AutoDisposeProviderRef<void> {
|
||||
/// The parameter `path` of this provider.
|
||||
String get path;
|
||||
|
||||
/// The parameter `context` of this provider.
|
||||
BuildContext get context;
|
||||
}
|
||||
|
||||
class _DoRestoreProviderElement extends AutoDisposeProviderElement<void>
|
||||
with DoRestoreRef {
|
||||
_DoRestoreProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get path => (origin as DoRestoreProvider).path;
|
||||
@override
|
||||
BuildContext get context => (origin as DoRestoreProvider).context;
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
|
|
@ -31,7 +31,7 @@ class MoreScreen extends StatelessWidget {
|
|||
const Divider(),
|
||||
// ListTile(
|
||||
// onTap: () {},
|
||||
// leading:
|
||||
// leading:
|
||||
// const SizedBox(height: 40, child: Icon(Icons.cloud_off)),
|
||||
// subtitle: const Text('Filter all entries in your library'),
|
||||
// title: const Text('Donloaded only'),
|
||||
|
|
@ -64,13 +64,13 @@ class MoreScreen extends StatelessWidget {
|
|||
// icon: Icons.history_outlined,
|
||||
// title: l10n.history,
|
||||
// ),
|
||||
// ListTile(
|
||||
// onTap: () {},
|
||||
// leading: const SizedBox(
|
||||
// height: 40,
|
||||
// child: Icon(Icons.settings_backup_restore_sharp)),
|
||||
// title: const Text('Backup and restore'),
|
||||
// ),
|
||||
ListTileWidget(
|
||||
onTap: () {
|
||||
context.push('/backupAndRestore');
|
||||
},
|
||||
icon: Icons.settings_backup_restore_sharp,
|
||||
title: 'Backup and restore',
|
||||
),
|
||||
// const Divider(
|
||||
// color: Colors.grey,
|
||||
// ),
|
||||
|
|
|
|||
|
|
@ -69,13 +69,13 @@ class MangaImageCardWidget extends ConsumerWidget {
|
|||
Container(
|
||||
color: snapshot.hasData &&
|
||||
snapshot.data!.isNotEmpty &&
|
||||
snapshot.data!.first.favorite
|
||||
snapshot.data!.first.favorite!
|
||||
? Colors.black.withOpacity(0.7)
|
||||
: null,
|
||||
),
|
||||
if (snapshot.hasData &&
|
||||
snapshot.data!.isNotEmpty &&
|
||||
snapshot.data!.first.favorite)
|
||||
snapshot.data!.first.favorite!)
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'package:mangayomi/models/source.dart';
|
|||
import 'package:mangayomi/modules/anime/anime_player_view.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/extension_detail.dart';
|
||||
import 'package:mangayomi/modules/browse/sources/sources_filter_screen.dart';
|
||||
import 'package:mangayomi/modules/more/backup_and_restore/backup_and_restore.dart';
|
||||
import 'package:mangayomi/modules/more/categories/categories_screen.dart';
|
||||
import 'package:mangayomi/modules/more/settings/downloads/downloads_screen.dart';
|
||||
import 'package:mangayomi/modules/more/settings/track/track.dart';
|
||||
|
|
@ -439,6 +440,19 @@ class RouterNotifier extends ChangeNotifier {
|
|||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: "/backupAndRestore",
|
||||
name: "backupAndRestore",
|
||||
builder: (context, state) {
|
||||
return const BackupAndRestore();
|
||||
},
|
||||
pageBuilder: (context, state) {
|
||||
return CustomTransition(
|
||||
key: state.pageKey,
|
||||
child: const BackupAndRestore(),
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue