feat/pick-cover-image-from-trackers

-ability to choose anime/manga cover image from trackers as custom image
This commit is contained in:
kodjomoustapha 2024-01-08 15:36:00 +01:00
parent 16e261ded3
commit 43be09db8f
15 changed files with 439 additions and 201 deletions

View file

@ -42,6 +42,8 @@ class Manga {
List<byte>? customCoverImage;
String? customCoverFromTracker;
@Backlink(to: "manga")
final chapters = IsarLinks<Chapter>();
@ -63,7 +65,8 @@ class Manga {
this.categories,
this.lastRead = 0,
this.isLocalArchive = false,
this.customCoverImage});
this.customCoverImage,
this.customCoverFromTracker});
Manga.fromJson(Map<String, dynamic> json) {
author = json['author'];
@ -84,6 +87,7 @@ class Manga {
name = json['name'];
source = json['source'];
status = Status.values[json['status']];
customCoverFromTracker = json['customCoverFromTracker'];
}
Map<String, dynamic> toJson() => {
@ -104,7 +108,8 @@ class Manga {
'link': link,
'name': name,
'source': source,
'status': status.index
'status': status.index,
'customCoverFromTracker': customCoverFromTracker,
};
}

View file

@ -27,78 +27,83 @@ const MangaSchema = CollectionSchema(
name: r'categories',
type: IsarType.longList,
),
r'customCoverImage': PropertySchema(
r'customCoverFromTracker': PropertySchema(
id: 2,
name: r'customCoverFromTracker',
type: IsarType.string,
),
r'customCoverImage': PropertySchema(
id: 3,
name: r'customCoverImage',
type: IsarType.byteList,
),
r'dateAdded': PropertySchema(
id: 3,
id: 4,
name: r'dateAdded',
type: IsarType.long,
),
r'description': PropertySchema(
id: 4,
id: 5,
name: r'description',
type: IsarType.string,
),
r'favorite': PropertySchema(
id: 5,
id: 6,
name: r'favorite',
type: IsarType.bool,
),
r'genre': PropertySchema(
id: 6,
id: 7,
name: r'genre',
type: IsarType.stringList,
),
r'imageUrl': PropertySchema(
id: 7,
id: 8,
name: r'imageUrl',
type: IsarType.string,
),
r'isLocalArchive': PropertySchema(
id: 8,
id: 9,
name: r'isLocalArchive',
type: IsarType.bool,
),
r'isManga': PropertySchema(
id: 9,
id: 10,
name: r'isManga',
type: IsarType.bool,
),
r'lang': PropertySchema(
id: 10,
id: 11,
name: r'lang',
type: IsarType.string,
),
r'lastRead': PropertySchema(
id: 11,
id: 12,
name: r'lastRead',
type: IsarType.long,
),
r'lastUpdate': PropertySchema(
id: 12,
id: 13,
name: r'lastUpdate',
type: IsarType.long,
),
r'link': PropertySchema(
id: 13,
id: 14,
name: r'link',
type: IsarType.string,
),
r'name': PropertySchema(
id: 14,
id: 15,
name: r'name',
type: IsarType.string,
),
r'source': PropertySchema(
id: 15,
id: 16,
name: r'source',
type: IsarType.string,
),
r'status': PropertySchema(
id: 16,
id: 17,
name: r'status',
type: IsarType.byte,
enumMap: _MangastatusEnumValueMap,
@ -144,6 +149,12 @@ int _mangaEstimateSize(
bytesCount += 3 + value.length * 8;
}
}
{
final value = object.customCoverFromTracker;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
{
final value = object.customCoverImage;
if (value != null) {
@ -209,21 +220,22 @@ void _mangaSerialize(
) {
writer.writeString(offsets[0], object.author);
writer.writeLongList(offsets[1], object.categories);
writer.writeByteList(offsets[2], object.customCoverImage);
writer.writeLong(offsets[3], object.dateAdded);
writer.writeString(offsets[4], object.description);
writer.writeBool(offsets[5], object.favorite);
writer.writeStringList(offsets[6], object.genre);
writer.writeString(offsets[7], object.imageUrl);
writer.writeBool(offsets[8], object.isLocalArchive);
writer.writeBool(offsets[9], object.isManga);
writer.writeString(offsets[10], object.lang);
writer.writeLong(offsets[11], object.lastRead);
writer.writeLong(offsets[12], object.lastUpdate);
writer.writeString(offsets[13], object.link);
writer.writeString(offsets[14], object.name);
writer.writeString(offsets[15], object.source);
writer.writeByte(offsets[16], object.status.index);
writer.writeString(offsets[2], object.customCoverFromTracker);
writer.writeByteList(offsets[3], object.customCoverImage);
writer.writeLong(offsets[4], object.dateAdded);
writer.writeString(offsets[5], object.description);
writer.writeBool(offsets[6], object.favorite);
writer.writeStringList(offsets[7], object.genre);
writer.writeString(offsets[8], object.imageUrl);
writer.writeBool(offsets[9], object.isLocalArchive);
writer.writeBool(offsets[10], object.isManga);
writer.writeString(offsets[11], object.lang);
writer.writeLong(offsets[12], object.lastRead);
writer.writeLong(offsets[13], object.lastUpdate);
writer.writeString(offsets[14], object.link);
writer.writeString(offsets[15], object.name);
writer.writeString(offsets[16], object.source);
writer.writeByte(offsets[17], object.status.index);
}
Manga _mangaDeserialize(
@ -235,22 +247,23 @@ Manga _mangaDeserialize(
final object = Manga(
author: reader.readStringOrNull(offsets[0]),
categories: reader.readLongList(offsets[1]),
customCoverImage: reader.readByteList(offsets[2]),
dateAdded: reader.readLongOrNull(offsets[3]),
description: reader.readStringOrNull(offsets[4]),
favorite: reader.readBoolOrNull(offsets[5]),
genre: reader.readStringList(offsets[6]),
customCoverFromTracker: reader.readStringOrNull(offsets[2]),
customCoverImage: reader.readByteList(offsets[3]),
dateAdded: reader.readLongOrNull(offsets[4]),
description: reader.readStringOrNull(offsets[5]),
favorite: reader.readBoolOrNull(offsets[6]),
genre: reader.readStringList(offsets[7]),
id: id,
imageUrl: reader.readStringOrNull(offsets[7]),
isLocalArchive: reader.readBoolOrNull(offsets[8]),
isManga: reader.readBoolOrNull(offsets[9]),
lang: reader.readStringOrNull(offsets[10]),
lastRead: reader.readLongOrNull(offsets[11]),
lastUpdate: reader.readLongOrNull(offsets[12]),
link: reader.readStringOrNull(offsets[13]),
name: reader.readStringOrNull(offsets[14]),
source: reader.readStringOrNull(offsets[15]),
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[16])] ??
imageUrl: reader.readStringOrNull(offsets[8]),
isLocalArchive: reader.readBoolOrNull(offsets[9]),
isManga: reader.readBoolOrNull(offsets[10]),
lang: reader.readStringOrNull(offsets[11]),
lastRead: reader.readLongOrNull(offsets[12]),
lastUpdate: reader.readLongOrNull(offsets[13]),
link: reader.readStringOrNull(offsets[14]),
name: reader.readStringOrNull(offsets[15]),
source: reader.readStringOrNull(offsets[16]),
status: _MangastatusValueEnumMap[reader.readByteOrNull(offsets[17])] ??
Status.ongoing,
);
return object;
@ -268,34 +281,36 @@ P _mangaDeserializeProp<P>(
case 1:
return (reader.readLongList(offset)) as P;
case 2:
return (reader.readByteList(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 3:
return (reader.readLongOrNull(offset)) as P;
return (reader.readByteList(offset)) as P;
case 4:
return (reader.readStringOrNull(offset)) as P;
return (reader.readLongOrNull(offset)) as P;
case 5:
return (reader.readBoolOrNull(offset)) as P;
case 6:
return (reader.readStringList(offset)) as P;
case 7:
return (reader.readStringOrNull(offset)) as P;
case 8:
case 6:
return (reader.readBoolOrNull(offset)) as P;
case 7:
return (reader.readStringList(offset)) as P;
case 8:
return (reader.readStringOrNull(offset)) as P;
case 9:
return (reader.readBoolOrNull(offset)) as P;
case 10:
return (reader.readStringOrNull(offset)) as P;
return (reader.readBoolOrNull(offset)) as P;
case 11:
return (reader.readLongOrNull(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 12:
return (reader.readLongOrNull(offset)) as P;
case 13:
return (reader.readStringOrNull(offset)) as P;
return (reader.readLongOrNull(offset)) as P;
case 14:
return (reader.readStringOrNull(offset)) as P;
case 15:
return (reader.readStringOrNull(offset)) as P;
case 16:
return (reader.readStringOrNull(offset)) as P;
case 17:
return (_MangastatusValueEnumMap[reader.readByteOrNull(offset)] ??
Status.ongoing) as P;
default:
@ -708,6 +723,162 @@ extension MangaQueryFilter on QueryBuilder<Manga, Manga, QFilterCondition> {
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'customCoverFromTracker',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'customCoverFromTracker',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'customCoverFromTracker',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'customCoverFromTracker',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'customCoverFromTracker',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerBetween(
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'customCoverFromTracker',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'customCoverFromTracker',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'customCoverFromTracker',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerContains(String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'customCoverFromTracker',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerMatches(String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'customCoverFromTracker',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'customCoverFromTracker',
value: '',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition>
customCoverFromTrackerIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'customCoverFromTracker',
value: '',
));
});
}
QueryBuilder<Manga, Manga, QAfterFilterCondition> customCoverImageIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
@ -2448,6 +2619,18 @@ extension MangaQuerySortBy on QueryBuilder<Manga, Manga, QSortBy> {
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> sortByCustomCoverFromTracker() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'customCoverFromTracker', Sort.asc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> sortByCustomCoverFromTrackerDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'customCoverFromTracker', Sort.desc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> sortByDateAdded() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'dateAdded', Sort.asc);
@ -2618,6 +2801,18 @@ extension MangaQuerySortThenBy on QueryBuilder<Manga, Manga, QSortThenBy> {
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> thenByCustomCoverFromTracker() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'customCoverFromTracker', Sort.asc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> thenByCustomCoverFromTrackerDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'customCoverFromTracker', Sort.desc);
});
}
QueryBuilder<Manga, Manga, QAfterSortBy> thenByDateAdded() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'dateAdded', Sort.asc);
@ -2801,6 +2996,14 @@ extension MangaQueryWhereDistinct on QueryBuilder<Manga, Manga, QDistinct> {
});
}
QueryBuilder<Manga, Manga, QDistinct> distinctByCustomCoverFromTracker(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'customCoverFromTracker',
caseSensitive: caseSensitive);
});
}
QueryBuilder<Manga, Manga, QDistinct> distinctByCustomCoverImage() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'customCoverImage');
@ -2917,6 +3120,13 @@ extension MangaQueryProperty on QueryBuilder<Manga, Manga, QQueryProperty> {
});
}
QueryBuilder<Manga, String?, QQueryOperations>
customCoverFromTrackerProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'customCoverFromTracker');
});
}
QueryBuilder<Manga, List<int>?, QQueryOperations> customCoverImageProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'customCoverImage');

View file

@ -7,7 +7,7 @@ part of 'anime_player_controller_provider.dart';
// **************************************************************************
String _$animeStreamControllerHash() =>
r'05102c5a067600752d15236c270f5eb1ab553980';
r'bf0730758333f74352257fb6afd2d0d0a319044f';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -235,7 +235,6 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
Widget build(BuildContext context) {
super.build(context);
final getMangaDetail = widget.manga;
final l10n = l10nLocalizations(context)!;
return GestureDetector(
onTap: () async {
pushToMangaReaderDetail(
@ -254,6 +253,7 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
.sourceEqualTo(widget.source.name)
.watch(fireImmediately: true),
builder: (context, snapshot) {
final hasData = snapshot.hasData && snapshot.data!.isNotEmpty;
return Padding(
padding: const EdgeInsets.only(left: 10),
child: Stack(
@ -261,26 +261,30 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
SizedBox(
width: 110,
child: Column(children: [
snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.customCoverImage != null
? Image.memory(snapshot.data!.first.customCoverImage
as Uint8List)
: ClipRRect(
Builder(
builder: (context) {
if (hasData &&
snapshot.data!.first.customCoverImage != null) {
return Image.memory(snapshot
.data!.first.customCoverImage as Uint8List);
}
return ClipRRect(
borderRadius: BorderRadius.circular(5),
child: cachedNetworkImage(
headers: ref.watch(headersProvider(
source: widget.source.name!,
lang: widget.source.lang!)),
imageUrl: snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.imageUrl != null
? toImgUrl(snapshot.data!.first.imageUrl!)
: toImgUrl(getMangaDetail.imageUrl!),
imageUrl: toImgUrl(hasData
? snapshot.data!.first
.customCoverFromTracker ??
snapshot.data!.first.imageUrl ??
""
: getMangaDetail.imageUrl!),
width: 110,
height: 150,
fit: BoxFit.fill),
),
fit: BoxFit.fill));
},
),
BottomTextWidget(
fontSize: 12.0,
text: widget.manga.name!,
@ -293,33 +297,19 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
Container(
width: 110,
height: 150,
color: snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.favorite!
color: hasData && snapshot.data!.first.favorite!
? Colors.black.withOpacity(0.7)
: null,
),
if (snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.favorite!)
if (hasData && snapshot.data!.first.favorite!)
Positioned(
top: 0,
left: 0,
child: Padding(
padding: const EdgeInsets.all(4),
child: Container(
decoration: BoxDecoration(
color: primaryColor(context),
borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: const EdgeInsets.all(2),
child: Text(
l10n.in_library,
style: const TextStyle(fontSize: 10),
),
),
),
)),
child: Icon(Icons.collections_bookmark,
color: primaryColor(context)),
))
],
),
);

View file

@ -12,6 +12,7 @@ import 'package:mangayomi/modules/history/providers/isar_providers.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/utils/headers.dart';
import 'package:mangayomi/modules/library/widgets/search_text_form_field.dart';
@ -260,7 +261,9 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
headers: ref.watch(headersProvider(
source: manga.source!,
lang: manga.lang!)),
imageUrl: manga.imageUrl!,
imageUrl: toImgUrl(
manga.customCoverFromTracker ??
manga.imageUrl!),
width: 60,
height: 90,
fit: BoxFit.cover),

View file

@ -2374,7 +2374,7 @@ final isLongPressedMangaStateProvider =
typedef _$IsLongPressedMangaState = AutoDisposeNotifier<bool>;
String _$mangasSetIsReadStateHash() =>
r'f283b6c15d908212b462a2dacbf776eeead863fe';
r'8f86296f588a48747de625e0471048978ee9bdeb';
abstract class _$MangasSetIsReadState
extends BuildlessAutoDisposeNotifier<void> {
@ -2519,7 +2519,7 @@ class _MangasSetIsReadStateProviderElement
}
String _$mangasSetUnReadStateHash() =>
r'198aba4f8eb504fc05dbd003e8eb5c4d12d31ff7';
r'3413e731b2fd8476a4032d3e47b943ca12f25090';
abstract class _$MangasSetUnReadState
extends BuildlessAutoDisposeNotifier<void> {

View file

@ -64,7 +64,7 @@ class LibraryGridViewWidget extends StatelessWidget {
? MemoryImage(entry.customCoverImage as Uint8List)
as ImageProvider
: CachedNetworkImageProvider(
toImgUrl(entry.imageUrl!),
toImgUrl(entry.customCoverFromTracker ?? entry.imageUrl!),
headers: ref.watch(headersProvider(
source: entry.source!, lang: entry.lang!)),
),

View file

@ -99,7 +99,9 @@ class LibraryListViewWidget extends StatelessWidget {
? MemoryImage(entry.customCoverImage
as Uint8List) as ImageProvider
: CachedNetworkImageProvider(
toImgUrl(entry.imageUrl!),
toImgUrl(
entry.customCoverFromTracker ??
entry.imageUrl!),
headers: ref.watch(headersProvider(
source: entry.source!,
lang: entry.lang!)),

View file

@ -234,7 +234,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
headers: ref.watch(headersProvider(
source: widget.manga!.source!,
lang: widget.manga!.lang!)),
imageUrl: toImgUrl(widget.manga!.imageUrl!),
imageUrl: toImgUrl(
widget.manga!.customCoverFromTracker ??
widget.manga!.imageUrl!),
width: mediaWidth(context, 1),
height: 300,
fit: BoxFit.cover),
@ -1320,7 +1322,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
final imageProvider = widget.manga!.customCoverImage != null
? MemoryImage(widget.manga!.customCoverImage as Uint8List)
as ImageProvider
: CachedNetworkImageProvider(toImgUrl(widget.manga!.imageUrl!),
: CachedNetworkImageProvider(
toImgUrl(widget.manga!.customCoverFromTracker ??
widget.manga!.imageUrl!),
headers: ref.watch(headersProvider(
source: widget.manga!.source!, lang: widget.manga!.lang!)));
return Padding(
@ -1506,23 +1510,91 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
right: 0,
child: Row(
children: [
if (!isLocalArchive)
if (widget.manga!.customCoverImage != null)
Column(
children: [
StreamBuilder(
stream: isar.trackPreferences
.filter()
.syncIdIsNotNull()
.watch(fireImmediately: true),
builder: (context, snapshot) {
List<TrackPreference>? entries =
snapshot.hasData ? snapshot.data! : [];
if (entries.isEmpty) {
return Container();
}
return Column(
children: entries
.map((e) => Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10)),
onPressed: () async {
final trackSearch =
await trackersSearchraggableMenu(
context,
isManga: widget.manga!.isManga!,
track: Track(
status:
TrackStatus.planToRead,
syncId: e.syncId!,
title: widget.manga!.name!),
) as TrackSearch?;
if (trackSearch != null) {
isar.writeTxnSync(() {
isar.mangas.putSync(widget
.manga!
..customCoverFromTracker =
trackSearch.coverUrl);
});
if (mounted) {
Navigator.pop(context);
}
}
},
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10),
color:
trackInfos(e.syncId!).$3),
width: 45,
height: 50,
child: Image.asset(
trackInfos(e.syncId!).$1,
height: 30,
),
),
),
))
.toList(),
);
},
),
PopupMenuButton(
itemBuilder: (context) {
return [
const PopupMenuItem<int>(
value: 0, child: Text("Delete")),
const PopupMenuItem<int>(
value: 1, child: Text("Edit")),
if (widget.manga!.customCoverImage != null ||
widget.manga!.customCoverFromTracker !=
null)
PopupMenuItem<int>(
value: 0,
child: Text(context.l10n.delete)),
PopupMenuItem<int>(
value: 1, child: Text(context.l10n.edit)),
];
},
onSelected: (value) async {
final manga = widget.manga!;
if (value == 0) {
isar.writeTxnSync(() {
isar.mangas
.putSync(manga..customCoverImage = null);
isar.mangas.putSync(manga
..customCoverImage = null
..customCoverFromTracker = null);
});
} else if (value == 1) {
FilePickerResult? result =
@ -1544,9 +1616,9 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
});
}
}
}
if (mounted) {
Navigator.pop(context);
if (mounted) {
Navigator.pop(context);
}
}
},
child: const Padding(
@ -1555,51 +1627,22 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
child: Icon(Icons.edit_outlined)),
),
),
// IconButton(
// onPressed: () async {
// Uint8List? bytes;
// if (isLocalArchive) {
// bytes =
// widget.manga!.customCoverImage as Uint8List?;
// }
// await Share.shareXFiles([
// XFile.fromData(bytes!,
// name: widget.manga!.name,
// mimeType: 'image/jpeg')
// ]);
// },
// icon: const CircleAvatar(child: Icon(Icons.share))),
if (isLocalArchive ||
widget.manga!.customCoverImage == null)
IconButton(
onPressed: () async {
FilePickerResult? result =
await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
'png',
'jpg',
'jpeg'
]);
if (result != null) {
if (result.files.first.size < 5000000) {
final manga = widget.manga!;
final customCoverImage =
File(result.files.first.path!)
.readAsBytesSync();
isar.writeTxnSync(() {
isar.mangas.putSync(manga
..customCoverImage = customCoverImage);
});
if (mounted) {
Navigator.pop(context);
}
}
}
},
icon: const CircleAvatar(
child: Icon(Icons.edit_outlined))),
// IconButton(
// onPressed: () async {
// Uint8List? bytes;
// if (isLocalArchive) {
// bytes =
// widget.manga!.customCoverImage as Uint8List?;
// }
// await Share.shareXFiles([
// XFile.fromData(bytes!,
// name: widget.manga!.name,
// mimeType: 'image/jpeg')
// ]);
// },
// icon: const CircleAvatar(child: Icon(Icons.share))),
],
),
],
),
)

View file

@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$updateMangaDetailHash() => r'7c528575751a4c88f3ea80edc87973dd668fba6c';
String _$updateMangaDetailHash() => r'753f7db14ba8284ede82e9c8baec4344b28acedb';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -229,17 +229,22 @@ trackersSearchraggableMenu(BuildContext context,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.clear)),
)
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.clear)),
)
],
),
const Divider()
],
),
)),

View file

@ -169,7 +169,7 @@ class _CurrentIndexProviderElement
Chapter get chapter => (origin as CurrentIndexProvider).chapter;
}
String _$readerControllerHash() => r'e6191b82e9cbbe2856c4c46b407ccd5da9206c8e';
String _$readerControllerHash() => r'0b60b5d4cafa82d45d1e180969af0b7c982b1f82';
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
late final Chapter chapter;

View file

@ -10,7 +10,6 @@ import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/manga/detail/manga_detail_main.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/router/router.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/constant.dart';
@ -32,7 +31,6 @@ class MangaImageCardWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
return StreamBuilder(
stream: isar.mangas
.filter()
@ -41,19 +39,18 @@ class MangaImageCardWidget extends ConsumerWidget {
.sourceEqualTo(source.name)
.watch(fireImmediately: true),
builder: (context, snapshot) {
final hasData = snapshot.hasData && snapshot.data!.isNotEmpty;
return CoverViewWidget(
image: snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.customCoverImage != null
image: hasData && snapshot.data!.first.customCoverImage != null
? MemoryImage(
snapshot.data!.first.customCoverImage as Uint8List)
as ImageProvider
: CachedNetworkImageProvider(
snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.imageUrl != null
? toImgUrl(snapshot.data!.first.imageUrl!)
: toImgUrl(getMangaDetail!.imageUrl!),
toImgUrl(hasData
? snapshot.data!.first.customCoverFromTracker ??
snapshot.data!.first.imageUrl ??
""
: getMangaDetail!.imageUrl!),
headers: ref.watch(headersProvider(
source: source.name!, lang: source.lang!)),
),
@ -67,35 +64,18 @@ class MangaImageCardWidget extends ConsumerWidget {
},
children: [
Container(
color: snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.favorite!
? Colors.black.withOpacity(0.7)
color: hasData && snapshot.data!.first.favorite!
? Colors.black.withOpacity(0.6)
: null,
),
if (snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.favorite!)
if (hasData && snapshot.data!.first.favorite!)
Positioned(
top: 0,
left: 0,
child: Padding(
padding: const EdgeInsets.all(4),
child: Container(
decoration: BoxDecoration(
color: primaryColor(context),
borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: const EdgeInsets.all(2),
child: Text(
l10n!.in_library,
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.scaffoldBackgroundColor),
),
),
),
child: Icon(Icons.collections_bookmark,
color: primaryColor(context)),
)),
BottomTextWidget(text: getMangaDetail!.name!)
]);

View file

@ -6,7 +6,7 @@ part of 'kitsu.dart';
// RiverpodGenerator
// **************************************************************************
String _$kitsuHash() => r'c6a31bcfb827bba5d0938d350538a01926d42297';
String _$kitsuHash() => r'425a6699eafe84e35320c9a66bce33b4ba332a52';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'headers.dart';
// RiverpodGenerator
// **************************************************************************
String _$headersHash() => r'36e19ced66a55af45ef31bb3b342505246745ebe';
String _$headersHash() => r'2075121328277856708a7f61718d22c409f915e0';
/// Copied from Dart SDK
class _SystemHash {