fix & reformat

This commit is contained in:
kodjomoustapha 2024-12-20 10:15:15 +01:00
parent 0c84faa5f8
commit a41ccaff22
228 changed files with 8642 additions and 3604 deletions

View file

@ -9,13 +9,15 @@ import 'package:mangayomi/eval/model/element.dart';
class $MDocument implements MDocument, $Instance { class $MDocument implements MDocument, $Instance {
$MDocument.wrap(this.$value) : _superclass = $Object($value); $MDocument.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MDocument')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MDocument'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef( '': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('document', BridgeTypeAnnotation($Element.$type, nullable: true), false), BridgeParameter('document',
BridgeTypeAnnotation($Element.$type, nullable: true), false),
]), ]),
) )
}, },
@ -36,60 +38,118 @@ class $MDocument implements MDocument, $Instance {
returns: BridgeTypeAnnotation($MElement.$type, nullable: true), returns: BridgeTypeAnnotation($MElement.$type, nullable: true),
)), )),
'outerHtml': BridgeMethodDef(BridgeFunctionDef( 'outerHtml': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'text': BridgeMethodDef(BridgeFunctionDef( 'text': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'children': BridgeMethodDef(BridgeFunctionDef( 'children': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MElement.$type]), nullable: true), returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MElement.$type]),
nullable: true),
)), )),
}, },
methods: { methods: {
'select': BridgeMethodDef( 'select': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MElement.$type]), nullable: true), returns: BridgeTypeAnnotation(
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), BridgeTypeRef(CoreTypes.list, [$MElement.$type]),
nullable: true),
params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'selectFirst': BridgeMethodDef( 'selectFirst': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation($MElement.$type, nullable: true), returns: BridgeTypeAnnotation($MElement.$type, nullable: true),
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'getElementsByClassName': BridgeMethodDef( 'getElementsByClassName': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true), returns: BridgeTypeAnnotation(
params: [BridgeParameter('classNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'classNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'getElementsByTagName': BridgeMethodDef( 'getElementsByTagName': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true), returns: BridgeTypeAnnotation(
params: [BridgeParameter('localNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'localNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'getElementById': BridgeMethodDef( 'getElementById': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation($MElement.$type, nullable: true), returns: BridgeTypeAnnotation($MElement.$type, nullable: true),
params: [BridgeParameter('id', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), params: [
BridgeParameter(
'id',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'xpath': BridgeMethodDef( 'xpath': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])), returns: BridgeTypeAnnotation(BridgeTypeRef(
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'xpathFirst': BridgeMethodDef( 'xpathFirst': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), nullable: true),
params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'attr': BridgeMethodDef( 'attr': BridgeMethodDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), params: [ BridgeFunctionDef(
BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), false) returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
]), params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
false)
]),
), ),
'hasAttr': BridgeMethodDef( 'hasAttr': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
params: [BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
}, },
wrap: true); wrap: true);
@ -125,7 +185,9 @@ class $MDocument implements MDocument, $Instance {
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
case 'children': case 'children':
final res = $value.children; final res = $value.children;
return res == null ? const $null() : $List.wrap(res.map((e) => $MElement.wrap(e)).toList()); return res == null
? const $null()
: $List.wrap(res.map((e) => $MElement.wrap(e)).toList());
case 'select': case 'select':
return __select; return __select;
case 'selectFirst': case 'selectFirst':
@ -156,59 +218,79 @@ class $MDocument implements MDocument, $Instance {
void $setProperty(Runtime runtime, String identifier, $Value value) {} void $setProperty(Runtime runtime, String identifier, $Value value) {}
static const $Function __select = $Function(_select); static const $Function __select = $Function(_select);
static $Value? _select(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _select(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).select(args[0]?.$value); final res = (target!.$value as MDocument).select(args[0]?.$value);
return res == null ? const $null() : $List.wrap(res.map((e) => $MElement.wrap(e)).toList()); return res == null
? const $null()
: $List.wrap(res.map((e) => $MElement.wrap(e)).toList());
} }
static const $Function __selectFirst = $Function(_selectFirst); static const $Function __selectFirst = $Function(_selectFirst);
static $Value? _selectFirst(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _selectFirst(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).selectFirst(args[0]?.$value); final res = (target!.$value as MDocument).selectFirst(args[0]?.$value);
return res == null ? const $null() : $MElement.wrap(res); return res == null ? const $null() : $MElement.wrap(res);
} }
static $Value? $new(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? $new(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
return $MDocument.wrap(MDocument(args[0]?.$value)); return $MDocument.wrap(MDocument(args[0]?.$value));
} }
static const $Function __getElementsByClassName = $Function(_getElementsByClassName); static const $Function __getElementsByClassName =
static $Value? _getElementsByClassName(final Runtime runtime, final $Value? target, final List<$Value?> args) { $Function(_getElementsByClassName);
final res = (target!.$value as MDocument).getElementsByClassName(args[0]?.$value); static $Value? _getElementsByClassName(
return res == null ? const $null() : $List.wrap(res.map((e) => $MElement.wrap(e)).toList()); final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res =
(target!.$value as MDocument).getElementsByClassName(args[0]?.$value);
return res == null
? const $null()
: $List.wrap(res.map((e) => $MElement.wrap(e)).toList());
} }
static const $Function __getElementsByTagName = $Function(_getElementsByTagName); static const $Function __getElementsByTagName =
static $Value? _getElementsByTagName(final Runtime runtime, final $Value? target, final List<$Value?> args) { $Function(_getElementsByTagName);
final res = (target!.$value as MDocument).getElementsByTagName(args[0]?.$value); static $Value? _getElementsByTagName(
return res == null ? const $null() : $List.wrap(res.map((e) => $MElement.wrap(e)).toList()); final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res =
(target!.$value as MDocument).getElementsByTagName(args[0]?.$value);
return res == null
? const $null()
: $List.wrap(res.map((e) => $MElement.wrap(e)).toList());
} }
static const $Function __getElementById = $Function(_getElementById); static const $Function __getElementById = $Function(_getElementById);
static $Value? _getElementById(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _getElementById(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).getElementById(args[0]?.$value); final res = (target!.$value as MDocument).getElementById(args[0]?.$value);
return res == null ? const $null() : $MElement.wrap(res); return res == null ? const $null() : $MElement.wrap(res);
} }
static const $Function __xpath = $Function(_xpath); static const $Function __xpath = $Function(_xpath);
static $Value? _xpath(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _xpath(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).xpath(args[0]?.$value); final res = (target!.$value as MDocument).xpath(args[0]?.$value);
return $List.wrap(res.map((e) => $String(e)).toList()); return $List.wrap(res.map((e) => $String(e)).toList());
} }
static const $Function __xpathFirst = $Function(_xpathFirst); static const $Function __xpathFirst = $Function(_xpathFirst);
static $Value? _xpathFirst(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _xpathFirst(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).xpathFirst(args[0]?.$value); final res = (target!.$value as MDocument).xpathFirst(args[0]?.$value);
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
} }
static const $Function __attr = $Function(_attr); static const $Function __attr = $Function(_attr);
static $Value? _attr(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _attr(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).attr(args[0]?.$value ?? ""); final res = (target!.$value as MDocument).attr(args[0]?.$value ?? "");
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
} }
static const $Function __hasAttr = $Function(_hasAttr); static const $Function __hasAttr = $Function(_hasAttr);
static $Value? _hasAttr(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _hasAttr(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MDocument).attr(args[0]?.$value ?? ""); final res = (target!.$value as MDocument).attr(args[0]?.$value ?? "");
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
} }
@ -226,10 +308,12 @@ class $MDocument implements MDocument, $Instance {
String? xpathFirst(String xpath) => $value.xpathFirst(xpath); String? xpathFirst(String xpath) => $value.xpathFirst(xpath);
@override @override
List<MElement>? getElementsByClassName(String classNames) => $value.getElementsByClassName(classNames); List<MElement>? getElementsByClassName(String classNames) =>
$value.getElementsByClassName(classNames);
@override @override
List<MElement>? getElementsByTagName(String localNames) => $value.getElementsByTagName(localNames); List<MElement>? getElementsByTagName(String localNames) =>
$value.getElementsByTagName(localNames);
@override @override
String? attr(String attr) => $value.attr(attr); String? attr(String attr) => $value.attr(attr);
@ -265,11 +349,15 @@ class $MDocument implements MDocument, $Instance {
class $Document implements $Instance { class $Document implements $Instance {
$Document.wrap(this.$value) : _superclass = $Object($value); $Document.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Document')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Document'));
static const $declaration = BridgeClassDef( static const $declaration = BridgeClassDef(
BridgeClassType($type), BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type, nullable: true)))}, constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true)))
},
wrap: true, wrap: true,
); );

View file

@ -5,13 +5,15 @@ import 'package:mangayomi/eval/model/element.dart';
class $MElement implements MElement, $Instance { class $MElement implements MElement, $Instance {
$MElement.wrap(this.$value) : _superclass = $Object($value); $MElement.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MElement')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MElement'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef( '': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('element', BridgeTypeAnnotation($Element.$type, nullable: true), false), BridgeParameter('element',
BridgeTypeAnnotation($Element.$type, nullable: true), false),
]), ]),
) )
}, },
@ -20,37 +22,48 @@ class $MElement implements MElement, $Instance {
}, },
getters: { getters: {
'outerHtml': BridgeMethodDef(BridgeFunctionDef( 'outerHtml': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'innerHtml': BridgeMethodDef(BridgeFunctionDef( 'innerHtml': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'text': BridgeMethodDef(BridgeFunctionDef( 'text': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'className': BridgeMethodDef(BridgeFunctionDef( 'className': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'localName': BridgeMethodDef(BridgeFunctionDef( 'localName': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'namespaceUri': BridgeMethodDef(BridgeFunctionDef( 'namespaceUri': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'getSrc': BridgeMethodDef(BridgeFunctionDef( 'getSrc': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'getImg': BridgeMethodDef(BridgeFunctionDef( 'getImg': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'getHref': BridgeMethodDef(BridgeFunctionDef( 'getHref': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'getDataSrc': BridgeMethodDef(BridgeFunctionDef( 'getDataSrc': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'children': BridgeMethodDef(BridgeFunctionDef( 'children': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
)), )),
'parent': BridgeMethodDef(BridgeFunctionDef( 'parent': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true), returns: BridgeTypeAnnotation($type, nullable: true),
@ -64,48 +77,100 @@ class $MElement implements MElement, $Instance {
}, },
methods: { methods: {
'attr': BridgeMethodDef( 'attr': BridgeMethodDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), params: [ BridgeFunctionDef(
BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), false) returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
]), params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
false)
]),
), ),
'text': BridgeMethodDef( 'text': BridgeMethodDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true)), BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true)),
), ),
'select': BridgeMethodDef( 'select': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true), returns: BridgeTypeAnnotation(
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'selectFirst': BridgeMethodDef( 'selectFirst': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true), returns: BridgeTypeAnnotation($type, nullable: true),
params: [BridgeParameter('selector', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), params: [
BridgeParameter(
'selector',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'getElementsByClassName': BridgeMethodDef( 'getElementsByClassName': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true), returns: BridgeTypeAnnotation(
params: [BridgeParameter('classNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'classNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'getElementsByTagName': BridgeMethodDef( 'getElementsByTagName': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$type]), nullable: true), returns: BridgeTypeAnnotation(
params: [BridgeParameter('localNames', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), BridgeTypeRef(CoreTypes.list, [$type]),
nullable: true),
params: [
BridgeParameter(
'localNames',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'xpath': BridgeMethodDef( 'xpath': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]), returns: BridgeTypeAnnotation(
BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]),
nullable: true), nullable: true),
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'xpathFirst': BridgeMethodDef( 'xpathFirst': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
params: [BridgeParameter('xpath', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), nullable: true),
params: [
BridgeParameter(
'xpath',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
'hasAttr': BridgeMethodDef( 'hasAttr': BridgeMethodDef(
BridgeFunctionDef( BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
params: [BridgeParameter('attr', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false)]), params: [
BridgeParameter(
'attr',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
false)
]),
), ),
}, },
wrap: true); wrap: true);
@ -129,28 +194,44 @@ class $MElement implements MElement, $Instance {
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
case 'text': case 'text':
final res = $value.text; final res = $value.text;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'className': case 'className':
final res = $value.className; final res = $value.className;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'localName': case 'localName':
final res = $value.localName; final res = $value.localName;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'namespaceUri': case 'namespaceUri':
final res = $value.namespaceUri; final res = $value.namespaceUri;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'getSrc': case 'getSrc':
final res = $value.getSrc; final res = $value.getSrc;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'getImg': case 'getImg':
final res = $value.getImg; final res = $value.getImg;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'getHref': case 'getHref':
final res = $value.getHref; final res = $value.getHref;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'getDataSrc': case 'getDataSrc':
final res = $value.getDataSrc; final res = $value.getDataSrc;
return res == null ? const $null() : $String(res.trim().trimLeft().trimRight()); return res == null
? const $null()
: $String(res.trim().trimLeft().trimRight());
case 'parent': case 'parent':
final res = $value.parent; final res = $value.parent;
return res == null ? const $null() : $MElement.wrap(res); return res == null ? const $null() : $MElement.wrap(res);
@ -187,62 +268,83 @@ class $MElement implements MElement, $Instance {
@override @override
void $setProperty(Runtime runtime, String identifier, $Value value) {} void $setProperty(Runtime runtime, String identifier, $Value value) {}
static $Value? $new(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? $new(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
return $MElement.wrap(MElement(args[0]?.$value)); return $MElement.wrap(MElement(args[0]?.$value));
} }
static const $Function __attr = $Function(_attr); static const $Function __attr = $Function(_attr);
static $Value? _attr(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _attr(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MElement).attr(args[0]?.$value ?? ""); final res = (target!.$value as MElement).attr(args[0]?.$value ?? "");
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
} }
static const $Function __select = $Function(_select); static const $Function __select = $Function(_select);
static $Value? _select(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _select(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MElement).select(args[0]?.$value); final res = (target!.$value as MElement).select(args[0]?.$value);
return res == null ? const $null() : $List.wrap(res.map((e) => $MElement.wrap(e)).toList()); return res == null
? const $null()
: $List.wrap(res.map((e) => $MElement.wrap(e)).toList());
} }
static const $Function __selectFirst = $Function(_selectFirst); static const $Function __selectFirst = $Function(_selectFirst);
static $Value? _selectFirst(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _selectFirst(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MElement).selectFirst(args[0]?.$value); final res = (target!.$value as MElement).selectFirst(args[0]?.$value);
return res == null ? const $null() : $MElement.wrap(res); return res == null ? const $null() : $MElement.wrap(res);
} }
static const $Function __getElementsByClassName = $Function(_getElementsByClassName); static const $Function __getElementsByClassName =
$Function(_getElementsByClassName);
static $Value? _getElementsByClassName(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _getElementsByClassName(
final res = (target!.$value as MElement).getElementsByClassName(args[0]?.$value); final Runtime runtime, final $Value? target, final List<$Value?> args) {
return res == null ? const $null() : $List.wrap(res.map((e) => $MElement.wrap(e)).toList()); final res =
(target!.$value as MElement).getElementsByClassName(args[0]?.$value);
return res == null
? const $null()
: $List.wrap(res.map((e) => $MElement.wrap(e)).toList());
} }
static const $Function __getElementsByTagName = $Function(_getElementsByTagName); static const $Function __getElementsByTagName =
$Function(_getElementsByTagName);
static $Value? _getElementsByTagName(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _getElementsByTagName(
final res = (target!.$value as MElement).getElementsByTagName(args[0]?.$value); final Runtime runtime, final $Value? target, final List<$Value?> args) {
return res == null ? const $null() : $List.wrap(res.map((e) => $MElement.wrap(e)).toList()); final res =
(target!.$value as MElement).getElementsByTagName(args[0]?.$value);
return res == null
? const $null()
: $List.wrap(res.map((e) => $MElement.wrap(e)).toList());
} }
static const $Function __xpath = $Function(_xpath); static const $Function __xpath = $Function(_xpath);
static $Value? _xpath(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _xpath(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MElement).xpath(args[0]?.$value); final res = (target!.$value as MElement).xpath(args[0]?.$value);
return res == null ? const $null() : $List.wrap(res.map((e) => $String(e)).toList()); return res == null
? const $null()
: $List.wrap(res.map((e) => $String(e)).toList());
} }
static const $Function __xpathFirst = $Function(_xpathFirst); static const $Function __xpathFirst = $Function(_xpathFirst);
static $Value? _xpathFirst(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _xpathFirst(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MElement).xpathFirst(args[0]?.$value); final res = (target!.$value as MElement).xpathFirst(args[0]?.$value);
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
} }
static const $Function __hasAttr = $Function(_hasAttr); static const $Function __hasAttr = $Function(_hasAttr);
static $Value? _hasAttr(final Runtime runtime, final $Value? target, final List<$Value?> args) { static $Value? _hasAttr(
final Runtime runtime, final $Value? target, final List<$Value?> args) {
final res = (target!.$value as MElement).attr(args[0]?.$value ?? ""); final res = (target!.$value as MElement).attr(args[0]?.$value ?? "");
return res == null ? const $null() : $String(res); return res == null ? const $null() : $String(res);
} }
@ -266,10 +368,12 @@ class $MElement implements MElement, $Instance {
List<MElement>? get children => $value.children; List<MElement>? get children => $value.children;
@override @override
List<MElement>? getElementsByClassName(String classNames) => $value.getElementsByClassName(classNames); List<MElement>? getElementsByClassName(String classNames) =>
$value.getElementsByClassName(classNames);
@override @override
List<MElement>? getElementsByTagName(String localNames) => $value.getElementsByTagName(localNames); List<MElement>? getElementsByTagName(String localNames) =>
$value.getElementsByTagName(localNames);
@override @override
bool hasAttr(String attr) => $value.hasAttr(attr); bool hasAttr(String attr) => $value.hasAttr(attr);
@ -317,11 +421,15 @@ class $MElement implements MElement, $Instance {
class $Element implements $Instance { class $Element implements $Instance {
$Element.wrap(this.$value) : _superclass = $Object($value); $Element.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Element')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Element'));
static const $declaration = BridgeClassDef( static const $declaration = BridgeClassDef(
BridgeClassType($type), BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type, nullable: true)))}, constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($type, nullable: true)))
},
wrap: true, wrap: true,
); );

View file

@ -5,18 +5,24 @@ import 'package:mangayomi/eval/model/filter.dart';
class $FilterList implements FilterList, $Instance { class $FilterList implements FilterList, $Instance {
$FilterList.wrap(this.$value) : _superclass = $Object($value); $FilterList.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'FilterList')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'FilterList'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('filters', BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), false), BridgeParameter(
'filters',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
false),
])) ]))
}, },
fields: { fields: {
'filters': BridgeFieldDef( 'filters': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
), ),
}, },
wrap: true); wrap: true);
@ -51,7 +57,9 @@ class $FilterList implements FilterList, $Instance {
void $setProperty(Runtime runtime, String identifier, $Value value) { void $setProperty(Runtime runtime, String identifier, $Value value) {
switch (identifier) { switch (identifier) {
case 'filters': case 'filters':
$value.filters = (value.$reified as List).map((e) => e is $Value ? e.$reified : e).toList(); $value.filters = (value.$reified as List)
.map((e) => e is $Value ? e.$reified : e)
.toList();
default: default:
_superclass.$setProperty(runtime, identifier, value); _superclass.$setProperty(runtime, identifier, value);
} }
@ -72,26 +80,37 @@ class $FilterList implements FilterList, $Instance {
class $SelectFilter implements SelectFilter, $Instance { class $SelectFilter implements SelectFilter, $Instance {
$SelectFilter.wrap(this.$value) : _superclass = $Object($value); $SelectFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SelectFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SelectFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('type',
BridgeParameter('state', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('name',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('state',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), false),
BridgeParameter( BridgeParameter(
'values', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), false), 'values',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
false),
])) ]))
}, },
fields: { fields: {
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'type': BridgeFieldDef(
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'state': BridgeFieldDef(BridgeTypeAnnotation( 'state': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.int), BridgeTypeRef(CoreTypes.int),
)), )),
'values': BridgeFieldDef( 'values': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
), ),
}, },
wrap: true); wrap: true);
@ -109,7 +128,8 @@ class $SelectFilter implements SelectFilter, $Instance {
map = value.map((key, value) => MapEntry(key.toString(), value)); map = value.map((key, value) => MapEntry(key.toString(), value));
if (map['type'] == 'SelectOption') { if (map['type'] == 'SelectOption') {
final filter = map['filter'] as Map; final filter = map['filter'] as Map;
return SelectFilterOption.fromJson(filter.map((key, value) => MapEntry(key.toString(), value))); return SelectFilterOption.fromJson(filter
.map((key, value) => MapEntry(key.toString(), value)));
} }
} }
return value; return value;
@ -202,23 +222,30 @@ class $SelectFilter implements SelectFilter, $Instance {
class $SelectFilterOption implements SelectFilterOption, $Instance { class $SelectFilterOption implements SelectFilterOption, $Instance {
$SelectFilterOption.wrap(this.$value) : _superclass = $Object($value); $SelectFilterOption.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SelectFilterOption')); static const $type = BridgeTypeRef(BridgeTypeSpec(
'package:mangayomi/bridge_lib.dart', 'SelectFilterOption'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('value', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('name',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('value',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
])) ]))
}, },
fields: { fields: {
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'name': BridgeFieldDef(
'value': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'value': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $SelectFilterOption.wrap(SelectFilterOption(args[0]!.$value, args[1]!.$value, null)); return $SelectFilterOption
.wrap(SelectFilterOption(args[0]!.$value, args[1]!.$value, null));
} }
@override @override
@ -285,21 +312,26 @@ class $SelectFilterOption implements SelectFilterOption, $Instance {
class $SeparatorFilter implements SeparatorFilter, $Instance { class $SeparatorFilter implements SeparatorFilter, $Instance {
$SeparatorFilter.wrap(this.$value) : _superclass = $Object($value); $SeparatorFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SeparatorFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SeparatorFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('type',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true),
])) ]))
}, },
fields: { fields: {
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'type': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $SeparatorFilter.wrap(SeparatorFilter(null, type: args[0]?.$value ?? '')); return $SeparatorFilter
.wrap(SeparatorFilter(null, type: args[0]?.$value ?? ''));
} }
@override @override
@ -355,23 +387,30 @@ class $SeparatorFilter implements SeparatorFilter, $Instance {
class $HeaderFilter implements HeaderFilter, $Instance { class $HeaderFilter implements HeaderFilter, $Instance {
$HeaderFilter.wrap(this.$value) : _superclass = $Object($value); $HeaderFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'HeaderFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'HeaderFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true), BridgeParameter('name',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('type',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true),
])) ]))
}, },
fields: { fields: {
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'name': BridgeFieldDef(
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'type': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $HeaderFilter.wrap(HeaderFilter(args[0]!.$value, null, type: args[1]?.$value ?? '')); return $HeaderFilter
.wrap(HeaderFilter(args[0]!.$value, null, type: args[1]?.$value ?? ''));
} }
@override @override
@ -438,18 +477,24 @@ class $HeaderFilter implements HeaderFilter, $Instance {
class $TextFilter implements TextFilter, $Instance { class $TextFilter implements TextFilter, $Instance {
$TextFilter.wrap(this.$value) : _superclass = $Object($value); $TextFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'TextFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'TextFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('type',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('name',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
])) ]))
}, },
fields: { fields: {
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'type': BridgeFieldDef(
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);
@ -530,24 +575,35 @@ class $TextFilter implements TextFilter, $Instance {
class $SortFilter implements SortFilter, $Instance { class $SortFilter implements SortFilter, $Instance {
$SortFilter.wrap(this.$value) : _superclass = $Object($value); $SortFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SortFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SortFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('type',
BridgeParameter('state', BridgeTypeAnnotation($SortState.$type), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('name',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter( BridgeParameter(
'values', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), false), 'state', BridgeTypeAnnotation($SortState.$type), false),
BridgeParameter(
'values',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
false),
])) ]))
}, },
fields: { fields: {
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'type': BridgeFieldDef(
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'state': BridgeFieldDef(BridgeTypeAnnotation($SortState.$type)), 'state': BridgeFieldDef(BridgeTypeAnnotation($SortState.$type)),
'values': BridgeFieldDef( 'values': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
), ),
}, },
wrap: true); wrap: true);
@ -557,7 +613,10 @@ class $SortFilter implements SortFilter, $Instance {
args[0]!.$value, args[0]!.$value,
args[1]!.$value, args[1]!.$value,
args[2]!.$value, args[2]!.$value,
(args[3]!.$value as List).map((e) => SelectFilterOption(e.$reified.name, e.$reified.value, null)).toList(), (args[3]!.$value as List)
.map((e) =>
SelectFilterOption(e.$reified.name, e.$reified.value, null))
.toList(),
null)); null));
} }
@ -644,13 +703,17 @@ class $SortFilter implements SortFilter, $Instance {
class $SortState implements SortState, $Instance { class $SortState implements SortState, $Instance {
$SortState.wrap(this.$value) : _superclass = $Object($value); $SortState.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SortState')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SortState'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('index', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('ascending', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), false), BridgeParameter('index',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), false),
BridgeParameter('ascending',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), false),
])) ]))
}, },
fields: { fields: {
@ -731,22 +794,31 @@ class $SortState implements SortState, $Instance {
class $TriStateFilter implements TriStateFilter, $Instance { class $TriStateFilter implements TriStateFilter, $Instance {
$TriStateFilter.wrap(this.$value) : _superclass = $Object($value); $TriStateFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'TriStateFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'TriStateFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('value', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('name',
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('value',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('type',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true),
], namedParams: [ ], namedParams: [
BridgeParameter('state', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), true) BridgeParameter(
'state', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), true)
])) ]))
}, },
fields: { fields: {
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'name': BridgeFieldDef(
'value': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'value': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'type': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'state': BridgeFieldDef(BridgeTypeAnnotation( 'state': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.int), BridgeTypeRef(CoreTypes.int),
)), )),
@ -754,8 +826,9 @@ class $TriStateFilter implements TriStateFilter, $Instance {
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $TriStateFilter.wrap( return $TriStateFilter.wrap(TriStateFilter(
TriStateFilter(args[2]?.$value ?? '', args[0]!.$value, args[1]!.$value, null, state: args[3]?.$value ?? 0)); args[2]?.$value ?? '', args[0]!.$value, args[1]!.$value, null,
state: args[3]?.$value ?? 0));
} }
@override @override
@ -842,22 +915,32 @@ class $TriStateFilter implements TriStateFilter, $Instance {
class $GroupFilter implements GroupFilter, $Instance { class $GroupFilter implements GroupFilter, $Instance {
$GroupFilter.wrap(this.$value) : _superclass = $Object($value); $GroupFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'GroupFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'GroupFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('type',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('name',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter( BridgeParameter(
'state', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), false), 'state',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
false),
])) ]))
}, },
fields: { fields: {
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'type': BridgeFieldDef(
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'state': BridgeFieldDef( 'state': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])), BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.dynamic)])),
), ),
}, },
wrap: true); wrap: true);
@ -874,10 +957,12 @@ class $GroupFilter implements GroupFilter, $Instance {
map = value.map((key, value) => MapEntry(key.toString(), value)); map = value.map((key, value) => MapEntry(key.toString(), value));
if (map['type'] == 'TriState') { if (map['type'] == 'TriState') {
final filter = map['filter'] as Map; final filter = map['filter'] as Map;
return TriStateFilter.fromJson(filter.map((key, value) => MapEntry(key.toString(), value))); return TriStateFilter.fromJson(filter
.map((key, value) => MapEntry(key.toString(), value)));
} else if (map['type'] == 'CheckBox') { } else if (map['type'] == 'CheckBox') {
final filter = map['filter'] as Map; final filter = map['filter'] as Map;
return CheckBoxFilter.fromJson(filter.map((key, value) => MapEntry(key.toString(), value))); return CheckBoxFilter.fromJson(filter
.map((key, value) => MapEntry(key.toString(), value)));
} }
} }
return value; return value;
@ -961,22 +1046,31 @@ class $GroupFilter implements GroupFilter, $Instance {
class $CheckBoxFilter implements CheckBoxFilter, $Instance { class $CheckBoxFilter implements CheckBoxFilter, $Instance {
$CheckBoxFilter.wrap(this.$value) : _superclass = $Object($value); $CheckBoxFilter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'CheckBoxFilter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'CheckBoxFilter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('value', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('name',
BridgeParameter('type', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('value',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('type',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true),
], namedParams: [ ], namedParams: [
BridgeParameter('state', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), true), BridgeParameter('state',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), true),
])) ]))
}, },
fields: { fields: {
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'name': BridgeFieldDef(
'value': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'type': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'value': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'type': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'state': BridgeFieldDef(BridgeTypeAnnotation( 'state': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.bool), BridgeTypeRef(CoreTypes.bool),
)), )),
@ -984,8 +1078,9 @@ class $CheckBoxFilter implements CheckBoxFilter, $Instance {
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $CheckBoxFilter.wrap( return $CheckBoxFilter.wrap(CheckBoxFilter(
CheckBoxFilter(args[2]?.$value ?? '', args[0]!.$value, args[1]!.$value, null, state: args[3]?.$value ?? false)); args[2]?.$value ?? '', args[0]!.$value, args[1]!.$value, null,
state: args[3]?.$value ?? false));
} }
@override @override

View file

@ -17,104 +17,165 @@ class $Client implements $Instance {
late final $Instance _superclass = $Object($value); late final $Instance _superclass = $Object($value);
/// Compile-time bridged type reference for [$InterceptedClient] /// Compile-time bridged type reference for [$InterceptedClient]
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Client')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Client'));
/// Compile-time bridged class declaration for [$InterceptedClient] /// Compile-time bridged class declaration for [$InterceptedClient]
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('source', BridgeTypeAnnotation($MSource.$type), true), BridgeParameter('source', BridgeTypeAnnotation($MSource.$type), true),
BridgeParameter('reqcopyWith', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true), BridgeParameter('reqcopyWith',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true),
], namedParams: [])) ], namedParams: []))
}, },
methods: { methods: {
'get': BridgeMethodDef(BridgeFunctionDef( 'get': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [$Response.$type])), returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.future, [$Response.$type])),
params: [ params: [
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false), BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false),
], ],
namedParams: [ namedParams: [
BridgeParameter( BridgeParameter(
'headers', 'headers',
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true), nullable: true),
true), true),
])), ])),
'post': BridgeMethodDef(BridgeFunctionDef( 'post': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [$Response.$type])), returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.future, [$Response.$type])),
params: [ params: [
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false), BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false),
], ],
namedParams: [ namedParams: [
BridgeParameter( BridgeParameter(
'headers', 'headers',
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true), nullable: true),
true), true),
BridgeParameter('body', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object), nullable: true), true),
BridgeParameter( BridgeParameter(
'encoding', BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding), nullable: true), true), 'body',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object),
nullable: true),
true),
BridgeParameter(
'encoding',
BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding),
nullable: true),
true),
])), ])),
'put': BridgeMethodDef(BridgeFunctionDef( 'put': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [$Response.$type])), returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.future, [$Response.$type])),
params: [ params: [
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false), BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false),
], ],
namedParams: [ namedParams: [
BridgeParameter( BridgeParameter(
'headers', 'headers',
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true), nullable: true),
true), true),
BridgeParameter('body', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object), nullable: true), true),
BridgeParameter( BridgeParameter(
'encoding', BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding), nullable: true), true), 'body',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object),
nullable: true),
true),
BridgeParameter(
'encoding',
BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding),
nullable: true),
true),
])), ])),
'delete': BridgeMethodDef(BridgeFunctionDef( 'delete': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [$Response.$type])), returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.future, [$Response.$type])),
params: [ params: [
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false), BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false),
], ],
namedParams: [ namedParams: [
BridgeParameter( BridgeParameter(
'headers', 'headers',
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true), nullable: true),
true), true),
BridgeParameter('body', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object), nullable: true), true),
BridgeParameter( BridgeParameter(
'encoding', BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding), nullable: true), true), 'body',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object),
nullable: true),
true),
BridgeParameter(
'encoding',
BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding),
nullable: true),
true),
])), ])),
'patch': BridgeMethodDef(BridgeFunctionDef( 'patch': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [$Response.$type])), returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.future, [$Response.$type])),
params: [ params: [
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false), BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false),
], ],
namedParams: [ namedParams: [
BridgeParameter( BridgeParameter(
'headers', 'headers',
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true), nullable: true),
true), true),
BridgeParameter('body', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object), nullable: true), true),
BridgeParameter( BridgeParameter(
'encoding', BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding), nullable: true), true), 'body',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.object),
nullable: true),
true),
BridgeParameter(
'encoding',
BridgeTypeAnnotation(BridgeTypeRef(ConvertTypes.encoding),
nullable: true),
true),
])), ])),
'read': BridgeMethodDef(BridgeFunctionDef( 'read': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [BridgeTypeRef(CoreTypes.string)])), returns: BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.future, [BridgeTypeRef(CoreTypes.string)])),
params: [ params: [
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false), BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false),
], ],
namedParams: [ namedParams: [
BridgeParameter( BridgeParameter(
'headers', 'headers',
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true), nullable: true),
true), true),
])), ])),
@ -123,20 +184,26 @@ class $Client implements $Instance {
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.int)]) BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.int)])
])), ])),
params: [ params: [
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false), BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.uri)), false),
], ],
namedParams: [ namedParams: [
BridgeParameter( BridgeParameter(
'headers', 'headers',
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true), nullable: true),
true), true),
])), ])),
'send': BridgeMethodDef(BridgeFunctionDef( 'send': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [BridgeTypeRef(CoreTypes.list)])), returns: BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.future, [BridgeTypeRef(CoreTypes.list)])),
params: [ params: [
BridgeParameter('request', BridgeTypeAnnotation($BaseRequest.$type), false), BridgeParameter(
'request', BridgeTypeAnnotation($BaseRequest.$type), false),
])), ])),
'close': BridgeMethodDef(BridgeFunctionDef( 'close': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.voidType)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.voidType)),
@ -147,7 +214,8 @@ class $Client implements $Instance {
static $Client $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Client $new(Runtime runtime, $Value? target, List<$Value?> args) {
final reqcopyWith = args[1]?.$value == null final reqcopyWith = args[1]?.$value == null
? null ? null
: (jsonDecode(args[1]!.$value) as Map).map((key, value) => MapEntry(key.toString(), value)); : (jsonDecode(args[1]!.$value) as Map)
.map((key, value) => MapEntry(key.toString(), value));
return $Client.wrap( return $Client.wrap(
MClient.init(source: args[0]?.$value, reqcopyWith: reqcopyWith), MClient.init(source: args[0]?.$value, reqcopyWith: reqcopyWith),
); );
@ -183,8 +251,10 @@ class $Client implements $Instance {
final url = args[0]!.$value as Uri; final url = args[0]!.$value as Uri;
final headers = _toMapString(args[1]?.$value); final headers = _toMapString(args[1]?.$value);
final request = (target!.$value as InterceptedClient).get(url, headers: headers); final request =
return $Future.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage()); (target!.$value as InterceptedClient).get(url, headers: headers);
return $Future
.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage());
} }
static const $Function __post = $Function(_post); static const $Function __post = $Function(_post);
@ -195,8 +265,10 @@ class $Client implements $Instance {
final body = _toBodyObject(args[2]?.$value); final body = _toBodyObject(args[2]?.$value);
final encoding = args[3]?.$value as Encoding?; final encoding = args[3]?.$value as Encoding?;
final request = (target!.$value as InterceptedClient).post(url, headers: headers, body: body, encoding: encoding); final request = (target!.$value as InterceptedClient)
return $Future.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage()); .post(url, headers: headers, body: body, encoding: encoding);
return $Future
.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage());
} }
static const $Function __put = $Function(_put); static const $Function __put = $Function(_put);
@ -207,8 +279,10 @@ class $Client implements $Instance {
final body = _toBodyObject(args[2]?.$value); final body = _toBodyObject(args[2]?.$value);
final encoding = args[3]?.$value as Encoding?; final encoding = args[3]?.$value as Encoding?;
final request = (target!.$value as InterceptedClient).put(url, headers: headers, body: body, encoding: encoding); final request = (target!.$value as InterceptedClient)
return $Future.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage()); .put(url, headers: headers, body: body, encoding: encoding);
return $Future
.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage());
} }
static const $Function __delete = $Function(_delete); static const $Function __delete = $Function(_delete);
@ -219,8 +293,10 @@ class $Client implements $Instance {
final body = _toBodyObject(args[2]?.$value); final body = _toBodyObject(args[2]?.$value);
final encoding = args[3]?.$value as Encoding?; final encoding = args[3]?.$value as Encoding?;
final request = (target!.$value as InterceptedClient).delete(url, headers: headers, body: body, encoding: encoding); final request = (target!.$value as InterceptedClient)
return $Future.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage()); .delete(url, headers: headers, body: body, encoding: encoding);
return $Future
.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage());
} }
static const $Function __patch = $Function(_patch); static const $Function __patch = $Function(_patch);
@ -231,8 +307,10 @@ class $Client implements $Instance {
final body = _toBodyObject(args[2]?.$value); final body = _toBodyObject(args[2]?.$value);
final encoding = args[3]?.$value as Encoding?; final encoding = args[3]?.$value as Encoding?;
final request = (target!.$value as InterceptedClient).patch(url, headers: headers, body: body, encoding: encoding); final request = (target!.$value as InterceptedClient)
return $Future.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage()); .patch(url, headers: headers, body: body, encoding: encoding);
return $Future
.wrap(request.then((value) => $Response.wrap(value)).onErrorMessage());
} }
static const $Function __read = $Function(_read); static const $Function __read = $Function(_read);
@ -241,19 +319,25 @@ class $Client implements $Instance {
final url = args[0]!.$value as Uri; final url = args[0]!.$value as Uri;
final headers = _toMapString(args[1]?.$value); final headers = _toMapString(args[1]?.$value);
final request = (target!.$value as InterceptedClient).read(url, headers: headers); final request =
return $Future.wrap(request.then((value) => $String(value)).onErrorMessage()); (target!.$value as InterceptedClient).read(url, headers: headers);
return $Future
.wrap(request.then((value) => $String(value)).onErrorMessage());
} }
static const $Function __readBytes = $Function(_readBytes); static const $Function __readBytes = $Function(_readBytes);
static $Value? _readBytes(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? _readBytes(
Runtime runtime, $Value? target, List<$Value?> args) {
final url = args[0]!.$value as Uri; final url = args[0]!.$value as Uri;
final headers = (args[1]?.$value as Map<$Value, $Value>?) final headers = (args[1]?.$value as Map<$Value, $Value>?)?.map(
?.map((key, value) => MapEntry((key.$reified).toString(), (value.$reified).toString())); (key, value) =>
MapEntry((key.$reified).toString(), (value.$reified).toString()));
final request = (target!.$value as InterceptedClient).readBytes(url, headers: headers); final request =
return $Future.wrap(request.then((value) => $List.wrap(value)).onErrorMessage()); (target!.$value as InterceptedClient).readBytes(url, headers: headers);
return $Future
.wrap(request.then((value) => $List.wrap(value)).onErrorMessage());
} }
static const $Function __close = $Function(_close); static const $Function __close = $Function(_close);
@ -281,46 +365,52 @@ class $BaseRequest implements $Instance {
final BaseRequest $value; final BaseRequest $value;
/// Compile-time bridged type reference for [$BaseRequest] /// Compile-time bridged type reference for [$BaseRequest]
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'BaseRequest')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'BaseRequest'));
/// Compile-time bridged class declaration for [$BaseRequest] /// Compile-time bridged class declaration for [$BaseRequest]
static const $declaration = BridgeClassDef(BridgeClassType($type, isAbstract: true), static const $declaration =
constructors: {}, BridgeClassDef(BridgeClassType($type, isAbstract: true),
getters: { constructors: {},
'contentLength': BridgeMethodDef(BridgeFunctionDef( getters: {
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int), nullable: true), 'contentLength': BridgeMethodDef(BridgeFunctionDef(
)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int),
'finalized': BridgeMethodDef(BridgeFunctionDef( nullable: true),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), )),
)), 'finalized': BridgeMethodDef(BridgeFunctionDef(
'followRedirects': BridgeMethodDef(BridgeFunctionDef( returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), )),
)), 'followRedirects': BridgeMethodDef(BridgeFunctionDef(
'headers': BridgeMethodDef(BridgeFunctionDef( returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
returns: BridgeTypeAnnotation( )),
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), 'headers': BridgeMethodDef(BridgeFunctionDef(
), returns: BridgeTypeAnnotation(
)), BridgeTypeRef(CoreTypes.map, [
'maxRedirects': BridgeMethodDef(BridgeFunctionDef( BridgeTypeRef(CoreTypes.string),
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), BridgeTypeRef(CoreTypes.string)
)), ]),
'method': BridgeMethodDef(BridgeFunctionDef( ),
returns: BridgeTypeAnnotation( )),
BridgeTypeRef(CoreTypes.string), 'maxRedirects': BridgeMethodDef(BridgeFunctionDef(
), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)),
)), )),
'persistentConnection': BridgeMethodDef(BridgeFunctionDef( 'method': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation( returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string),
), ),
)), )),
'url': BridgeMethodDef(BridgeFunctionDef( 'persistentConnection': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation( returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.uri), BridgeTypeRef(CoreTypes.string),
), ),
)), )),
}, 'url': BridgeMethodDef(BridgeFunctionDef(
wrap: true); returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.uri),
),
)),
},
wrap: true);
final $Instance _superclass; final $Instance _superclass;
@ -369,25 +459,34 @@ class $Response implements $Instance {
final Response $value; final Response $value;
/// Compile-time bridged type reference for [$Response] /// Compile-time bridged type reference for [$Response]
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Response')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'Response'));
/// Compile-time bridged class declaration for [$Response] /// Compile-time bridged class declaration for [$Response]
static const $declaration = BridgeClassDef( static const $declaration = BridgeClassDef(
BridgeClassType($type), BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type)))}, constructors: {
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type)))
},
getters: { getters: {
'body': BridgeMethodDef(BridgeFunctionDef( 'body': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
)), )),
'bodyBytes': BridgeMethodDef(BridgeFunctionDef( 'bodyBytes': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.int)])), returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.int)])),
)), )),
'contentLength': BridgeMethodDef(BridgeFunctionDef( 'contentLength': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int), nullable: true), returns:
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int), nullable: true),
)), )),
'headers': BridgeMethodDef(BridgeFunctionDef( 'headers': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation( returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
), ),
)), )),
'isRedirect': BridgeMethodDef(BridgeFunctionDef( 'isRedirect': BridgeMethodDef(BridgeFunctionDef(
@ -397,7 +496,8 @@ class $Response implements $Instance {
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
)), )),
'reasonPhrase': BridgeMethodDef(BridgeFunctionDef( 'reasonPhrase': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'statusCode': BridgeMethodDef(BridgeFunctionDef( 'statusCode': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)),
@ -460,22 +560,30 @@ class $StreamedResponse implements $Instance {
final StreamedResponse $value; final StreamedResponse $value;
/// Compile-time bridged type reference for [$StreamedResponse] /// Compile-time bridged type reference for [$StreamedResponse]
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'StreamedResponse')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'StreamedResponse'));
/// Compile-time bridged class declaration for [$StreamedResponse] /// Compile-time bridged class declaration for [$StreamedResponse]
static const $declaration = BridgeClassDef( static const $declaration = BridgeClassDef(
BridgeClassType($type), BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type)))}, constructors: {
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type)))
},
getters: { getters: {
'stream': BridgeMethodDef(BridgeFunctionDef( 'stream': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation($ByteStream.$type), returns: BridgeTypeAnnotation($ByteStream.$type),
)), )),
'contentLength': BridgeMethodDef(BridgeFunctionDef( 'contentLength': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int), nullable: true), returns:
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int), nullable: true),
)), )),
'headers': BridgeMethodDef(BridgeFunctionDef( 'headers': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation( returns: BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
), ),
)), )),
'isRedirect': BridgeMethodDef(BridgeFunctionDef( 'isRedirect': BridgeMethodDef(BridgeFunctionDef(
@ -485,7 +593,8 @@ class $StreamedResponse implements $Instance {
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)),
)), )),
'reasonPhrase': BridgeMethodDef(BridgeFunctionDef( 'reasonPhrase': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string), nullable: true), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string),
nullable: true),
)), )),
'statusCode': BridgeMethodDef(BridgeFunctionDef( 'statusCode': BridgeMethodDef(BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)),
@ -546,12 +655,16 @@ class $ByteStream implements $Instance {
final ByteStream $value; final ByteStream $value;
/// Compile-time bridged type reference for [$ByteStream] /// Compile-time bridged type reference for [$ByteStream]
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'ByteStream')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'ByteStream'));
/// Compile-time bridged class declaration for [$ByteStream] /// Compile-time bridged class declaration for [$ByteStream]
static const $declaration = BridgeClassDef( static const $declaration = BridgeClassDef(
BridgeClassType($type), BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type)))}, constructors: {
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type)))
},
getters: {}, getters: {},
wrap: true, wrap: true,
); );
@ -579,13 +692,15 @@ class $ByteStream implements $Instance {
} }
Map<String, String>? _toMapString(Map<$Value, $Value>? value) { Map<String, String>? _toMapString(Map<$Value, $Value>? value) {
return value?.map((key, value) => MapEntry((key.$reified).toString(), (value.$reified).toString())); return value?.map((key, value) =>
MapEntry((key.$reified).toString(), (value.$reified).toString()));
} }
Object? _toBodyObject(Object? value) { Object? _toBodyObject(Object? value) {
Object? body; Object? body;
if (value is Map<$Value, $Value>) { if (value is Map<$Value, $Value>) {
body = value.map((key, value) => MapEntry((key.$reified).toString(), (value.$reified).toString())); body = value.map((key, value) =>
MapEntry((key.$reified).toString(), (value.$reified).toString()));
} else if (value is List<$Value>) { } else if (value is List<$Value>) {
body = value.map((e) => e.$reified).toList(); body = value.map((e) => e.$reified).toList();
} else { } else {

View file

@ -5,23 +5,35 @@ import 'package:mangayomi/eval/model/m_chapter.dart';
class $MChapter implements MChapter, $Instance { class $MChapter implements MChapter, $Instance {
$MChapter.wrap(this.$value) : _superclass = $Object($value); $MChapter.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MChapter')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MChapter'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [], namedParams: [ '': BridgeConstructorDef(BridgeFunctionDef(
BridgeParameter('name', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), returns: BridgeTypeAnnotation($type),
BridgeParameter('url', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), params: [],
BridgeParameter('dateUpload', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), namedParams: [
BridgeParameter('scanlator', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true), BridgeParameter('name',
])) BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('url',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('dateUpload',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('scanlator',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), true),
]))
}, },
// Specify class fields // Specify class fields
fields: { fields: {
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'name': BridgeFieldDef(
'url': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dateUpload': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'url': BridgeFieldDef(
'scanlator': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dateUpload': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'scanlator': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);
@ -102,5 +114,10 @@ class $MChapter implements MChapter, $Instance {
set scanlator(String? scanlator) {} set scanlator(String? scanlator) {}
@override @override
Map<String, dynamic> toJson() => {'name': name, 'url': url, 'dateUpload': dateUpload, 'scanlator': scanlator}; Map<String, dynamic> toJson() => {
'name': name,
'url': url,
'dateUpload': dateUpload,
'scanlator': scanlator
};
} }

View file

@ -10,25 +10,36 @@ import 'package:mangayomi/utils/extensions/string_extensions.dart';
class $MManga implements MManga, $Instance { class $MManga implements MManga, $Instance {
$MManga.wrap(this.$value) : _superclass = $Object($value); $MManga.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MManga')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MManga'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))}, constructors: {
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))
},
// Specify class fields // Specify class fields
fields: { fields: {
'author': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'author': BridgeFieldDef(
'artist': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'artist': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'status': BridgeFieldDef(BridgeTypeAnnotation($MStatus.$type)), 'status': BridgeFieldDef(BridgeTypeAnnotation($MStatus.$type)),
'genre': BridgeFieldDef( 'genre': BridgeFieldDef(
BridgeTypeAnnotation( BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]),
), ),
), ),
'imageUrl': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'imageUrl': BridgeFieldDef(
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'link': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'name': BridgeFieldDef(
'description': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'chapters': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MChapter.$type]))), 'link': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'description': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'chapters': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MChapter.$type]))),
}, },
wrap: true); wrap: true);
@ -65,7 +76,8 @@ class $MManga implements MManga, $Instance {
case 'description': case 'description':
return $String($value.description!); return $String($value.description!);
case 'chapters': case 'chapters':
return $List.wrap($value.chapters!.map((e) => $MChapter.wrap(e)).toList()); return $List
.wrap($value.chapters!.map((e) => $MChapter.wrap(e)).toList());
default: default:
return _superclass.$getProperty(runtime, identifier); return _superclass.$getProperty(runtime, identifier);
@ -85,7 +97,8 @@ class $MManga implements MManga, $Instance {
case 'status': case 'status':
$value.status = value.$reified; $value.status = value.$reified;
case 'genre': case 'genre':
$value.genre = (value.$reified as List).map((e) => e.toString()).toList(); $value.genre =
(value.$reified as List).map((e) => e.toString()).toList();
case 'imageUrl': case 'imageUrl':
$value.imageUrl = value.$reified; $value.imageUrl = value.$reified;
case 'name': case 'name':
@ -96,7 +109,11 @@ class $MManga implements MManga, $Instance {
$value.description = value.$reified; $value.description = value.$reified;
case 'chapters': case 'chapters':
$value.chapters = (value.$reified as List) $value.chapters = (value.$reified as List)
.map((e) => MChapter(dateUpload: e.dateUpload, url: e.url, name: e.name, scanlator: e.scanlator)) .map((e) => MChapter(
dateUpload: e.dateUpload,
url: e.url,
name: e.name,
scanlator: e.scanlator))
.toList(); .toList();
default: default:

View file

@ -7,26 +7,40 @@ import 'package:mangayomi/eval/model/m_pages.dart';
class $MPages implements MPages, $Instance { class $MPages implements MPages, $Instance {
$MPages.wrap(this.$value) : _superclass = $Object($value); $MPages.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MPages')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MPages'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [ '': BridgeConstructorDef(
BridgeParameter('list', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MManga.$type])), false), BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [
BridgeParameter('hasNextPage', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool), nullable: true), true), BridgeParameter(
'list',
BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MManga.$type])),
false),
BridgeParameter(
'hasNextPage',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool),
nullable: true),
true),
])) ]))
}, },
fields: { fields: {
'list': BridgeFieldDef( 'list': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MManga.$type])), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MManga.$type])),
), ),
'hasNextPage': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool), nullable: true)), 'hasNextPage': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.bool),
nullable: true)),
}, },
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
List<$Value> list = args[0]!.$value; List<$Value> list = args[0]!.$value;
return $MPages.wrap(MPages(list: list.map((e) => e as MManga).toList(), hasNextPage: args[1]?.$value ?? false)); return $MPages.wrap(MPages(
list: list.map((e) => e as MManga).toList(),
hasNextPage: args[1]?.$value ?? false));
} }
@override @override

File diff suppressed because it is too large Load diff

View file

@ -5,21 +5,35 @@ import 'package:mangayomi/eval/model/m_source.dart';
class $MSource implements MSource, $Instance { class $MSource implements MSource, $Instance {
$MSource.wrap(this.$value) : _superclass = $Object($value); $MSource.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MSource')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MSource'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: {'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))}, constructors: {
'': BridgeConstructorDef(
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))
},
fields: { fields: {
'id': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))), 'id':
'name': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))),
'baseUrl': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'name': BridgeFieldDef(
'lang': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'isFullData': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))), 'baseUrl': BridgeFieldDef(
'hasCloudflare': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dateFormat': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'lang': BridgeFieldDef(
'dateFormatLocale': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'apiUrl': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'isFullData':
'additionalParams': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
'hasCloudflare':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
'dateFormat': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dateFormatLocale': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'apiUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'additionalParams': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);

View file

@ -3,14 +3,18 @@ import 'package:dart_eval/stdlib/core.dart';
import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/manga.dart';
class $MStatus implements $Instance { class $MStatus implements $Instance {
static $MStatus $wrap(Runtime runtime, $Value? target, List<$Value?> args) => $MStatus.wrap(args[0]!.$value); static $MStatus $wrap(Runtime runtime, $Value? target, List<$Value?> args) =>
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MStatus')); $MStatus.wrap(args[0]!.$value);
static const $declaration = BridgeEnumDef($type, static const $type = BridgeTypeRef(
values: ['ongoing', 'completed', 'canceled', 'unknown', 'onHiatus', 'publishingFinished'], BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MStatus'));
methods: {}, static const $declaration = BridgeEnumDef($type, values: [
getters: {}, 'ongoing',
setters: {}, 'completed',
fields: {}); 'canceled',
'unknown',
'onHiatus',
'publishingFinished'
], methods: {}, getters: {}, setters: {}, fields: {});
static final $values = Status.values.asNameMap().map( static final $values = Status.values.asNameMap().map(
(key, value) => MapEntry(key, $MStatus.wrap(value)), (key, value) => MapEntry(key, $MStatus.wrap(value)),
); );

View file

@ -5,7 +5,8 @@ import 'package:mangayomi/models/video.dart';
class $MTrack implements Track, $Instance { class $MTrack implements Track, $Instance {
$MTrack.wrap(this.$value) : _superclass = $Object($value); $MTrack.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MTrack')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MTrack'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
@ -15,8 +16,10 @@ class $MTrack implements Track, $Instance {
}, },
// Specify class fields // Specify class fields
fields: { fields: {
'file': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'file': BridgeFieldDef(
'label': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'label': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);

View file

@ -6,7 +6,8 @@ import 'package:mangayomi/models/video.dart';
class $MVideo implements Video, $Instance { class $MVideo implements Video, $Instance {
$MVideo.wrap(this.$value) : _superclass = $Object($value); $MVideo.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MVideo')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MVideo'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
@ -16,14 +17,22 @@ class $MVideo implements Video, $Instance {
}, },
// Specify class fields // Specify class fields
fields: { fields: {
'url': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'url': BridgeFieldDef(
'quality': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'originalUrl': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'quality': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'originalUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'headers': BridgeFieldDef(BridgeTypeAnnotation( 'headers': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.map, [BridgeTypeRef(CoreTypes.string), BridgeTypeRef(CoreTypes.string)]), BridgeTypeRef(CoreTypes.map, [
BridgeTypeRef(CoreTypes.string),
BridgeTypeRef(CoreTypes.string)
]),
nullable: true)), nullable: true)),
'subtitles': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))), 'subtitles': BridgeFieldDef(BridgeTypeAnnotation(
'audios': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))), BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))),
'audios': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [$MTrack.$type]))),
}, },
wrap: true); wrap: true);
@ -51,9 +60,13 @@ class $MVideo implements Video, $Instance {
case 'headers': case 'headers':
return $Map.wrap($value.headers ?? {}); return $Map.wrap($value.headers ?? {});
case 'subtitles': case 'subtitles':
return $List.wrap($value.subtitles!.map((e) => $MTrack.wrap(Track(file: e.file, label: e.label))).toList()); return $List.wrap($value.subtitles!
.map((e) => $MTrack.wrap(Track(file: e.file, label: e.label)))
.toList());
case 'audios': case 'audios':
return $List.wrap($value.audios!.map((e) => $MTrack.wrap(Track(file: e.file, label: e.label))).toList()); return $List.wrap($value.audios!
.map((e) => $MTrack.wrap(Track(file: e.file, label: e.label)))
.toList());
default: default:
return _superclass.$getProperty(runtime, identifier); return _superclass.$getProperty(runtime, identifier);
@ -73,12 +86,17 @@ class $MVideo implements Video, $Instance {
case 'originalUrl': case 'originalUrl':
$value.originalUrl = value.$reified; $value.originalUrl = value.$reified;
case 'headers': case 'headers':
$value.headers = (value.$reified as Map).map((key, value) => MapEntry(key.toString(), value.toString())); $value.headers = (value.$reified as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
case 'subtitles': case 'subtitles':
$value.subtitles = (value.$reified as List).map((e) => Track(file: e.file, label: e.label)).toList(); $value.subtitles = (value.$reified as List)
.map((e) => Track(file: e.file, label: e.label))
.toList();
case 'audios': case 'audios':
$value.audios = (value.$reified as List).map((e) => Track(file: e.file, label: e.label)).toList(); $value.audios = (value.$reified as List)
.map((e) => Track(file: e.file, label: e.label))
.toList();
default: default:
_superclass.$setProperty(runtime, identifier, value); _superclass.$setProperty(runtime, identifier, value);

View file

@ -6,30 +6,44 @@ import 'package:mangayomi/eval/model/source_preference.dart';
class $CheckBoxPreference implements SourcePreference, $Instance { class $CheckBoxPreference implements SourcePreference, $Instance {
$CheckBoxPreference.wrap(this.$value) : _superclass = $Object($value); $CheckBoxPreference.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'CheckBoxPreference')); static const $type = BridgeTypeRef(BridgeTypeSpec(
'package:mangayomi/bridge_lib.dart', 'CheckBoxPreference'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [], namedParams: [ '': BridgeConstructorDef(BridgeFunctionDef(
BridgeParameter('key', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), returns: BridgeTypeAnnotation($type),
BridgeParameter('title', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), params: [],
BridgeParameter('summary', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), namedParams: [
BridgeParameter('value', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), false), BridgeParameter('key',
])) BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('title',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('summary',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('value',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), false),
]))
}, },
fields: { fields: {
'key': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'key': BridgeFieldDef(
'title': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'summary': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'title': BridgeFieldDef(
'value': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'summary': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'value':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
}, },
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $CheckBoxPreference.wrap(SourcePreference( return $CheckBoxPreference.wrap(SourcePreference(
key: args[0]!.$value, key: args[0]!.$value,
checkBoxPreference: checkBoxPreference: CheckBoxPreference(
CheckBoxPreference(title: args[1]!.$value, summary: args[2]!.$value, value: args[3]!.$value))); title: args[1]!.$value,
summary: args[2]!.$value,
value: args[3]!.$value)));
} }
@override @override
@ -78,10 +92,12 @@ class $CheckBoxPreference implements SourcePreference, $Instance {
ListPreference? get listPreference => $value.listPreference; ListPreference? get listPreference => $value.listPreference;
@override @override
MultiSelectListPreference? get multiSelectListPreference => $value.multiSelectListPreference; MultiSelectListPreference? get multiSelectListPreference =>
$value.multiSelectListPreference;
@override @override
SwitchPreferenceCompat? get switchPreferenceCompat => $value.switchPreferenceCompat; SwitchPreferenceCompat? get switchPreferenceCompat =>
$value.switchPreferenceCompat;
@override @override
Id? get id => $value.id; Id? get id => $value.id;
@ -108,7 +124,8 @@ class $CheckBoxPreference implements SourcePreference, $Instance {
set listPreference(ListPreference? listPreference) {} set listPreference(ListPreference? listPreference) {}
@override @override
set multiSelectListPreference(MultiSelectListPreference? multiSelectListPreference) {} set multiSelectListPreference(
MultiSelectListPreference? multiSelectListPreference) {}
@override @override
set sourceId(int? sourceId) {} set sourceId(int? sourceId) {}
@ -125,30 +142,44 @@ class $CheckBoxPreference implements SourcePreference, $Instance {
class $SwitchPreferenceCompat implements SourcePreference, $Instance { class $SwitchPreferenceCompat implements SourcePreference, $Instance {
$SwitchPreferenceCompat.wrap(this.$value) : _superclass = $Object($value); $SwitchPreferenceCompat.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'SwitchPreferenceCompat')); static const $type = BridgeTypeRef(BridgeTypeSpec(
'package:mangayomi/bridge_lib.dart', 'SwitchPreferenceCompat'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [], namedParams: [ '': BridgeConstructorDef(BridgeFunctionDef(
BridgeParameter('key', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), returns: BridgeTypeAnnotation($type),
BridgeParameter('title', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), params: [],
BridgeParameter('summary', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), namedParams: [
BridgeParameter('value', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), false), BridgeParameter('key',
])) BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('title',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('summary',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('value',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool)), false),
]))
}, },
fields: { fields: {
'key': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'key': BridgeFieldDef(
'title': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'summary': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'title': BridgeFieldDef(
'value': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'summary': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'value':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
}, },
wrap: true); wrap: true);
static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) { static $Value? $new(Runtime runtime, $Value? target, List<$Value?> args) {
return $SwitchPreferenceCompat.wrap(SourcePreference( return $SwitchPreferenceCompat.wrap(SourcePreference(
key: args[0]!.$value, key: args[0]!.$value,
switchPreferenceCompat: switchPreferenceCompat: SwitchPreferenceCompat(
SwitchPreferenceCompat(title: args[1]!.$value, summary: args[2]!.$value, value: args[3]!.$value))); title: args[1]!.$value,
summary: args[2]!.$value,
value: args[3]!.$value)));
} }
@override @override
@ -197,10 +228,12 @@ class $SwitchPreferenceCompat implements SourcePreference, $Instance {
ListPreference? get listPreference => $value.listPreference; ListPreference? get listPreference => $value.listPreference;
@override @override
MultiSelectListPreference? get multiSelectListPreference => $value.multiSelectListPreference; MultiSelectListPreference? get multiSelectListPreference =>
$value.multiSelectListPreference;
@override @override
SwitchPreferenceCompat? get switchPreferenceCompat => $value.switchPreferenceCompat; SwitchPreferenceCompat? get switchPreferenceCompat =>
$value.switchPreferenceCompat;
@override @override
Id? get id => $value.id; Id? get id => $value.id;
@ -227,7 +260,8 @@ class $SwitchPreferenceCompat implements SourcePreference, $Instance {
set listPreference(ListPreference? listPreference) {} set listPreference(ListPreference? listPreference) {}
@override @override
set multiSelectListPreference(MultiSelectListPreference? multiSelectListPreference) {} set multiSelectListPreference(
MultiSelectListPreference? multiSelectListPreference) {}
@override @override
set sourceId(int? sourceId) {} set sourceId(int? sourceId) {}
@ -244,30 +278,48 @@ class $SwitchPreferenceCompat implements SourcePreference, $Instance {
class $ListPreference implements SourcePreference, $Instance { class $ListPreference implements SourcePreference, $Instance {
$ListPreference.wrap(this.$value) : _superclass = $Object($value); $ListPreference.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'ListPreference')); static const $type = BridgeTypeRef(
BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'ListPreference'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [], namedParams: [ '': BridgeConstructorDef(BridgeFunctionDef(
BridgeParameter('key', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), returns: BridgeTypeAnnotation($type),
BridgeParameter('title', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), params: [],
BridgeParameter('summary', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), namedParams: [
BridgeParameter('valueIndex', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), false), BridgeParameter('key',
BridgeParameter( BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
'entries', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])), false), BridgeParameter('title',
BridgeParameter('entryValues', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])), false), BridgeParameter('summary',
])) BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('valueIndex',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int)), false),
BridgeParameter(
'entries',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
false),
BridgeParameter(
'entryValues',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
false),
]))
}, },
fields: { fields: {
'key': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'key': BridgeFieldDef(
'title': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'summary': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'title': BridgeFieldDef(
'valueIndex': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'entries': 'summary': BridgeFieldDef(
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'entryValues': 'valueIndex':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))), BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))),
'entries': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))),
'entryValues': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))),
}, },
wrap: true); wrap: true);
@ -278,8 +330,12 @@ class $ListPreference implements SourcePreference, $Instance {
title: args[1]!.$value, title: args[1]!.$value,
summary: args[2]!.$value, summary: args[2]!.$value,
valueIndex: args[3]!.$value, valueIndex: args[3]!.$value,
entries: (args[4]!.$value as List).map((e) => (e is $Value ? e.$reified : e).toString()).toList(), entries: (args[4]!.$value as List)
entryValues: (args[5]!.$value as List).map((e) => (e is $Value ? e.$reified : e).toString()).toList()))); .map((e) => (e is $Value ? e.$reified : e).toString())
.toList(),
entryValues: (args[5]!.$value as List)
.map((e) => (e is $Value ? e.$reified : e).toString())
.toList())));
} }
@override @override
@ -332,10 +388,12 @@ class $ListPreference implements SourcePreference, $Instance {
ListPreference? get listPreference => $value.listPreference; ListPreference? get listPreference => $value.listPreference;
@override @override
MultiSelectListPreference? get multiSelectListPreference => $value.multiSelectListPreference; MultiSelectListPreference? get multiSelectListPreference =>
$value.multiSelectListPreference;
@override @override
SwitchPreferenceCompat? get switchPreferenceCompat => $value.switchPreferenceCompat; SwitchPreferenceCompat? get switchPreferenceCompat =>
$value.switchPreferenceCompat;
@override @override
Id? get id => $value.id; Id? get id => $value.id;
@ -362,7 +420,8 @@ class $ListPreference implements SourcePreference, $Instance {
set listPreference(ListPreference? listPreference) {} set listPreference(ListPreference? listPreference) {}
@override @override
set multiSelectListPreference(MultiSelectListPreference? multiSelectListPreference) {} set multiSelectListPreference(
MultiSelectListPreference? multiSelectListPreference) {}
@override @override
set sourceId(int? sourceId) {} set sourceId(int? sourceId) {}
@ -379,32 +438,51 @@ class $ListPreference implements SourcePreference, $Instance {
class $MultiSelectListPreference implements SourcePreference, $Instance { class $MultiSelectListPreference implements SourcePreference, $Instance {
$MultiSelectListPreference.wrap(this.$value) : _superclass = $Object($value); $MultiSelectListPreference.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'MultiSelectListPreference')); static const $type = BridgeTypeRef(BridgeTypeSpec(
'package:mangayomi/bridge_lib.dart', 'MultiSelectListPreference'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [], namedParams: [ '': BridgeConstructorDef(BridgeFunctionDef(
BridgeParameter('key', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), returns: BridgeTypeAnnotation($type),
BridgeParameter('title', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), params: [],
BridgeParameter('summary', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), namedParams: [
BridgeParameter( BridgeParameter('key',
'entries', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('entryValues', BridgeParameter('title',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter( BridgeParameter('summary',
'values', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
])) BridgeParameter(
'entries',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
false),
BridgeParameter(
'entryValues',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
false),
BridgeParameter(
'values',
BridgeTypeAnnotation(BridgeTypeRef(
CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])),
false),
]))
}, },
fields: { fields: {
'key': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'key': BridgeFieldDef(
'title': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'summary': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'title': BridgeFieldDef(
'entries': BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))), 'summary': BridgeFieldDef(
'entryValues': BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))), 'entries': BridgeFieldDef(BridgeTypeAnnotation(
'values': BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))),
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))), 'entryValues': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))),
'values': BridgeFieldDef(BridgeTypeAnnotation(
BridgeTypeRef(CoreTypes.list, [BridgeTypeRef(CoreTypes.string)]))),
}, },
wrap: true); wrap: true);
@ -414,9 +492,15 @@ class $MultiSelectListPreference implements SourcePreference, $Instance {
multiSelectListPreference: MultiSelectListPreference( multiSelectListPreference: MultiSelectListPreference(
title: args[1]!.$value, title: args[1]!.$value,
summary: args[2]!.$value, summary: args[2]!.$value,
entries: (args[3]!.$value as List).map((e) => (e is $Value ? e.$reified : e).toString()).toList(), entries: (args[3]!.$value as List)
entryValues: (args[4]!.$value as List).map((e) => (e is $Value ? e.$reified : e).toString()).toList(), .map((e) => (e is $Value ? e.$reified : e).toString())
values: (args[5]!.$value as List).map((e) => (e is $Value ? e.$reified : e).toString()).toList()))); .toList(),
entryValues: (args[4]!.$value as List)
.map((e) => (e is $Value ? e.$reified : e).toString())
.toList(),
values: (args[5]!.$value as List)
.map((e) => (e is $Value ? e.$reified : e).toString())
.toList())));
} }
@override @override
@ -469,10 +553,12 @@ class $MultiSelectListPreference implements SourcePreference, $Instance {
ListPreference? get listPreference => $value.listPreference; ListPreference? get listPreference => $value.listPreference;
@override @override
MultiSelectListPreference? get multiSelectListPreference => $value.multiSelectListPreference; MultiSelectListPreference? get multiSelectListPreference =>
$value.multiSelectListPreference;
@override @override
SwitchPreferenceCompat? get switchPreferenceCompat => $value.switchPreferenceCompat; SwitchPreferenceCompat? get switchPreferenceCompat =>
$value.switchPreferenceCompat;
@override @override
Id? get id => $value.id; Id? get id => $value.id;
@ -499,7 +585,8 @@ class $MultiSelectListPreference implements SourcePreference, $Instance {
set listPreference(ListPreference? listPreference) {} set listPreference(ListPreference? listPreference) {}
@override @override
set multiSelectListPreference(MultiSelectListPreference? multiSelectListPreference) {} set multiSelectListPreference(
MultiSelectListPreference? multiSelectListPreference) {}
@override @override
set sourceId(int? sourceId) {} set sourceId(int? sourceId) {}
@ -516,28 +603,46 @@ class $MultiSelectListPreference implements SourcePreference, $Instance {
class $EditTextPreference implements SourcePreference, $Instance { class $EditTextPreference implements SourcePreference, $Instance {
$EditTextPreference.wrap(this.$value) : _superclass = $Object($value); $EditTextPreference.wrap(this.$value) : _superclass = $Object($value);
static const $type = BridgeTypeRef(BridgeTypeSpec('package:mangayomi/bridge_lib.dart', 'EditTextPreference')); static const $type = BridgeTypeRef(BridgeTypeSpec(
'package:mangayomi/bridge_lib.dart', 'EditTextPreference'));
static const $declaration = BridgeClassDef(BridgeClassType($type), static const $declaration = BridgeClassDef(BridgeClassType($type),
constructors: { constructors: {
'': BridgeConstructorDef(BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: [], namedParams: [ '': BridgeConstructorDef(BridgeFunctionDef(
BridgeParameter('key', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), returns: BridgeTypeAnnotation($type),
BridgeParameter('title', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), params: [],
BridgeParameter('summary', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), namedParams: [
BridgeParameter('value', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('key',
BridgeParameter('dialogTitle', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('dialogMessage', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeParameter('title',
BridgeParameter('text', BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
])) BridgeParameter('summary',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('value',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('dialogTitle',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('dialogMessage',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
BridgeParameter('text',
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), false),
]))
}, },
fields: { fields: {
'key': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'key': BridgeFieldDef(
'title': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'summary': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'title': BridgeFieldDef(
'value': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dialogTitle': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'summary': BridgeFieldDef(
'dialogMessage': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'text': BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))), 'value': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dialogTitle': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dialogMessage': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'text': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
}, },
wrap: true); wrap: true);
@ -605,10 +710,12 @@ class $EditTextPreference implements SourcePreference, $Instance {
ListPreference? get listPreference => $value.listPreference; ListPreference? get listPreference => $value.listPreference;
@override @override
MultiSelectListPreference? get multiSelectListPreference => $value.multiSelectListPreference; MultiSelectListPreference? get multiSelectListPreference =>
$value.multiSelectListPreference;
@override @override
SwitchPreferenceCompat? get switchPreferenceCompat => $value.switchPreferenceCompat; SwitchPreferenceCompat? get switchPreferenceCompat =>
$value.switchPreferenceCompat;
@override @override
Id? get id => $value.id; Id? get id => $value.id;
@ -635,7 +742,8 @@ class $EditTextPreference implements SourcePreference, $Instance {
set listPreference(ListPreference? listPreference) {} set listPreference(ListPreference? listPreference) {}
@override @override
set multiSelectListPreference(MultiSelectListPreference? multiSelectListPreference) {} set multiSelectListPreference(
MultiSelectListPreference? multiSelectListPreference) {}
@override @override
set sourceId(int? sourceId) {} set sourceId(int? sourceId) {}

View file

@ -61,39 +61,64 @@ class MEvalPlugin extends EvalPlugin {
@override @override
void configureForRuntime(Runtime runtime) { void configureForRuntime(Runtime runtime) {
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MProvider.', $MProvider.$construct, runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'MProvider.', $MProvider.$construct,
isBridge: true); isBridge: true);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MChapter.', $MChapter.$new); runtime.registerBridgeFunc(
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MManga.', $MManga.$new); 'package:mangayomi/bridge_lib.dart', 'MChapter.', $MChapter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MPages.', $MPages.$new); runtime.registerBridgeFunc(
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MSource.', $MSource.$new); 'package:mangayomi/bridge_lib.dart', 'MManga.', $MManga.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MVideo.', $MVideo.$new); runtime.registerBridgeFunc(
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MTrack.', $MTrack.$new); 'package:mangayomi/bridge_lib.dart', 'MPages.', $MPages.$new);
runtime.registerBridgeEnumValues('package:mangayomi/bridge_lib.dart', 'MStatus', $MStatus.$values); runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MSource.', $MSource.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MVideo.', $MVideo.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MTrack.', $MTrack.$new);
runtime.registerBridgeEnumValues(
'package:mangayomi/bridge_lib.dart', 'MStatus', $MStatus.$values);
//Filter //Filter
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'FilterList.', $FilterList.$new); runtime.registerBridgeFunc(
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'SelectFilter.', $SelectFilter.$new); 'package:mangayomi/bridge_lib.dart', 'FilterList.', $FilterList.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'SeparatorFilter.', $SeparatorFilter.$new); runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'HeaderFilter.', $HeaderFilter.$new); 'SelectFilter.', $SelectFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'TextFilter.', $TextFilter.$new); runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'SortFilter.', $SortFilter.$new); 'SeparatorFilter.', $SeparatorFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'TriStateFilter.', $TriStateFilter.$new); runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'GroupFilter.', $GroupFilter.$new); 'HeaderFilter.', $HeaderFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'CheckBoxFilter.', $CheckBoxFilter.$new); runtime.registerBridgeFunc(
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'SortState.', $SortState.$new); 'package:mangayomi/bridge_lib.dart', 'TextFilter.', $TextFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'SelectFilterOption.', $SelectFilterOption.$new); runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'SortFilter.', $SortFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'TriStateFilter.', $TriStateFilter.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'GroupFilter.', $GroupFilter.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'CheckBoxFilter.', $CheckBoxFilter.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'SortState.', $SortState.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'SelectFilterOption.', $SelectFilterOption.$new);
//Sources preferences //Sources preferences
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'CheckBoxPreference.', $CheckBoxPreference.$new); runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
runtime.registerBridgeFunc( 'CheckBoxPreference.', $CheckBoxPreference.$new);
'package:mangayomi/bridge_lib.dart', 'SwitchPreferenceCompat.', $SwitchPreferenceCompat.$new); runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'ListPreference.', $ListPreference.$new); 'SwitchPreferenceCompat.', $SwitchPreferenceCompat.$new);
runtime.registerBridgeFunc( runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'package:mangayomi/bridge_lib.dart', 'MultiSelectListPreference.', $MultiSelectListPreference.$new); 'ListPreference.', $ListPreference.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'EditTextPreference.', $EditTextPreference.$new); runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'MultiSelectListPreference.', $MultiSelectListPreference.$new);
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart',
'EditTextPreference.', $EditTextPreference.$new);
//DOM HTML //DOM HTML
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MElement.', $MElement.$new); runtime.registerBridgeFunc(
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'MDocument.', $MDocument.$new); 'package:mangayomi/bridge_lib.dart', 'MElement.', $MElement.$new);
runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'MDocument.', $MDocument.$new);
//HTTP CLIENT //HTTP CLIENT
runtime.registerBridgeFunc('package:mangayomi/bridge_lib.dart', 'Client.', $Client.$new); runtime.registerBridgeFunc(
'package:mangayomi/bridge_lib.dart', 'Client.', $Client.$new);
} }
} }

View file

@ -26,7 +26,8 @@ class DartExtensionService implements ExtensionService {
final runtime = runtimeEval(bytecode); final runtime = runtimeEval(bytecode);
return runtime.executeLib('package:mangayomi/main.dart', 'main', [$MSource.wrap(source.toMSource())]) as MProvider; return runtime.executeLib('package:mangayomi/main.dart', 'main',
[$MSource.wrap(source.toMSource())]) as MProvider;
} }
@override @override
@ -103,7 +104,9 @@ class DartExtensionService implements ExtensionService {
@override @override
Future<List<PageUrl>> getPageList(String url) async { Future<List<PageUrl>> getPageList(String url) async {
return (await _executeLib().getPageList(url)) return (await _executeLib().getPageList(url))
.map((e) => e is String ? PageUrl(e.toString().trim()) : PageUrl.fromJson((e as Map).toMapStringDynamic!)) .map((e) => e is String
? PageUrl(e.toString().trim())
: PageUrl.fromJson((e as Map).toMapStringDynamic!))
.toList(); .toList();
} }
@ -117,7 +120,10 @@ class DartExtensionService implements ExtensionService {
List<dynamic> list; List<dynamic> list;
try { try {
list = _executeLib().getFilterList().map((e) => e is $Value ? e.$reified : e).toList(); list = _executeLib()
.getFilterList()
.map((e) => e is $Value ? e.$reified : e)
.toList();
} catch (_) { } catch (_) {
list = []; list = [];
} }

View file

@ -67,8 +67,10 @@ class JsDomSelector {
final type = args[0]; final type = args[0];
final key = args[1]; final key = args[1];
final ele = _elements[key]; final ele = _elements[key];
final element = final element = switch (type) {
switch (type) { 'nextElementSibling' => ele?.nextElementSibling, _ => ele?.previousElementSibling }; 'nextElementSibling' => ele?.nextElementSibling,
_ => ele?.previousElementSibling
};
_elementKey++; _elementKey++;
_elements[_elementKey] = element; _elements[_elementKey] = element;
return _elementKey; return _elementKey;

View file

@ -10,7 +10,8 @@ class JsVideosExtractors {
void init() { void init() {
runtime.onMessage('sibnetExtractor', (dynamic args) async { runtime.onMessage('sibnetExtractor', (dynamic args) async {
return (await MBridge.sibnetExtractor(args[0], args[1] ?? "")).encodeToJson(); return (await MBridge.sibnetExtractor(args[0], args[1] ?? ""))
.encodeToJson();
}); });
runtime.onMessage('myTvExtractor', (dynamic args) async { runtime.onMessage('myTvExtractor', (dynamic args) async {
return (await MBridge.myTvExtractor(args[0])).encodeToJson(); return (await MBridge.myTvExtractor(args[0])).encodeToJson();
@ -25,7 +26,8 @@ class JsVideosExtractors {
return (await MBridge.vidBomExtractor(args[0])).encodeToJson(); return (await MBridge.vidBomExtractor(args[0])).encodeToJson();
}); });
runtime.onMessage('quarkVideosExtractor', (dynamic args) async { runtime.onMessage('quarkVideosExtractor', (dynamic args) async {
return (await MBridge.quarkVideosExtractor(args[0], args[1])).encodeToJson(); return (await MBridge.quarkVideosExtractor(args[0], args[1]))
.encodeToJson();
}); });
runtime.onMessage('ucVideosExtractor', (dynamic args) async { runtime.onMessage('ucVideosExtractor', (dynamic args) async {
return (await MBridge.ucVideosExtractor(args[0], args[1])).encodeToJson(); return (await MBridge.ucVideosExtractor(args[0], args[1])).encodeToJson();
@ -39,16 +41,27 @@ class JsVideosExtractors {
return (await MBridge.ucFilesExtractor(urls, args[1])); return (await MBridge.ucFilesExtractor(urls, args[1]));
}); });
runtime.onMessage('streamlareExtractor', (dynamic args) async { runtime.onMessage('streamlareExtractor', (dynamic args) async {
return (await MBridge.streamlareExtractor(args[0], args[1] ?? "", args[2] ?? "")).encodeToJson(); return (await MBridge.streamlareExtractor(
args[0], args[1] ?? "", args[2] ?? ""))
.encodeToJson();
}); });
runtime.onMessage('sendVidExtractor', (dynamic args) async { runtime.onMessage('sendVidExtractor', (dynamic args) async {
return (await MBridge.sendVidExtractor( return (await MBridge.sendVidExtractor(
args[0], args[1] != null ? jsonEncode((args[1] as Map?).toMapStringString) : null, args[2] ?? "")) args[0],
args[1] != null
? jsonEncode((args[1] as Map?).toMapStringString)
: null,
args[2] ?? ""))
.encodeToJson(); .encodeToJson();
}); });
runtime.onMessage('yourUploadExtractor', (dynamic args) async { runtime.onMessage('yourUploadExtractor', (dynamic args) async {
return (await MBridge.yourUploadExtractor(args[0], return (await MBridge.yourUploadExtractor(
args[1] != null ? jsonEncode((args[1] as Map?).toMapStringString) : null, args[2], args[3] ?? "")) args[0],
args[1] != null
? jsonEncode((args[1] as Map?).toMapStringString)
: null,
args[2],
args[3] ?? ""))
.encodeToJson(); .encodeToJson();
}); });
runtime.onMessage('gogoCdnExtractor', (dynamic args) async { runtime.onMessage('gogoCdnExtractor', (dynamic args) async {
@ -58,18 +71,27 @@ class JsVideosExtractors {
return (await MBridge.doodExtractor(args[0], args[1])).encodeToJson(); return (await MBridge.doodExtractor(args[0], args[1])).encodeToJson();
}); });
runtime.onMessage('streamTapeExtractor', (dynamic args) async { runtime.onMessage('streamTapeExtractor', (dynamic args) async {
return (await MBridge.streamTapeExtractor(args[0], args[1])).encodeToJson(); return (await MBridge.streamTapeExtractor(args[0], args[1]))
.encodeToJson();
}); });
runtime.onMessage('mp4UploadExtractor', (dynamic args) async { runtime.onMessage('mp4UploadExtractor', (dynamic args) async {
return (await MBridge.mp4UploadExtractor(args[0], return (await MBridge.mp4UploadExtractor(
args[1] != null ? jsonEncode((args[1] as Map?).toMapStringString) : null, args[2] ?? "", args[3] ?? "")) args[0],
args[1] != null
? jsonEncode((args[1] as Map?).toMapStringString)
: null,
args[2] ?? "",
args[3] ?? ""))
.encodeToJson(); .encodeToJson();
}); });
runtime.onMessage('streamWishExtractor', (dynamic args) async { runtime.onMessage('streamWishExtractor', (dynamic args) async {
return (await MBridge.streamWishExtractor(args[0], args[1] ?? "")).encodeToJson(); return (await MBridge.streamWishExtractor(args[0], args[1] ?? ""))
.encodeToJson();
}); });
runtime.onMessage('filemoonExtractor', (dynamic args) async { runtime.onMessage('filemoonExtractor', (dynamic args) async {
return (await MBridge.filemoonExtractor(args[0], args[1] ?? "", args[2] ?? "")).encodeToJson(); return (await MBridge.filemoonExtractor(
args[0], args[1] ?? "", args[2] ?? ""))
.encodeToJson();
}); });
runtime.evaluate(''' runtime.evaluate('''

View file

@ -11,7 +11,8 @@ class JsHttpClient {
void init() { void init() {
InterceptedClient client(dynamic reqcopyWith) { InterceptedClient client(dynamic reqcopyWith) {
return MClient.init(reqcopyWith: (reqcopyWith as Map?)?.toMapStringDynamic); return MClient.init(
reqcopyWith: (reqcopyWith as Map?)?.toMapStringDynamic);
} }
runtime.onMessage('http_get', (dynamic args) async { runtime.onMessage('http_get', (dynamic args) async {
@ -85,7 +86,9 @@ Future<String> _toHttpResponse(Client client, String method, List args) async {
final body = args.length >= 5 ? (args[4] as Map?)?.toMapStringDynamic : null; final body = args.length >= 5 ? (args[4] as Map?)?.toMapStringDynamic : null;
var request = http.Request(method, Uri.parse(url)); var request = http.Request(method, Uri.parse(url));
request.headers.addAll(headers ?? {}); request.headers.addAll(headers ?? {});
if ((request.headers[HttpHeaders.contentTypeHeader]?.contains("application/json")) ?? false) { if ((request.headers[HttpHeaders.contentTypeHeader]
?.contains("application/json")) ??
false) {
request.body = json.encode(body); request.body = json.encode(body);
request.headers.addAll(headers ?? {}); request.headers.addAll(headers ?? {});
http.StreamedResponse response = await client.send(request); http.StreamedResponse response = await client.send(request);
@ -136,6 +139,7 @@ extension ToMapExtension on Map? {
} }
Map<String, String>? get toMapStringString { Map<String, String>? get toMapStringString {
return this?.map((key, value) => MapEntry(key.toString(), value.toString())); return this
?.map((key, value) => MapEntry(key.toString(), value.toString()));
} }
} }

View file

@ -78,7 +78,8 @@ var extention = new DefaultExtension();
@override @override
Map<String, String> getHeaders() { Map<String, String> getHeaders() {
return _extensionCall<Map>('getHeaders(`${source.baseUrl ?? ''}`)', {}).toMapStringString!; return _extensionCall<Map>('getHeaders(`${source.baseUrl ?? ''}`)', {})
.toMapStringString!;
} }
@override @override
@ -98,13 +99,15 @@ var extention = new DefaultExtension();
@override @override
Future<MPages> getLatestUpdates(int page) async { Future<MPages> getLatestUpdates(int page) async {
return MPages.fromJson(await _extensionCallAsync('getLatestUpdates($page)', {})); return MPages.fromJson(
await _extensionCallAsync('getLatestUpdates($page)', {}));
} }
@override @override
Future<MPages> search(String query, int page, List<dynamic> filters) async { Future<MPages> search(String query, int page, List<dynamic> filters) async {
return MPages.fromJson( return MPages.fromJson(await _extensionCallAsync(
await _extensionCallAsync('search("$query",$page,${jsonEncode(filterValuesListToJson(filters))})', {})); 'search("$query",$page,${jsonEncode(filterValuesListToJson(filters))})',
{}));
} }
@override @override
@ -115,14 +118,17 @@ var extention = new DefaultExtension();
@override @override
Future<List<PageUrl>> getPageList(String url) async { Future<List<PageUrl>> getPageList(String url) async {
return (await _extensionCallAsync<List>('getPageList(`$url`)', [])) return (await _extensionCallAsync<List>('getPageList(`$url`)', []))
.map((e) => e is String ? PageUrl(e.trim()) : PageUrl.fromJson((e as Map).toMapStringDynamic!)) .map((e) => e is String
? PageUrl(e.trim())
: PageUrl.fromJson((e as Map).toMapStringDynamic!))
.toList(); .toList();
} }
@override @override
Future<List<Video>> getVideoList(String url) async { Future<List<Video>> getVideoList(String url) async {
return (await _extensionCallAsync<List>('getVideoList(`$url`)', [])) return (await _extensionCallAsync<List>('getVideoList(`$url`)', []))
.where((element) => element['url'] != null && element['originalUrl'] != null) .where((element) =>
element['url'] != null && element['originalUrl'] != null)
.map((e) => Video.fromJson(e)) .map((e) => Video.fromJson(e))
.toList() .toList()
.toSet() .toSet()
@ -149,12 +155,11 @@ var extention = new DefaultExtension();
.toList(); .toList();
} }
T _extensionCall<T>(String call, T def) { T _extensionCall<T>(String call, T def) {
_init(); _init();
try { try {
final res = runtime.evaluate('JSON.stringify(extention.`$call`)'); final res = runtime.evaluate('JSON.stringify(extention.$call)');
return jsonDecode(res.stringResult) as T; return jsonDecode(res.stringResult) as T;
} catch (_) { } catch (_) {
@ -170,7 +175,8 @@ var extention = new DefaultExtension();
_init(); _init();
try { try {
final promised = await runtime.handlePromise(await runtime.evaluateAsync('jsonStringify(() => extention.$call)')); final promised = await runtime.handlePromise(
await runtime.evaluateAsync('jsonStringify(() => extention.$call)'));
return jsonDecode(promised.stringResult) as T; return jsonDecode(promised.stringResult) as T;
} catch (_) { } catch (_) {

View file

@ -19,7 +19,8 @@ class MDocument {
String? get text => _document?.text; String? get text => _document?.text;
List<MElement>? get children => _document?.children.map((e) => MElement(e)).toList(); List<MElement>? get children =>
_document?.children.map((e) => MElement(e)).toList();
List<MElement>? select(String selector) { List<MElement>? select(String selector) {
return _document?.select(selector)?.map((e) => MElement(e)).toList(); return _document?.select(selector)?.map((e) => MElement(e)).toList();
@ -34,11 +35,17 @@ class MDocument {
} }
List<MElement>? getElementsByClassName(String classNames) { List<MElement>? getElementsByClassName(String classNames) {
return _document?.getElementsByClassName(classNames).map((e) => MElement(e)).toList(); return _document
?.getElementsByClassName(classNames)
.map((e) => MElement(e))
.toList();
} }
List<MElement>? getElementsByTagName(String localNames) { List<MElement>? getElementsByTagName(String localNames) {
return _document?.getElementsByTagName(localNames).map((e) => MElement(e)).toList(); return _document
?.getElementsByTagName(localNames)
.map((e) => MElement(e))
.toList();
} }
MElement? getElementById(String id) { MElement? getElementById(String id) {

View file

@ -26,13 +26,15 @@ class MElement {
String? get getDataSrc => _element?.getDataSrc; String? get getDataSrc => _element?.getDataSrc;
List<MElement>? get children => _element?.children.map((e) => MElement(e)).toList(); List<MElement>? get children =>
_element?.children.map((e) => MElement(e)).toList();
MElement? get parent => MElement(_element?.parent); MElement? get parent => MElement(_element?.parent);
MElement? get nextElementSibling => MElement(_element?.nextElementSibling); MElement? get nextElementSibling => MElement(_element?.nextElementSibling);
MElement? get previousElementSibling => MElement(_element?.previousElementSibling); MElement? get previousElementSibling =>
MElement(_element?.previousElementSibling);
String? xpathFirst(String xpath) { String? xpathFirst(String xpath) {
return _element?.outerHtml == null ? null : _element?.xpathFirst(xpath); return _element?.outerHtml == null ? null : _element?.xpathFirst(xpath);
@ -43,11 +45,17 @@ class MElement {
} }
List<MElement>? getElementsByClassName(String classNames) { List<MElement>? getElementsByClassName(String classNames) {
return _element?.getElementsByClassName(classNames).map((e) => MElement(e)).toList(); return _element
?.getElementsByClassName(classNames)
.map((e) => MElement(e))
.toList();
} }
List<MElement>? getElementsByTagName(String localNames) { List<MElement>? getElementsByTagName(String localNames) {
return _element?.getElementsByTagName(localNames).map((e) => MElement(e)).toList(); return _element
?.getElementsByTagName(localNames)
.map((e) => MElement(e))
.toList();
} }
List<MElement>? select(String selector) { List<MElement>? select(String selector) {

View file

@ -18,8 +18,8 @@ class SelectFilter {
SelectFilter(this.type, this.name, this.state, this.values, this.typeName); SelectFilter(this.type, this.name, this.state, this.values, this.typeName);
factory SelectFilter.fromJson(Map<String, dynamic> json) { factory SelectFilter.fromJson(Map<String, dynamic> json) {
return SelectFilter( return SelectFilter(json['type'], json['name'], json['state'] ?? 0,
json['type'], json['name'], json['state'] ?? 0, fromJsonFilterValuesToList(json['values']), json['type_name']); fromJsonFilterValuesToList(json['values']), json['type_name']);
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'type': type, 'type': type,
@ -39,7 +39,8 @@ class SelectFilterOption {
factory SelectFilterOption.fromJson(Map<String, dynamic> json) { factory SelectFilterOption.fromJson(Map<String, dynamic> json) {
return SelectFilterOption(json['name'], json['value'], json['type_name']); return SelectFilterOption(json['name'], json['value'], json['type_name']);
} }
Map<String, dynamic> toJson() => {'value': value, 'name': name, 'type_name': "SelectOption"}; Map<String, dynamic> toJson() =>
{'value': value, 'name': name, 'type_name': "SelectOption"};
} }
class SeparatorFilter { class SeparatorFilter {
@ -49,7 +50,8 @@ class SeparatorFilter {
factory SeparatorFilter.fromJson(Map<String, dynamic> json) { factory SeparatorFilter.fromJson(Map<String, dynamic> json) {
return SeparatorFilter(type: json['type'], json['type_name']); return SeparatorFilter(type: json['type'], json['type_name']);
} }
Map<String, dynamic> toJson() => {'type': type, 'type_name': "SeparatorFilter"}; Map<String, dynamic> toJson() =>
{'type': type, 'type_name': "SeparatorFilter"};
} }
class HeaderFilter { class HeaderFilter {
@ -60,7 +62,8 @@ class HeaderFilter {
factory HeaderFilter.fromJson(Map<String, dynamic> json) { factory HeaderFilter.fromJson(Map<String, dynamic> json) {
return HeaderFilter(json['name'], json['type_name'], type: json['value']); return HeaderFilter(json['name'], json['type_name'], type: json['value']);
} }
Map<String, dynamic> toJson() => {'type': type, 'name': name, 'type_name': "HeaderFilter"}; Map<String, dynamic> toJson() =>
{'type': type, 'name': name, 'type_name': "HeaderFilter"};
} }
class TextFilter { class TextFilter {
@ -71,9 +74,11 @@ class TextFilter {
TextFilter(this.type, this.name, this.typeName, {this.state = ""}); TextFilter(this.type, this.name, this.typeName, {this.state = ""});
factory TextFilter.fromJson(Map<String, dynamic> json) { factory TextFilter.fromJson(Map<String, dynamic> json) {
return TextFilter(json['type'], json['name'], json['type_name'], state: json['state'] ?? ""); return TextFilter(json['type'], json['name'], json['type_name'],
state: json['state'] ?? "");
} }
Map<String, dynamic> toJson() => {'type': type, 'name': name, 'state': state, 'type_name': "TextFilter"}; Map<String, dynamic> toJson() =>
{'type': type, 'name': name, 'state': state, 'type_name': "TextFilter"};
} }
class SortFilter { class SortFilter {
@ -88,7 +93,9 @@ class SortFilter {
return SortFilter( return SortFilter(
json['type'], json['type'],
json['name'], json['name'],
json['state'] == null ? SortState(0, false, "") : SortState.fromJson(json['state']), json['state'] == null
? SortState(0, false, "")
: SortState.fromJson(json['state']),
fromJsonFilterValuesToList(json['values']), fromJsonFilterValuesToList(json['values']),
json['type_name']); json['type_name']);
} }
@ -110,7 +117,8 @@ class SortState {
factory SortState.fromJson(Map<String, dynamic> json) { factory SortState.fromJson(Map<String, dynamic> json) {
return SortState(json['index'], json['ascending'], json['type_name']); return SortState(json['index'], json['ascending'], json['type_name']);
} }
Map<String, dynamic> toJson() => {'index': index, 'ascending': ascending, 'type_name': "SortState"}; Map<String, dynamic> toJson() =>
{'index': index, 'ascending': ascending, 'type_name': "SortState"};
} }
class TriStateFilter { class TriStateFilter {
@ -121,11 +129,19 @@ class TriStateFilter {
String? typeName; String? typeName;
factory TriStateFilter.fromJson(Map<String, dynamic> json) { factory TriStateFilter.fromJson(Map<String, dynamic> json) {
return TriStateFilter(json['type'], json['name'], json['value'], json['type_name'], state: json['state'] ?? 0); return TriStateFilter(
json['type'], json['name'], json['value'], json['type_name'],
state: json['state'] ?? 0);
} }
TriStateFilter(this.type, this.name, this.value, this.typeName, {this.state = 0}); TriStateFilter(this.type, this.name, this.value, this.typeName,
Map<String, dynamic> toJson() => {this.state = 0});
{'type': type, 'name': name, 'value': value, 'state': state, 'type_name': "TriState"}; Map<String, dynamic> toJson() => {
'type': type,
'name': name,
'value': value,
'state': state,
'type_name': "TriState"
};
} }
class GroupFilter { class GroupFilter {
@ -136,10 +152,15 @@ class GroupFilter {
GroupFilter(this.type, this.name, this.state, this.typeName); GroupFilter(this.type, this.name, this.state, this.typeName);
factory GroupFilter.fromJson(Map<String, dynamic> json) { factory GroupFilter.fromJson(Map<String, dynamic> json) {
return GroupFilter(json['type'], json['name'], fromJsonFilterValuesToList(json['state']), json['type_name']); return GroupFilter(json['type'], json['name'],
fromJsonFilterValuesToList(json['state']), json['type_name']);
} }
Map<String, dynamic> toJson() => Map<String, dynamic> toJson() => {
{'type': type, 'name': name, 'state': filterValuesListToJson(state), 'type_name': "GroupFilter"}; 'type': type,
'name': name,
'state': filterValuesListToJson(state),
'type_name': "GroupFilter"
};
} }
class CheckBoxFilter { class CheckBoxFilter {
@ -149,12 +170,20 @@ class CheckBoxFilter {
bool state; bool state;
String? typeName; String? typeName;
CheckBoxFilter(this.type, this.name, this.value, this.typeName, {this.state = false}); CheckBoxFilter(this.type, this.name, this.value, this.typeName,
{this.state = false});
factory CheckBoxFilter.fromJson(Map<String, dynamic> json) { factory CheckBoxFilter.fromJson(Map<String, dynamic> json) {
return CheckBoxFilter(json['type'], json['name'], json['value'], json['type_name'], state: json['state'] ?? false); return CheckBoxFilter(
json['type'], json['name'], json['value'], json['type_name'],
state: json['state'] ?? false);
} }
Map<String, dynamic> toJson() => Map<String, dynamic> toJson() => {
{'type': type, 'name': name, 'value': value, 'state': state, 'type_name': "CheckBox"}; 'type': type,
'name': name,
'value': value,
'state': state,
'type_name': "CheckBox"
};
} }
List<dynamic> fromJsonFilterValuesToList(List list) { List<dynamic> fromJsonFilterValuesToList(List list) {
@ -165,9 +194,11 @@ List<dynamic> fromJsonFilterValuesToList(List list) {
return switch (map['type_name']) { return switch (map['type_name']) {
'TriState' => TriStateFilter.fromJson(map.toMapStringDynamic!), 'TriState' => TriStateFilter.fromJson(map.toMapStringDynamic!),
'CheckBox' => CheckBoxFilter.fromJson(map.toMapStringDynamic!), 'CheckBox' => CheckBoxFilter.fromJson(map.toMapStringDynamic!),
'SelectOption' => SelectFilterOption.fromJson(map.toMapStringDynamic!), 'SelectOption' =>
SelectFilterOption.fromJson(map.toMapStringDynamic!),
'SelectFilter' => SelectFilter.fromJson(map.toMapStringDynamic!), 'SelectFilter' => SelectFilter.fromJson(map.toMapStringDynamic!),
'SeparatorFilter' => SeparatorFilter.fromJson(map.toMapStringDynamic!), 'SeparatorFilter' =>
SeparatorFilter.fromJson(map.toMapStringDynamic!),
'HeaderFilter' => HeaderFilter.fromJson(map.toMapStringDynamic!), 'HeaderFilter' => HeaderFilter.fromJson(map.toMapStringDynamic!),
'TextFilter' => TextFilter.fromJson(map.toMapStringDynamic!), 'TextFilter' => TextFilter.fromJson(map.toMapStringDynamic!),
'SortFilter' => SortFilter.fromJson(map.toMapStringDynamic!), 'SortFilter' => SortFilter.fromJson(map.toMapStringDynamic!),

View file

@ -44,15 +44,18 @@ class WordSet {
WordSet(this.words); WordSet(this.words);
bool anyWordIn(String dateString) { bool anyWordIn(String dateString) {
return words.any((word) => dateString.toLowerCase().contains(word.toLowerCase())); return words
.any((word) => dateString.toLowerCase().contains(word.toLowerCase()));
} }
bool startsWith(String dateString) { bool startsWith(String dateString) {
return words.any((word) => dateString.toLowerCase().startsWith(word.toLowerCase())); return words
.any((word) => dateString.toLowerCase().startsWith(word.toLowerCase()));
} }
bool endsWith(String dateString) { bool endsWith(String dateString) {
return words.any((word) => dateString.toLowerCase().endsWith(word.toLowerCase())); return words
.any((word) => dateString.toLowerCase().endsWith(word.toLowerCase()));
} }
} }
@ -79,7 +82,8 @@ class MBridge {
//Return one attr //Return one attr
else if (query.nodes.length == 1) { else if (query.nodes.length == 1) {
String attr = query.attr != null ? query.attr!.trim().trimLeft().trimRight() : ""; String attr =
query.attr != null ? query.attr!.trim().trimLeft().trimRight() : "";
if (attr.isNotEmpty) { if (attr.isNotEmpty) {
attrs = [attr]; attrs = [attr];
} }
@ -102,7 +106,10 @@ class MBridge {
statusMap = element; statusMap = element;
} }
for (var element in statusMap.entries) { for (var element in statusMap.entries) {
if (element.key.toString().toLowerCase().contains(status.toLowerCase().trim().trimLeft().trimRight())) { if (element.key
.toString()
.toLowerCase()
.contains(status.toLowerCase().trim().trimLeft().trimRight())) {
return switch (element.value as int) { return switch (element.value as int) {
0 => Status.ongoing, 0 => Status.ongoing,
1 => Status.completed, 1 => Status.completed,
@ -259,7 +266,8 @@ class MBridge {
} }
//Parse a list of dates to millisecondsSinceEpoch //Parse a list of dates to millisecondsSinceEpoch
static List parseDates(List value, String dateFormat, String dateFormatLocale) { static List parseDates(
List value, String dateFormat, String dateFormatLocale) {
List<dynamic> val = []; List<dynamic> val = [];
for (var element in value) { for (var element in value) {
if (element is $Value) { if (element is $Value) {
@ -304,7 +312,8 @@ class MBridge {
} }
//Utility to use RegExp //Utility to use RegExp
static String regExp(String expression, String source, String replace, int type, int group) { static String regExp(
String expression, String source, String replace, int type, int group) {
if (type == 0) { if (type == 0) {
return expression.replaceAll(RegExp(source), replace); return expression.replaceAll(RegExp(source), replace);
} }
@ -319,48 +328,58 @@ class MBridge {
return await DoodExtractor().videosFromUrl(url, quality: quality); return await DoodExtractor().videosFromUrl(url, quality: quality);
} }
static Future<List<Video>> streamWishExtractor(String url, String prefix) async { static Future<List<Video>> streamWishExtractor(
String url, String prefix) async {
return await StreamWishExtractor().videosFromUrl(url, prefix); return await StreamWishExtractor().videosFromUrl(url, prefix);
} }
static Future<List<Video>> filemoonExtractor(String url, String prefix, String suffix) async { static Future<List<Video>> filemoonExtractor(
String url, String prefix, String suffix) async {
return await FilemoonExtractor().videosFromUrl(url, prefix, suffix); return await FilemoonExtractor().videosFromUrl(url, prefix, suffix);
} }
static Future<List<Video>> mp4UploadExtractor(String url, String? headers, String prefix, String suffix) async { static Future<List<Video>> mp4UploadExtractor(
String url, String? headers, String prefix, String suffix) async {
Map<String, String> newHeaders = {}; Map<String, String> newHeaders = {};
if (headers != null) { if (headers != null) {
newHeaders = (jsonDecode(headers) as Map).toMapStringString!; newHeaders = (jsonDecode(headers) as Map).toMapStringString!;
} }
return await Mp4uploadExtractor().videosFromUrl(url, newHeaders, prefix: prefix, suffix: suffix); return await Mp4uploadExtractor()
.videosFromUrl(url, newHeaders, prefix: prefix, suffix: suffix);
} }
static Future<List<Map<String, String>>> quarkFilesExtractor(List<String> url, String cookie) async { static Future<List<Map<String, String>>> quarkFilesExtractor(
List<String> url, String cookie) async {
QuarkUcExtractor quark = QuarkUcExtractor(); QuarkUcExtractor quark = QuarkUcExtractor();
await quark.initCloudDrive(cookie, CloudDriveType.quark); await quark.initCloudDrive(cookie, CloudDriveType.quark);
return await quark.videoFilesFromUrl(url); return await quark.videoFilesFromUrl(url);
} }
static Future<List<Map<String, String>>> ucFilesExtractor(List<String> url, String cookie) async { static Future<List<Map<String, String>>> ucFilesExtractor(
List<String> url, String cookie) async {
QuarkUcExtractor uc = QuarkUcExtractor(); QuarkUcExtractor uc = QuarkUcExtractor();
await uc.initCloudDrive(cookie, CloudDriveType.uc); await uc.initCloudDrive(cookie, CloudDriveType.uc);
return await uc.videoFilesFromUrl(url); return await uc.videoFilesFromUrl(url);
} }
static Future<List<Video>> quarkVideosExtractor(String url, String cookie) async { static Future<List<Video>> quarkVideosExtractor(
String url, String cookie) async {
QuarkUcExtractor quark = QuarkUcExtractor(); QuarkUcExtractor quark = QuarkUcExtractor();
await quark.initCloudDrive(cookie, CloudDriveType.quark); await quark.initCloudDrive(cookie, CloudDriveType.quark);
return await quark.videosFromUrl(url); return await quark.videosFromUrl(url);
} }
static Future<List<Video>> ucVideosExtractor(String url, String cookie) async { static Future<List<Video>> ucVideosExtractor(
String url, String cookie) async {
QuarkUcExtractor uc = QuarkUcExtractor(); QuarkUcExtractor uc = QuarkUcExtractor();
await uc.initCloudDrive(cookie, CloudDriveType.uc); await uc.initCloudDrive(cookie, CloudDriveType.uc);
return await uc.videosFromUrl(url); return await uc.videosFromUrl(url);
} }
static Future<List<Video>> streamTapeExtractor(String url, String? quality) async { static Future<List<Video>> streamTapeExtractor(
return await StreamTapeExtractor().videosFromUrl(url, quality: quality ?? "StreamTape"); String url, String? quality) async {
return await StreamTapeExtractor()
.videosFromUrl(url, quality: quality ?? "StreamTape");
} }
//Utility to use substring //Utility to use substring
@ -383,28 +402,55 @@ class MBridge {
} }
//Parse a chapter date to millisecondsSinceEpoch //Parse a chapter date to millisecondsSinceEpoch
static String parseChapterDate( static String parseChapterDate(String date, String dateFormat,
String date, String dateFormat, String dateFormatLocale, Function((String, String, bool)) newLocale) { String dateFormatLocale, Function((String, String, bool)) newLocale) {
int parseRelativeDate(String date) { int parseRelativeDate(String date) {
final number = int.tryParse(RegExp(r"(\d+)").firstMatch(date)!.group(0)!); final number = int.tryParse(RegExp(r"(\d+)").firstMatch(date)!.group(0)!);
if (number == null) return 0; if (number == null) return 0;
final cal = DateTime.now(); final cal = DateTime.now();
if (WordSet(["hari", "gün", "jour", "día", "dia", "day", "วัน", "ngày", "giorni", "أيام", ""]).anyWordIn(date)) { if (WordSet([
"hari",
"gün",
"jour",
"día",
"dia",
"day",
"วัน",
"ngày",
"giorni",
"أيام",
""
]).anyWordIn(date)) {
return cal.subtract(Duration(days: number)).millisecondsSinceEpoch; return cal.subtract(Duration(days: number)).millisecondsSinceEpoch;
} else if (WordSet(["jam", "saat", "heure", "hora", "hour", "ชั่วโมง", "giờ", "ore", "ساعة", "小时"]) } else if (WordSet([
.anyWordIn(date)) { "jam",
"saat",
"heure",
"hora",
"hour",
"ชั่วโมง",
"giờ",
"ore",
"ساعة",
"小时"
]).anyWordIn(date)) {
return cal.subtract(Duration(hours: number)).millisecondsSinceEpoch; return cal.subtract(Duration(hours: number)).millisecondsSinceEpoch;
} else if (WordSet(["menit", "dakika", "min", "minute", "minuto", "นาที", "دقائق"]).anyWordIn(date)) { } else if (WordSet(
["menit", "dakika", "min", "minute", "minuto", "นาที", "دقائق"])
.anyWordIn(date)) {
return cal.subtract(Duration(minutes: number)).millisecondsSinceEpoch; return cal.subtract(Duration(minutes: number)).millisecondsSinceEpoch;
} else if (WordSet(["detik", "segundo", "second", "วินาที", "sec"]).anyWordIn(date)) { } else if (WordSet(["detik", "segundo", "second", "วินาที", "sec"])
.anyWordIn(date)) {
return cal.subtract(Duration(seconds: number)).millisecondsSinceEpoch; return cal.subtract(Duration(seconds: number)).millisecondsSinceEpoch;
} else if (WordSet(["week", "semana"]).anyWordIn(date)) { } else if (WordSet(["week", "semana"]).anyWordIn(date)) {
return cal.subtract(Duration(days: number * 7)).millisecondsSinceEpoch; return cal.subtract(Duration(days: number * 7)).millisecondsSinceEpoch;
} else if (WordSet(["month", "mes"]).anyWordIn(date)) { } else if (WordSet(["month", "mes"]).anyWordIn(date)) {
return cal.subtract(Duration(days: number * 30)).millisecondsSinceEpoch; return cal.subtract(Duration(days: number * 30)).millisecondsSinceEpoch;
} else if (WordSet(["year", "año"]).anyWordIn(date)) { } else if (WordSet(["year", "año"]).anyWordIn(date)) {
return cal.subtract(Duration(days: number * 365)).millisecondsSinceEpoch; return cal
.subtract(Duration(days: number * 365))
.millisecondsSinceEpoch;
} else { } else {
return 0; return 0;
} }
@ -430,11 +476,19 @@ class MBridge {
} else if (date.contains(RegExp(r"\d(st|nd|rd|th)"))) { } else if (date.contains(RegExp(r"\d(st|nd|rd|th)"))) {
final cleanedDate = date final cleanedDate = date
.split(" ") .split(" ")
.map((it) => it.contains(RegExp(r"\d\D\D")) ? it.replaceAll(RegExp(r"\D"), "") : it) .map((it) => it.contains(RegExp(r"\d\D\D"))
? it.replaceAll(RegExp(r"\D"), "")
: it)
.join(" "); .join(" ");
return DateFormat(dateFormat, dateFormatLocale).parse(cleanedDate).millisecondsSinceEpoch.toString(); return DateFormat(dateFormat, dateFormatLocale)
.parse(cleanedDate)
.millisecondsSinceEpoch
.toString();
} else { } else {
return DateFormat(dateFormat, dateFormatLocale).parse(date).millisecondsSinceEpoch.toString(); return DateFormat(dateFormat, dateFormatLocale)
.parse(date)
.millisecondsSinceEpoch
.toString();
} }
} catch (e) { } catch (e) {
final supportedLocales = DateFormat.allLocalesWithSymbols(); final supportedLocales = DateFormat.allLocalesWithSymbols();
@ -456,18 +510,27 @@ class MBridge {
DateTime cal = DateTime.now().subtract(const Duration(days: 2)); DateTime cal = DateTime.now().subtract(const Duration(days: 2));
cal = DateTime(cal.year, cal.month, cal.day); cal = DateTime(cal.year, cal.month, cal.day);
return cal.millisecondsSinceEpoch.toString(); return cal.millisecondsSinceEpoch.toString();
} else if (WordSet(["ago", "atrás", "önce", "قبل"]).endsWith(date)) { } else if (WordSet(["ago", "atrás", "önce", "قبل"])
.endsWith(date)) {
return parseRelativeDate(date).toString(); return parseRelativeDate(date).toString();
} else if (WordSet(["hace"]).startsWith(date)) { } else if (WordSet(["hace"]).startsWith(date)) {
return parseRelativeDate(date).toString(); return parseRelativeDate(date).toString();
} else if (date.contains(RegExp(r"\d(st|nd|rd|th)"))) { } else if (date.contains(RegExp(r"\d(st|nd|rd|th)"))) {
final cleanedDate = date final cleanedDate = date
.split(" ") .split(" ")
.map((it) => it.contains(RegExp(r"\d\D\D")) ? it.replaceAll(RegExp(r"\D"), "") : it) .map((it) => it.contains(RegExp(r"\d\D\D"))
? it.replaceAll(RegExp(r"\D"), "")
: it)
.join(" "); .join(" ");
return DateFormat(dateFormat, locale).parse(cleanedDate).millisecondsSinceEpoch.toString(); return DateFormat(dateFormat, locale)
.parse(cleanedDate)
.millisecondsSinceEpoch
.toString();
} else { } else {
return DateFormat(dateFormat, locale).parse(date).millisecondsSinceEpoch.toString(); return DateFormat(dateFormat, locale)
.parse(date)
.millisecondsSinceEpoch
.toString();
} }
} catch (_) {} } catch (_) {}
} }
@ -485,13 +548,15 @@ class MBridge {
return await SibnetExtractor().videosFromUrl(url, prefix: prefix); return await SibnetExtractor().videosFromUrl(url, prefix: prefix);
} }
static Future<List<Video>> sendVidExtractor(String url, String? headers, String prefix) async { static Future<List<Video>> sendVidExtractor(
String url, String? headers, String prefix) async {
Map<String, String> newHeaders = {}; Map<String, String> newHeaders = {};
if (headers != null) { if (headers != null) {
newHeaders = (jsonDecode(headers) as Map).toMapStringString!; newHeaders = (jsonDecode(headers) as Map).toMapStringString!;
} }
return await SendvidExtractor(newHeaders).videosFromUrl(url, prefix: prefix); return await SendvidExtractor(newHeaders)
.videosFromUrl(url, prefix: prefix);
} }
static Future<List<Video>> myTvExtractor(String url) async { static Future<List<Video>> myTvExtractor(String url) async {
@ -502,12 +567,14 @@ class MBridge {
return await OkruExtractor().videosFromUrl(url); return await OkruExtractor().videosFromUrl(url);
} }
static Future<List<Video>> yourUploadExtractor(String url, String? headers, String? name, String prefix) async { static Future<List<Video>> yourUploadExtractor(
String url, String? headers, String? name, String prefix) async {
Map<String, String> newHeaders = {}; Map<String, String> newHeaders = {};
if (headers != null) { if (headers != null) {
newHeaders = (jsonDecode(headers) as Map).toMapStringString!; newHeaders = (jsonDecode(headers) as Map).toMapStringString!;
} }
return await YourUploadExtractor().videosFromUrl(url, newHeaders, prefix: prefix, name: name ?? "YourUpload"); return await YourUploadExtractor().videosFromUrl(url, newHeaders,
prefix: prefix, name: name ?? "YourUpload");
} }
static Future<List<Video>> voeExtractor(String url, String? quality) async { static Future<List<Video>> voeExtractor(String url, String? quality) async {
@ -518,8 +585,10 @@ class MBridge {
return await VidBomExtractor().videosFromUrl(url); return await VidBomExtractor().videosFromUrl(url);
} }
static Future<List<Video>> streamlareExtractor(String url, String prefix, String suffix) async { static Future<List<Video>> streamlareExtractor(
return await StreamlareExtractor().videosFromUrl(url, prefix: prefix, suffix: suffix); String url, String prefix, String suffix) async {
return await StreamlareExtractor()
.videosFromUrl(url, prefix: prefix, suffix: suffix);
} }
static String encryptAESCryptoJS(String plainText, String passphrase) { static String encryptAESCryptoJS(String plainText, String passphrase) {
@ -530,16 +599,18 @@ class MBridge {
return CryptoAES.decryptAESCryptoJS(encrypted, passphrase); return CryptoAES.decryptAESCryptoJS(encrypted, passphrase);
} }
static Video toVideo( static Video toVideo(String url, String quality, String originalUrl,
String url, String quality, String originalUrl, String? headers, List<Track>? subtitles, List<Track>? audios) { String? headers, List<Track>? subtitles, List<Track>? audios) {
Map<String, String> newHeaders = {}; Map<String, String> newHeaders = {};
if (headers != null) { if (headers != null) {
newHeaders = (jsonDecode(headers) as Map).toMapStringString!; newHeaders = (jsonDecode(headers) as Map).toMapStringString!;
} }
return Video(url, quality, originalUrl, headers: newHeaders, subtitles: subtitles ?? [], audios: audios ?? []); return Video(url, quality, originalUrl,
headers: newHeaders, subtitles: subtitles ?? [], audios: audios ?? []);
} }
static String cryptoHandler(String text, String iv, String secretKeyString, bool encrypt) { static String cryptoHandler(
String text, String iv, String secretKeyString, bool encrypt) {
try { try {
if (encrypt) { if (encrypt) {
final encryptt = _encrypt(secretKeyString, iv); final encryptt = _encrypt(secretKeyString, iv);
@ -603,7 +674,10 @@ void botToast(String title,
bool hasCloudFlare = false, bool hasCloudFlare = false,
String? url}) { String? url}) {
final context = navigatorKey.currentState?.context; final context = navigatorKey.currentState?.context;
final assets = ['assets/app_icons/icon-black.png', 'assets/app_icons/icon-red.png']; final assets = [
'assets/app_icons/icon-black.png',
'assets/app_icons/icon-red.png'
];
BotToast.showNotification( BotToast.showNotification(
onlyOne: true, onlyOne: true,
dismissDirections: [DismissDirection.horizontal, DismissDirection.down], dismissDirections: [DismissDirection.horizontal, DismissDirection.down],
@ -617,9 +691,11 @@ void botToast(String title,
? (_) => OutlinedButton.icon( ? (_) => OutlinedButton.icon(
style: OutlinedButton.styleFrom(elevation: 10), style: OutlinedButton.styleFrom(elevation: 10),
onPressed: () { onPressed: () {
context?.push("/mangawebview", extra: {'url': url, 'title': ''}); context
?.push("/mangawebview", extra: {'url': url, 'title': ''});
}, },
label: Text("Resolve Cloudflare challenge", style: TextStyle(color: context?.secondaryColor)), label: Text("Resolve Cloudflare challenge",
style: TextStyle(color: context?.secondaryColor)),
icon: const Icon(Icons.public), icon: const Icon(Icons.public),
) )
: null, : null,
@ -629,6 +705,7 @@ void botToast(String title,
(encrypt.Encrypter, encrypt.IV) _encrypt(String keyy, String ivv) { (encrypt.Encrypter, encrypt.IV) _encrypt(String keyy, String ivv) {
final key = encrypt.Key.fromUtf8(keyy); final key = encrypt.Key.fromUtf8(keyy);
final iv = encrypt.IV.fromUtf8(ivv); final iv = encrypt.IV.fromUtf8(ivv);
final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: 'PKCS7')); final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: 'PKCS7'));
return (encrypter, iv); return (encrypter, iv);
} }

View file

@ -8,7 +8,16 @@ class MChapter {
String? scanlator; String? scanlator;
MChapter({this.name, this.url, this.dateUpload, this.scanlator}); MChapter({this.name, this.url, this.dateUpload, this.scanlator});
factory MChapter.fromJson(Map<String, dynamic> json) { factory MChapter.fromJson(Map<String, dynamic> json) {
return MChapter(name: json['name'], url: json['url'], dateUpload: json['dateUpload'], scanlator: json['scanlator']); return MChapter(
name: json['name'],
url: json['url'],
dateUpload: json['dateUpload'],
scanlator: json['scanlator']);
} }
Map<String, dynamic> toJson() => {'name': name, 'url': url, 'dateUpload': dateUpload, 'scanlator': scanlator}; Map<String, dynamic> toJson() => {
'name': name,
'url': url,
'dateUpload': dateUpload,
'scanlator': scanlator
};
} }

View file

@ -48,11 +48,16 @@ class MManga {
4 => Status.publishingFinished, 4 => Status.publishingFinished,
_ => Status.unknown, _ => Status.unknown,
}, },
genre: (json['genre'] as List?)?.map((e) => e.toString()).toList() ?? [], genre:
(json['genre'] as List?)?.map((e) => e.toString()).toList() ?? [],
chapters: json['chapters'] != null chapters: json['chapters'] != null
? (json['chapters'] as List).map((e) => MChapter.fromJson(e)).toList() ? (json['chapters'] as List)
.map((e) => MChapter.fromJson(e))
.toList()
: json['episodes'] != null : json['episodes'] != null
? (json['episodes'] as List).map((e) => MChapter.fromJson(e)).toList() ? (json['episodes'] as List)
.map((e) => MChapter.fromJson(e))
.toList()
: []); : []);
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

View file

@ -7,7 +7,9 @@ class MPages {
factory MPages.fromJson(Map<String, dynamic> json) { factory MPages.fromJson(Map<String, dynamic> json) {
return MPages( return MPages(
list: json['list'] != null ? (json['list'] as List).map((e) => MManga.fromJson(e)).toList() : [], list: json['list'] != null
? (json['list'] as List).map((e) => MManga.fromJson(e)).toList()
: [],
hasNextPage: json['hasNextPage']); hasNextPage: json['hasNextPage']);
} }

View file

@ -6,7 +6,8 @@ class MVideo {
List<MTrack>? subtitles; List<MTrack>? subtitles;
List<MTrack>? audios; List<MTrack>? audios;
MVideo(this.url, this.quality, this.originalUrl, {this.headers, this.subtitles, this.audios}); MVideo(this.url, this.quality, this.originalUrl,
{this.headers, this.subtitles, this.audios});
} }
class MTrack { class MTrack {

View file

@ -27,11 +27,15 @@ class SourcePreference {
'id': id, 'id': id,
'sourceId': sourceId, 'sourceId': sourceId,
'key': key, 'key': key,
if (checkBoxPreference != null) 'checkBoxPreference': checkBoxPreference!.toJson(), if (checkBoxPreference != null)
if (switchPreferenceCompat != null) 'switchPreferenceCompat': switchPreferenceCompat!.toJson(), 'checkBoxPreference': checkBoxPreference!.toJson(),
if (switchPreferenceCompat != null)
'switchPreferenceCompat': switchPreferenceCompat!.toJson(),
if (listPreference != null) 'listPreference': listPreference!.toJson(), if (listPreference != null) 'listPreference': listPreference!.toJson(),
if (multiSelectListPreference != null) 'multiSelectListPreference': multiSelectListPreference!.toJson(), if (multiSelectListPreference != null)
if (editTextPreference != null) 'editTextPreference': editTextPreference!.toJson() 'multiSelectListPreference': multiSelectListPreference!.toJson(),
if (editTextPreference != null)
'editTextPreference': editTextPreference!.toJson()
}; };
factory SourcePreference.fromJson(Map<String, dynamic> json) { factory SourcePreference.fromJson(Map<String, dynamic> json) {
@ -39,17 +43,22 @@ class SourcePreference {
id: json['id'] ?? Isar.autoIncrement, id: json['id'] ?? Isar.autoIncrement,
sourceId: json['sourceId'], sourceId: json['sourceId'],
key: json['key'], key: json['key'],
checkBoxPreference: checkBoxPreference: json['checkBoxPreference'] != null
json['checkBoxPreference'] != null ? CheckBoxPreference.fromJson(json['checkBoxPreference']) : null, ? CheckBoxPreference.fromJson(json['checkBoxPreference'])
: null,
switchPreferenceCompat: json['switchPreferenceCompat'] != null switchPreferenceCompat: json['switchPreferenceCompat'] != null
? SwitchPreferenceCompat.fromJson(json['switchPreferenceCompat']) ? SwitchPreferenceCompat.fromJson(json['switchPreferenceCompat'])
: null, : null,
listPreference: json['listPreference'] != null ? ListPreference.fromJson(json['listPreference']) : null, listPreference: json['listPreference'] != null
multiSelectListPreference: json['multiSelectListPreference'] != null ? ListPreference.fromJson(json['listPreference'])
? MultiSelectListPreference.fromJson(json['multiSelectListPreference'])
: null, : null,
editTextPreference: multiSelectListPreference: json['multiSelectListPreference'] != null
json['editTextPreference'] != null ? EditTextPreference.fromJson(json['editTextPreference']) : null); ? MultiSelectListPreference.fromJson(
json['multiSelectListPreference'])
: null,
editTextPreference: json['editTextPreference'] != null
? EditTextPreference.fromJson(json['editTextPreference'])
: null);
} }
} }
@ -61,10 +70,12 @@ class CheckBoxPreference {
CheckBoxPreference({this.title, this.summary, this.value}); CheckBoxPreference({this.title, this.summary, this.value});
Map<String, dynamic> toJson() => {'title': title, 'summary': summary, 'value': value}; Map<String, dynamic> toJson() =>
{'title': title, 'summary': summary, 'value': value};
factory CheckBoxPreference.fromJson(Map<String, dynamic> json) { factory CheckBoxPreference.fromJson(Map<String, dynamic> json) {
return CheckBoxPreference(title: json['title'], summary: json['summary'], value: json['value']); return CheckBoxPreference(
title: json['title'], summary: json['summary'], value: json['value']);
} }
} }
@ -76,10 +87,12 @@ class SwitchPreferenceCompat {
SwitchPreferenceCompat({this.title, this.summary, this.value}); SwitchPreferenceCompat({this.title, this.summary, this.value});
Map<String, dynamic> toJson() => {'title': title, 'summary': summary, 'value': value}; Map<String, dynamic> toJson() =>
{'title': title, 'summary': summary, 'value': value};
factory SwitchPreferenceCompat.fromJson(Map<String, dynamic> json) { factory SwitchPreferenceCompat.fromJson(Map<String, dynamic> json) {
return SwitchPreferenceCompat(title: json['title'], summary: json['summary'], value: json['value']); return SwitchPreferenceCompat(
title: json['title'], summary: json['summary'], value: json['value']);
} }
} }
@ -91,10 +104,20 @@ class ListPreference {
List<String>? entries; List<String>? entries;
List<String>? entryValues; List<String>? entryValues;
ListPreference({this.title, this.summary, this.valueIndex, this.entries, this.entryValues}); ListPreference(
{this.title,
this.summary,
this.valueIndex,
this.entries,
this.entryValues});
Map<String, dynamic> toJson() => Map<String, dynamic> toJson() => {
{'title': title, 'summary': summary, 'valueIndex': valueIndex, 'entries': entries, 'entryValues': entryValues}; 'title': title,
'summary': summary,
'valueIndex': valueIndex,
'entries': entries,
'entryValues': entryValues
};
factory ListPreference.fromJson(Map<String, dynamic> json) { factory ListPreference.fromJson(Map<String, dynamic> json) {
return ListPreference( return ListPreference(
@ -114,7 +137,8 @@ class MultiSelectListPreference {
List<String>? entryValues; List<String>? entryValues;
List<String>? values; List<String>? values;
MultiSelectListPreference({this.title, this.summary, this.entries, this.entryValues, this.values}); MultiSelectListPreference(
{this.title, this.summary, this.entries, this.entryValues, this.values});
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'title': title, 'title': title,
@ -143,7 +167,13 @@ class EditTextPreference {
String? dialogMessage; String? dialogMessage;
String? text; String? text;
EditTextPreference({this.title, this.summary, this.value, this.dialogTitle, this.dialogMessage, this.text}); EditTextPreference(
{this.title,
this.summary,
this.value,
this.dialogTitle,
this.dialogMessage,
this.text});
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'title': title, 'title': title,
@ -173,5 +203,6 @@ class SourcePreferenceStringValue {
String? key; String? key;
String? value; String? value;
SourcePreferenceStringValue({this.id = Isar.autoIncrement, this.sourceId, this.key, this.value}); SourcePreferenceStringValue(
{this.id = Isar.autoIncrement, this.sourceId, this.key, this.value});
} }

View file

@ -13,13 +13,17 @@ import 'dart:ffi' as ffi;
/// Bindings to `lib/ffi/libmtorrentserver.h`. /// Bindings to `lib/ffi/libmtorrentserver.h`.
class TorrentLibrary { class TorrentLibrary {
/// Holds the symbol lookup function. /// Holds the symbol lookup function.
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName) _lookup; final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
_lookup;
/// The symbols are looked up in [dynamicLibrary]. /// The symbols are looked up in [dynamicLibrary].
TorrentLibrary(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup; TorrentLibrary(ffi.DynamicLibrary dynamicLibrary)
: _lookup = dynamicLibrary.lookup;
/// The symbols are looked up with [lookup]. /// The symbols are looked up with [lookup].
TorrentLibrary.fromLookup(ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName) lookup) TorrentLibrary.fromLookup(
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
lookup)
: _lookup = lookup; : _lookup = lookup;
void __va_start( void __va_start(
@ -30,15 +34,21 @@ class TorrentLibrary {
); );
} }
late final ___va_startPtr = _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<va_list>)>>('__va_start'); late final ___va_startPtr =
late final ___va_start = ___va_startPtr.asFunction<void Function(ffi.Pointer<va_list>)>(); _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<va_list>)>>(
'__va_start');
late final ___va_start =
___va_startPtr.asFunction<void Function(ffi.Pointer<va_list>)>();
void __security_init_cookie() { void __security_init_cookie() {
return ___security_init_cookie(); return ___security_init_cookie();
} }
late final ___security_init_cookiePtr = _lookup<ffi.NativeFunction<ffi.Void Function()>>('__security_init_cookie'); late final ___security_init_cookiePtr =
late final ___security_init_cookie = ___security_init_cookiePtr.asFunction<void Function()>(); _lookup<ffi.NativeFunction<ffi.Void Function()>>(
'__security_init_cookie');
late final ___security_init_cookie =
___security_init_cookiePtr.asFunction<void Function()>();
void __security_check_cookie( void __security_check_cookie(
int _StackCookie, int _StackCookie,
@ -49,8 +59,10 @@ class TorrentLibrary {
} }
late final ___security_check_cookiePtr = late final ___security_check_cookiePtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.UintPtr)>>('__security_check_cookie'); _lookup<ffi.NativeFunction<ffi.Void Function(ffi.UintPtr)>>(
late final ___security_check_cookie = ___security_check_cookiePtr.asFunction<void Function(int)>(); '__security_check_cookie');
late final ___security_check_cookie =
___security_check_cookiePtr.asFunction<void Function(int)>();
void __report_gsfailure( void __report_gsfailure(
int _StackCookie, int _StackCookie,
@ -60,10 +72,14 @@ class TorrentLibrary {
); );
} }
late final ___report_gsfailurePtr = _lookup<ffi.NativeFunction<ffi.Void Function(ffi.UintPtr)>>('__report_gsfailure'); late final ___report_gsfailurePtr =
late final ___report_gsfailure = ___report_gsfailurePtr.asFunction<void Function(int)>(); _lookup<ffi.NativeFunction<ffi.Void Function(ffi.UintPtr)>>(
'__report_gsfailure');
late final ___report_gsfailure =
___report_gsfailurePtr.asFunction<void Function(int)>();
late final ffi.Pointer<ffi.UintPtr> ___security_cookie = _lookup<ffi.UintPtr>('__security_cookie'); late final ffi.Pointer<ffi.UintPtr> ___security_cookie =
_lookup<ffi.UintPtr>('__security_cookie');
int get __security_cookie => ___security_cookie.value; int get __security_cookie => ___security_cookie.value;
@ -74,16 +90,20 @@ class TorrentLibrary {
} }
late final __invalid_parameter_noinfoPtr = late final __invalid_parameter_noinfoPtr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>('_invalid_parameter_noinfo'); _lookup<ffi.NativeFunction<ffi.Void Function()>>(
late final __invalid_parameter_noinfo = __invalid_parameter_noinfoPtr.asFunction<void Function()>(); '_invalid_parameter_noinfo');
late final __invalid_parameter_noinfo =
__invalid_parameter_noinfoPtr.asFunction<void Function()>();
void _invalid_parameter_noinfo_noreturn() { void _invalid_parameter_noinfo_noreturn() {
return __invalid_parameter_noinfo_noreturn(); return __invalid_parameter_noinfo_noreturn();
} }
late final __invalid_parameter_noinfo_noreturnPtr = late final __invalid_parameter_noinfo_noreturnPtr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>('_invalid_parameter_noinfo_noreturn'); _lookup<ffi.NativeFunction<ffi.Void Function()>>(
late final __invalid_parameter_noinfo_noreturn = __invalid_parameter_noinfo_noreturnPtr.asFunction<void Function()>(); '_invalid_parameter_noinfo_noreturn');
late final __invalid_parameter_noinfo_noreturn =
__invalid_parameter_noinfo_noreturnPtr.asFunction<void Function()>();
void _invoke_watson( void _invoke_watson(
ffi.Pointer<ffi.WChar> _Expression, ffi.Pointer<ffi.WChar> _Expression,
@ -103,16 +123,22 @@ class TorrentLibrary {
late final __invoke_watsonPtr = _lookup< late final __invoke_watsonPtr = _lookup<
ffi.NativeFunction< ffi.NativeFunction<
ffi.Void Function(ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>, ffi.UnsignedInt, ffi.Void Function(
ffi.Pointer<ffi.WChar>,
ffi.Pointer<ffi.WChar>,
ffi.Pointer<ffi.WChar>,
ffi.UnsignedInt,
ffi.UintPtr)>>('_invoke_watson'); ffi.UintPtr)>>('_invoke_watson');
late final __invoke_watson = __invoke_watsonPtr late final __invoke_watson = __invoke_watsonPtr.asFunction<
.asFunction<void Function(ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>, int, int)>(); void Function(ffi.Pointer<ffi.WChar>, ffi.Pointer<ffi.WChar>,
ffi.Pointer<ffi.WChar>, int, int)>();
ffi.Pointer<ffi.Int> _errno() { ffi.Pointer<ffi.Int> _errno() {
return __errno(); return __errno();
} }
late final __errnoPtr = _lookup<ffi.NativeFunction<ffi.Pointer<ffi.Int> Function()>>('_errno'); late final __errnoPtr =
_lookup<ffi.NativeFunction<ffi.Pointer<ffi.Int> Function()>>('_errno');
late final __errno = __errnoPtr.asFunction<ffi.Pointer<ffi.Int> Function()>(); late final __errno = __errnoPtr.asFunction<ffi.Pointer<ffi.Int> Function()>();
int _set_errno( int _set_errno(
@ -123,7 +149,8 @@ class TorrentLibrary {
); );
} }
late final __set_errnoPtr = _lookup<ffi.NativeFunction<errno_t Function(ffi.Int)>>('_set_errno'); late final __set_errnoPtr =
_lookup<ffi.NativeFunction<errno_t Function(ffi.Int)>>('_set_errno');
late final __set_errno = __set_errnoPtr.asFunction<int Function(int)>(); late final __set_errno = __set_errnoPtr.asFunction<int Function(int)>();
int _get_errno( int _get_errno(
@ -134,21 +161,26 @@ class TorrentLibrary {
); );
} }
late final __get_errnoPtr = _lookup<ffi.NativeFunction<errno_t Function(ffi.Pointer<ffi.Int>)>>('_get_errno'); late final __get_errnoPtr =
late final __get_errno = __get_errnoPtr.asFunction<int Function(ffi.Pointer<ffi.Int>)>(); _lookup<ffi.NativeFunction<errno_t Function(ffi.Pointer<ffi.Int>)>>(
'_get_errno');
late final __get_errno =
__get_errnoPtr.asFunction<int Function(ffi.Pointer<ffi.Int>)>();
int __threadid() { int __threadid() {
return ___threadid(); return ___threadid();
} }
late final ___threadidPtr = _lookup<ffi.NativeFunction<ffi.UnsignedLong Function()>>('__threadid'); late final ___threadidPtr =
_lookup<ffi.NativeFunction<ffi.UnsignedLong Function()>>('__threadid');
late final ___threadid = ___threadidPtr.asFunction<int Function()>(); late final ___threadid = ___threadidPtr.asFunction<int Function()>();
int __threadhandle() { int __threadhandle() {
return ___threadhandle(); return ___threadhandle();
} }
late final ___threadhandlePtr = _lookup<ffi.NativeFunction<ffi.UintPtr Function()>>('__threadhandle'); late final ___threadhandlePtr =
_lookup<ffi.NativeFunction<ffi.UintPtr Function()>>('__threadhandle');
late final ___threadhandle = ___threadhandlePtr.asFunction<int Function()>(); late final ___threadhandle = ___threadhandlePtr.asFunction<int Function()>();
double cabs( double cabs(
@ -159,7 +191,8 @@ class TorrentLibrary {
); );
} }
late final _cabsPtr = _lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('cabs'); late final _cabsPtr =
_lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('cabs');
late final _cabs = _cabsPtr.asFunction<double Function(_Dcomplex)>(); late final _cabs = _cabsPtr.asFunction<double Function(_Dcomplex)>();
_Dcomplex cacos( _Dcomplex cacos(
@ -170,7 +203,8 @@ class TorrentLibrary {
); );
} }
late final _cacosPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cacos'); late final _cacosPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cacos');
late final _cacos = _cacosPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _cacos = _cacosPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex cacosh( _Dcomplex cacosh(
@ -181,7 +215,8 @@ class TorrentLibrary {
); );
} }
late final _cacoshPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cacosh'); late final _cacoshPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cacosh');
late final _cacosh = _cacoshPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _cacosh = _cacoshPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
double carg( double carg(
@ -192,7 +227,8 @@ class TorrentLibrary {
); );
} }
late final _cargPtr = _lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('carg'); late final _cargPtr =
_lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('carg');
late final _carg = _cargPtr.asFunction<double Function(_Dcomplex)>(); late final _carg = _cargPtr.asFunction<double Function(_Dcomplex)>();
_Dcomplex casin( _Dcomplex casin(
@ -203,7 +239,8 @@ class TorrentLibrary {
); );
} }
late final _casinPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('casin'); late final _casinPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('casin');
late final _casin = _casinPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _casin = _casinPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex casinh( _Dcomplex casinh(
@ -214,7 +251,8 @@ class TorrentLibrary {
); );
} }
late final _casinhPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('casinh'); late final _casinhPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('casinh');
late final _casinh = _casinhPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _casinh = _casinhPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex catan( _Dcomplex catan(
@ -225,7 +263,8 @@ class TorrentLibrary {
); );
} }
late final _catanPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('catan'); late final _catanPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('catan');
late final _catan = _catanPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _catan = _catanPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex catanh( _Dcomplex catanh(
@ -236,7 +275,8 @@ class TorrentLibrary {
); );
} }
late final _catanhPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('catanh'); late final _catanhPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('catanh');
late final _catanh = _catanhPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _catanh = _catanhPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex ccos( _Dcomplex ccos(
@ -247,7 +287,8 @@ class TorrentLibrary {
); );
} }
late final _ccosPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ccos'); late final _ccosPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ccos');
late final _ccos = _ccosPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _ccos = _ccosPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex ccosh( _Dcomplex ccosh(
@ -258,7 +299,8 @@ class TorrentLibrary {
); );
} }
late final _ccoshPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ccosh'); late final _ccoshPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ccosh');
late final _ccosh = _ccoshPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _ccosh = _ccoshPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex cexp( _Dcomplex cexp(
@ -269,7 +311,8 @@ class TorrentLibrary {
); );
} }
late final _cexpPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cexp'); late final _cexpPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cexp');
late final _cexp = _cexpPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _cexp = _cexpPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
double cimag( double cimag(
@ -280,7 +323,8 @@ class TorrentLibrary {
); );
} }
late final _cimagPtr = _lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('cimag'); late final _cimagPtr =
_lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('cimag');
late final _cimag = _cimagPtr.asFunction<double Function(_Dcomplex)>(); late final _cimag = _cimagPtr.asFunction<double Function(_Dcomplex)>();
_Dcomplex clog( _Dcomplex clog(
@ -291,7 +335,8 @@ class TorrentLibrary {
); );
} }
late final _clogPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('clog'); late final _clogPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('clog');
late final _clog = _clogPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _clog = _clogPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex clog10( _Dcomplex clog10(
@ -302,7 +347,8 @@ class TorrentLibrary {
); );
} }
late final _clog10Ptr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('clog10'); late final _clog10Ptr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('clog10');
late final _clog10 = _clog10Ptr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _clog10 = _clog10Ptr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex conj( _Dcomplex conj(
@ -313,7 +359,8 @@ class TorrentLibrary {
); );
} }
late final _conjPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('conj'); late final _conjPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('conj');
late final _conj = _conjPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _conj = _conjPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex cpow( _Dcomplex cpow(
@ -326,8 +373,11 @@ class TorrentLibrary {
); );
} }
late final _cpowPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>('cpow'); late final _cpowPtr =
late final _cpow = _cpowPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>(); _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>(
'cpow');
late final _cpow =
_cpowPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>();
_Dcomplex cproj( _Dcomplex cproj(
_Dcomplex _Z, _Dcomplex _Z,
@ -337,7 +387,8 @@ class TorrentLibrary {
); );
} }
late final _cprojPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cproj'); late final _cprojPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('cproj');
late final _cproj = _cprojPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _cproj = _cprojPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
double creal( double creal(
@ -348,7 +399,8 @@ class TorrentLibrary {
); );
} }
late final _crealPtr = _lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('creal'); late final _crealPtr =
_lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('creal');
late final _creal = _crealPtr.asFunction<double Function(_Dcomplex)>(); late final _creal = _crealPtr.asFunction<double Function(_Dcomplex)>();
_Dcomplex csin( _Dcomplex csin(
@ -359,7 +411,8 @@ class TorrentLibrary {
); );
} }
late final _csinPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('csin'); late final _csinPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('csin');
late final _csin = _csinPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _csin = _csinPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex csinh( _Dcomplex csinh(
@ -370,7 +423,8 @@ class TorrentLibrary {
); );
} }
late final _csinhPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('csinh'); late final _csinhPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('csinh');
late final _csinh = _csinhPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _csinh = _csinhPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex csqrt( _Dcomplex csqrt(
@ -381,7 +435,8 @@ class TorrentLibrary {
); );
} }
late final _csqrtPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('csqrt'); late final _csqrtPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('csqrt');
late final _csqrt = _csqrtPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _csqrt = _csqrtPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex ctan( _Dcomplex ctan(
@ -392,7 +447,8 @@ class TorrentLibrary {
); );
} }
late final _ctanPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ctan'); late final _ctanPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ctan');
late final _ctan = _ctanPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _ctan = _ctanPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
_Dcomplex ctanh( _Dcomplex ctanh(
@ -403,7 +459,8 @@ class TorrentLibrary {
); );
} }
late final _ctanhPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ctanh'); late final _ctanhPtr =
_lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex)>>('ctanh');
late final _ctanh = _ctanhPtr.asFunction<_Dcomplex Function(_Dcomplex)>(); late final _ctanh = _ctanhPtr.asFunction<_Dcomplex Function(_Dcomplex)>();
double norm( double norm(
@ -414,7 +471,8 @@ class TorrentLibrary {
); );
} }
late final _normPtr = _lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('norm'); late final _normPtr =
_lookup<ffi.NativeFunction<ffi.Double Function(_Dcomplex)>>('norm');
late final _norm = _normPtr.asFunction<double Function(_Dcomplex)>(); late final _norm = _normPtr.asFunction<double Function(_Dcomplex)>();
double cabsf( double cabsf(
@ -425,7 +483,8 @@ class TorrentLibrary {
); );
} }
late final _cabsfPtr = _lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('cabsf'); late final _cabsfPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('cabsf');
late final _cabsf = _cabsfPtr.asFunction<double Function(_Fcomplex)>(); late final _cabsf = _cabsfPtr.asFunction<double Function(_Fcomplex)>();
_Fcomplex cacosf( _Fcomplex cacosf(
@ -436,7 +495,8 @@ class TorrentLibrary {
); );
} }
late final _cacosfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cacosf'); late final _cacosfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cacosf');
late final _cacosf = _cacosfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _cacosf = _cacosfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex cacoshf( _Fcomplex cacoshf(
@ -447,7 +507,8 @@ class TorrentLibrary {
); );
} }
late final _cacoshfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cacoshf'); late final _cacoshfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cacoshf');
late final _cacoshf = _cacoshfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _cacoshf = _cacoshfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
double cargf( double cargf(
@ -458,7 +519,8 @@ class TorrentLibrary {
); );
} }
late final _cargfPtr = _lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('cargf'); late final _cargfPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('cargf');
late final _cargf = _cargfPtr.asFunction<double Function(_Fcomplex)>(); late final _cargf = _cargfPtr.asFunction<double Function(_Fcomplex)>();
_Fcomplex casinf( _Fcomplex casinf(
@ -469,7 +531,8 @@ class TorrentLibrary {
); );
} }
late final _casinfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('casinf'); late final _casinfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('casinf');
late final _casinf = _casinfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _casinf = _casinfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex casinhf( _Fcomplex casinhf(
@ -480,7 +543,8 @@ class TorrentLibrary {
); );
} }
late final _casinhfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('casinhf'); late final _casinhfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('casinhf');
late final _casinhf = _casinhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _casinhf = _casinhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex catanf( _Fcomplex catanf(
@ -491,7 +555,8 @@ class TorrentLibrary {
); );
} }
late final _catanfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('catanf'); late final _catanfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('catanf');
late final _catanf = _catanfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _catanf = _catanfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex catanhf( _Fcomplex catanhf(
@ -502,7 +567,8 @@ class TorrentLibrary {
); );
} }
late final _catanhfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('catanhf'); late final _catanhfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('catanhf');
late final _catanhf = _catanhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _catanhf = _catanhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex ccosf( _Fcomplex ccosf(
@ -513,7 +579,8 @@ class TorrentLibrary {
); );
} }
late final _ccosfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ccosf'); late final _ccosfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ccosf');
late final _ccosf = _ccosfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _ccosf = _ccosfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex ccoshf( _Fcomplex ccoshf(
@ -524,7 +591,8 @@ class TorrentLibrary {
); );
} }
late final _ccoshfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ccoshf'); late final _ccoshfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ccoshf');
late final _ccoshf = _ccoshfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _ccoshf = _ccoshfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex cexpf( _Fcomplex cexpf(
@ -535,7 +603,8 @@ class TorrentLibrary {
); );
} }
late final _cexpfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cexpf'); late final _cexpfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cexpf');
late final _cexpf = _cexpfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _cexpf = _cexpfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
double cimagf( double cimagf(
@ -546,7 +615,8 @@ class TorrentLibrary {
); );
} }
late final _cimagfPtr = _lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('cimagf'); late final _cimagfPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('cimagf');
late final _cimagf = _cimagfPtr.asFunction<double Function(_Fcomplex)>(); late final _cimagf = _cimagfPtr.asFunction<double Function(_Fcomplex)>();
_Fcomplex clogf( _Fcomplex clogf(
@ -557,7 +627,8 @@ class TorrentLibrary {
); );
} }
late final _clogfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('clogf'); late final _clogfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('clogf');
late final _clogf = _clogfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _clogf = _clogfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex clog10f( _Fcomplex clog10f(
@ -568,7 +639,8 @@ class TorrentLibrary {
); );
} }
late final _clog10fPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('clog10f'); late final _clog10fPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('clog10f');
late final _clog10f = _clog10fPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _clog10f = _clog10fPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex conjf( _Fcomplex conjf(
@ -579,7 +651,8 @@ class TorrentLibrary {
); );
} }
late final _conjfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('conjf'); late final _conjfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('conjf');
late final _conjf = _conjfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _conjf = _conjfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex cpowf( _Fcomplex cpowf(
@ -592,8 +665,11 @@ class TorrentLibrary {
); );
} }
late final _cpowfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>('cpowf'); late final _cpowfPtr =
late final _cpowf = _cpowfPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>(); _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>(
'cpowf');
late final _cpowf =
_cpowfPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>();
_Fcomplex cprojf( _Fcomplex cprojf(
_Fcomplex _Z, _Fcomplex _Z,
@ -603,7 +679,8 @@ class TorrentLibrary {
); );
} }
late final _cprojfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cprojf'); late final _cprojfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('cprojf');
late final _cprojf = _cprojfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _cprojf = _cprojfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
double crealf( double crealf(
@ -614,7 +691,8 @@ class TorrentLibrary {
); );
} }
late final _crealfPtr = _lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('crealf'); late final _crealfPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('crealf');
late final _crealf = _crealfPtr.asFunction<double Function(_Fcomplex)>(); late final _crealf = _crealfPtr.asFunction<double Function(_Fcomplex)>();
_Fcomplex csinf( _Fcomplex csinf(
@ -625,7 +703,8 @@ class TorrentLibrary {
); );
} }
late final _csinfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('csinf'); late final _csinfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('csinf');
late final _csinf = _csinfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _csinf = _csinfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex csinhf( _Fcomplex csinhf(
@ -636,7 +715,8 @@ class TorrentLibrary {
); );
} }
late final _csinhfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('csinhf'); late final _csinhfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('csinhf');
late final _csinhf = _csinhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _csinhf = _csinhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex csqrtf( _Fcomplex csqrtf(
@ -647,7 +727,8 @@ class TorrentLibrary {
); );
} }
late final _csqrtfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('csqrtf'); late final _csqrtfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('csqrtf');
late final _csqrtf = _csqrtfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _csqrtf = _csqrtfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex ctanf( _Fcomplex ctanf(
@ -658,7 +739,8 @@ class TorrentLibrary {
); );
} }
late final _ctanfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ctanf'); late final _ctanfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ctanf');
late final _ctanf = _ctanfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _ctanf = _ctanfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
_Fcomplex ctanhf( _Fcomplex ctanhf(
@ -669,7 +751,8 @@ class TorrentLibrary {
); );
} }
late final _ctanhfPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ctanhf'); late final _ctanhfPtr =
_lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex)>>('ctanhf');
late final _ctanhf = _ctanhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>(); late final _ctanhf = _ctanhfPtr.asFunction<_Fcomplex Function(_Fcomplex)>();
double normf( double normf(
@ -680,7 +763,8 @@ class TorrentLibrary {
); );
} }
late final _normfPtr = _lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('normf'); late final _normfPtr =
_lookup<ffi.NativeFunction<ffi.Float Function(_Fcomplex)>>('normf');
late final _normf = _normfPtr.asFunction<double Function(_Fcomplex)>(); late final _normf = _normfPtr.asFunction<double Function(_Fcomplex)>();
_Dcomplex _Cbuild( _Dcomplex _Cbuild(
@ -693,8 +777,11 @@ class TorrentLibrary {
); );
} }
late final __CbuildPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(ffi.Double, ffi.Double)>>('_Cbuild'); late final __CbuildPtr =
late final __Cbuild = __CbuildPtr.asFunction<_Dcomplex Function(double, double)>(); _lookup<ffi.NativeFunction<_Dcomplex Function(ffi.Double, ffi.Double)>>(
'_Cbuild');
late final __Cbuild =
__CbuildPtr.asFunction<_Dcomplex Function(double, double)>();
_Dcomplex _Cmulcc( _Dcomplex _Cmulcc(
_Dcomplex _X, _Dcomplex _X,
@ -706,8 +793,11 @@ class TorrentLibrary {
); );
} }
late final __CmulccPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>('_Cmulcc'); late final __CmulccPtr =
late final __Cmulcc = __CmulccPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>(); _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>>(
'_Cmulcc');
late final __Cmulcc =
__CmulccPtr.asFunction<_Dcomplex Function(_Dcomplex, _Dcomplex)>();
_Dcomplex _Cmulcr( _Dcomplex _Cmulcr(
_Dcomplex _X, _Dcomplex _X,
@ -719,8 +809,11 @@ class TorrentLibrary {
); );
} }
late final __CmulcrPtr = _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, ffi.Double)>>('_Cmulcr'); late final __CmulcrPtr =
late final __Cmulcr = __CmulcrPtr.asFunction<_Dcomplex Function(_Dcomplex, double)>(); _lookup<ffi.NativeFunction<_Dcomplex Function(_Dcomplex, ffi.Double)>>(
'_Cmulcr');
late final __Cmulcr =
__CmulcrPtr.asFunction<_Dcomplex Function(_Dcomplex, double)>();
_Fcomplex _FCbuild( _Fcomplex _FCbuild(
double _Re, double _Re,
@ -732,8 +825,11 @@ class TorrentLibrary {
); );
} }
late final __FCbuildPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(ffi.Float, ffi.Float)>>('_FCbuild'); late final __FCbuildPtr =
late final __FCbuild = __FCbuildPtr.asFunction<_Fcomplex Function(double, double)>(); _lookup<ffi.NativeFunction<_Fcomplex Function(ffi.Float, ffi.Float)>>(
'_FCbuild');
late final __FCbuild =
__FCbuildPtr.asFunction<_Fcomplex Function(double, double)>();
_Fcomplex _FCmulcc( _Fcomplex _FCmulcc(
_Fcomplex _X, _Fcomplex _X,
@ -745,8 +841,11 @@ class TorrentLibrary {
); );
} }
late final __FCmulccPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>('_FCmulcc'); late final __FCmulccPtr =
late final __FCmulcc = __FCmulccPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>(); _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>>(
'_FCmulcc');
late final __FCmulcc =
__FCmulccPtr.asFunction<_Fcomplex Function(_Fcomplex, _Fcomplex)>();
_Fcomplex _FCmulcr( _Fcomplex _FCmulcr(
_Fcomplex _X, _Fcomplex _X,
@ -758,8 +857,11 @@ class TorrentLibrary {
); );
} }
late final __FCmulcrPtr = _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, ffi.Float)>>('_FCmulcr'); late final __FCmulcrPtr =
late final __FCmulcr = __FCmulcrPtr.asFunction<_Fcomplex Function(_Fcomplex, double)>(); _lookup<ffi.NativeFunction<_Fcomplex Function(_Fcomplex, ffi.Float)>>(
'_FCmulcr');
late final __FCmulcr =
__FCmulcrPtr.asFunction<_Fcomplex Function(_Fcomplex, double)>();
Start_return Start( Start_return Start(
ffi.Pointer<ffi.Char> mcfg, ffi.Pointer<ffi.Char> mcfg,
@ -769,8 +871,11 @@ class TorrentLibrary {
); );
} }
late final _StartPtr = _lookup<ffi.NativeFunction<Start_return Function(ffi.Pointer<ffi.Char>)>>('Start'); late final _StartPtr =
late final _Start = _StartPtr.asFunction<Start_return Function(ffi.Pointer<ffi.Char>)>(); _lookup<ffi.NativeFunction<Start_return Function(ffi.Pointer<ffi.Char>)>>(
'Start');
late final _Start =
_StartPtr.asFunction<Start_return Function(ffi.Pointer<ffi.Char>)>();
} }
typedef va_list = ffi.Pointer<ffi.Char>; typedef va_list = ffi.Pointer<ffi.Char>;

View file

@ -47,7 +47,8 @@ void main(List<String> args) async {
'Failed to find an installed WebView2 runtime or non-stable Microsoft Edge installation.'); 'Failed to find an installed WebView2 runtime or non-stable Microsoft Edge installation.');
final document = await getApplicationDocumentsDirectory(); final document = await getApplicationDocumentsDirectory();
webViewEnvironment = await WebViewEnvironment.create( webViewEnvironment = await WebViewEnvironment.create(
settings: WebViewEnvironmentSettings(userDataFolder: p.join(document.path, 'flutter_inappwebview'))); settings: WebViewEnvironmentSettings(
userDataFolder: p.join(document.path, 'flutter_inappwebview')));
} }
isar = await StorageProvider().initDB(null, inspector: kDebugMode); isar = await StorageProvider().initDB(null, inspector: kDebugMode);
await StorageProvider().requestPermission(); await StorageProvider().requestPermission();

View file

@ -7,7 +7,10 @@ class Category {
Id? id; Id? id;
String? name; String? name;
bool? forManga; 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) { Category.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@ -15,5 +18,6 @@ class Category {
forManga = json['forManga']; forManga = json['forManga'];
} }
Map<String, dynamic> toJson() => {'id': id, 'name': name, 'forManga': forManga}; Map<String, dynamic> toJson() =>
{'id': id, 'name': name, 'forManga': forManga};
} }

View file

@ -48,7 +48,13 @@ class UpdatedChapter {
bool? isRead; bool? isRead;
String? lastPageRead; String? lastPageRead;
bool? deleted; bool? deleted;
UpdatedChapter({this.chapterId, this.mangaId, this.isBookmarked, this.isRead, this.lastPageRead, this.deleted}); UpdatedChapter(
{this.chapterId,
this.mangaId,
this.isBookmarked,
this.isRead,
this.lastPageRead,
this.deleted});
UpdatedChapter.fromJson(Map<String, dynamic> json) { UpdatedChapter.fromJson(Map<String, dynamic> json) {
chapterId = json['chapterId']; chapterId = json['chapterId'];
mangaId = json['mangaId']; mangaId = json['mangaId'];

View file

@ -33,6 +33,11 @@ class History {
mangaId = json['mangaId']; mangaId = json['mangaId'];
} }
Map<String, dynamic> toJson() => Map<String, dynamic> toJson() => {
{'chapterId': chapterId, 'date': date, 'id': id, 'isManga': isManga, 'mangaId': mangaId}; 'chapterId': chapterId,
'date': date,
'id': id,
'isManga': isManga,
'mangaId': mangaId
};
} }

View file

@ -118,4 +118,11 @@ class Manga {
}; };
} }
enum Status { ongoing, completed, canceled, unknown, onHiatus, publishingFinished } enum Status {
ongoing,
completed,
canceled,
unknown,
onHiatus,
publishingFinished
}

View file

@ -280,45 +280,62 @@ class Settings {
Settings.fromJson(Map<String, dynamic> json) { Settings.fromJson(Map<String, dynamic> json) {
animatePageTransitions = json['animatePageTransitions']; animatePageTransitions = json['animatePageTransitions'];
animeDisplayType = DisplayType.values[json['animeDisplayType'] ?? DisplayType.compactGrid.index]; animeDisplayType = DisplayType
.values[json['animeDisplayType'] ?? DisplayType.compactGrid.index];
animeLibraryDownloadedChapters = json['animeLibraryDownloadedChapters']; animeLibraryDownloadedChapters = json['animeLibraryDownloadedChapters'];
animeLibraryLocalSource = json['animeLibraryLocalSource']; animeLibraryLocalSource = json['animeLibraryLocalSource'];
animeLibraryShowCategoryTabs = json['animeLibraryShowCategoryTabs']; animeLibraryShowCategoryTabs = json['animeLibraryShowCategoryTabs'];
animeLibraryShowContinueReadingButton = json['animeLibraryShowContinueReadingButton']; animeLibraryShowContinueReadingButton =
json['animeLibraryShowContinueReadingButton'];
animeLibraryShowLanguage = json['animeLibraryShowLanguage']; animeLibraryShowLanguage = json['animeLibraryShowLanguage'];
animeLibraryShowNumbersOfItems = json['animeLibraryShowNumbersOfItems']; animeLibraryShowNumbersOfItems = json['animeLibraryShowNumbersOfItems'];
autoExtensionsUpdates = json['autoExtensionsUpdates']; autoExtensionsUpdates = json['autoExtensionsUpdates'];
backgroundColor = BackgroundColor.values[json['backgroundColor'] ?? BackgroundColor.black.index]; backgroundColor = BackgroundColor
.values[json['backgroundColor'] ?? BackgroundColor.black.index];
if (json['chapterFilterBookmarkedList'] != null) { if (json['chapterFilterBookmarkedList'] != null) {
chapterFilterBookmarkedList = chapterFilterBookmarkedList =
(json['chapterFilterBookmarkedList'] as List).map((e) => ChapterFilterBookmarked.fromJson(e)).toList(); (json['chapterFilterBookmarkedList'] as List)
.map((e) => ChapterFilterBookmarked.fromJson(e))
.toList();
} }
if (json['chapterFilterDownloadedList'] != null) { if (json['chapterFilterDownloadedList'] != null) {
chapterFilterDownloadedList = chapterFilterDownloadedList =
(json['chapterFilterDownloadedList'] as List).map((e) => ChapterFilterDownloaded.fromJson(e)).toList(); (json['chapterFilterDownloadedList'] as List)
.map((e) => ChapterFilterDownloaded.fromJson(e))
.toList();
} }
if (json['chapterFilterUnreadList'] != null) { if (json['chapterFilterUnreadList'] != null) {
chapterFilterUnreadList = chapterFilterUnreadList = (json['chapterFilterUnreadList'] as List)
(json['chapterFilterUnreadList'] as List).map((e) => ChapterFilterUnread.fromJson(e)).toList(); .map((e) => ChapterFilterUnread.fromJson(e))
.toList();
} }
if (json['chapterPageIndexList'] != null) { if (json['chapterPageIndexList'] != null) {
chapterPageIndexList = (json['chapterPageIndexList'] as List).map((e) => ChapterPageIndex.fromJson(e)).toList(); chapterPageIndexList = (json['chapterPageIndexList'] as List)
.map((e) => ChapterPageIndex.fromJson(e))
.toList();
} }
if (json['chapterPageUrlsList'] != null) { if (json['chapterPageUrlsList'] != null) {
chapterPageUrlsList = (json['chapterPageUrlsList'] as List).map((e) => ChapterPageurls.fromJson(e)).toList(); chapterPageUrlsList = (json['chapterPageUrlsList'] as List)
.map((e) => ChapterPageurls.fromJson(e))
.toList();
} }
checkForExtensionUpdates = json['checkForExtensionUpdates']; checkForExtensionUpdates = json['checkForExtensionUpdates'];
if (json['cookiesList'] != null) { if (json['cookiesList'] != null) {
cookiesList = (json['cookiesList'] as List).map((e) => MCookie.fromJson(e)).toList(); cookiesList = (json['cookiesList'] as List)
.map((e) => MCookie.fromJson(e))
.toList();
} }
cropBorders = json['cropBorders']; cropBorders = json['cropBorders'];
dateFormat = json['dateFormat']; dateFormat = json['dateFormat'];
defaultReaderMode = ReaderMode.values[json['defaultReaderMode'] ?? ReaderMode.vertical.index]; defaultReaderMode = ReaderMode
.values[json['defaultReaderMode'] ?? ReaderMode.vertical.index];
displayType = DisplayType.values[json['displayType']]; displayType = DisplayType.values[json['displayType']];
doubleTapAnimationSpeed = json['doubleTapAnimationSpeed']; doubleTapAnimationSpeed = json['doubleTapAnimationSpeed'];
downloadLocation = json['downloadLocation']; downloadLocation = json['downloadLocation'];
downloadOnlyOnWifi = json['downloadOnlyOnWifi']; downloadOnlyOnWifi = json['downloadOnlyOnWifi'];
filterScanlatorList = (json['filterScanlatorList'] as List?)?.map((e) => FilterScanlator.fromJson(e)).toList(); filterScanlatorList = (json['filterScanlatorList'] as List?)
?.map((e) => FilterScanlator.fromJson(e))
.toList();
flexColorSchemeBlendLevel = json['flexColorSchemeBlendLevel'] is double flexColorSchemeBlendLevel = json['flexColorSchemeBlendLevel'] is double
? json['flexColorSchemeBlendLevel'] ? json['flexColorSchemeBlendLevel']
: (json['flexColorSchemeBlendLevel'] as int).toDouble(); : (json['flexColorSchemeBlendLevel'] as int).toDouble();
@ -330,7 +347,8 @@ class Settings {
libraryFilterAnimeDownloadType = json['libraryFilterAnimeDownloadType']; libraryFilterAnimeDownloadType = json['libraryFilterAnimeDownloadType'];
libraryFilterAnimeStartedType = json['libraryFilterAnimeStartedType']; libraryFilterAnimeStartedType = json['libraryFilterAnimeStartedType'];
libraryFilterAnimeUnreadType = json['libraryFilterAnimeUnreadType']; libraryFilterAnimeUnreadType = json['libraryFilterAnimeUnreadType'];
libraryFilterMangasBookMarkedType = json['libraryFilterMangasBookMarkedType']; libraryFilterMangasBookMarkedType =
json['libraryFilterMangasBookMarkedType'];
libraryFilterMangasDownloadType = json['libraryFilterMangasDownloadType']; libraryFilterMangasDownloadType = json['libraryFilterMangasDownloadType'];
libraryFilterMangasStartedType = json['libraryFilterMangasStartedType']; libraryFilterMangasStartedType = json['libraryFilterMangasStartedType'];
libraryFilterMangasUnreadType = json['libraryFilterMangasUnreadType']; libraryFilterMangasUnreadType = json['libraryFilterMangasUnreadType'];
@ -339,28 +357,41 @@ class Settings {
libraryShowContinueReadingButton = json['libraryShowContinueReadingButton']; libraryShowContinueReadingButton = json['libraryShowContinueReadingButton'];
libraryShowLanguage = json['libraryShowLanguage']; libraryShowLanguage = json['libraryShowLanguage'];
libraryShowNumbersOfItems = json['libraryShowNumbersOfItems']; libraryShowNumbersOfItems = json['libraryShowNumbersOfItems'];
locale = json['locale'] != null ? L10nLocale.fromJson(json['locale']) : null; locale =
json['locale'] != null ? L10nLocale.fromJson(json['locale']) : null;
onlyIncludePinnedSources = json['onlyIncludePinnedSources']; onlyIncludePinnedSources = json['onlyIncludePinnedSources'];
pagePreloadAmount = json['pagePreloadAmount']; pagePreloadAmount = json['pagePreloadAmount'];
if (json['personalPageModeList'] != null) { if (json['personalPageModeList'] != null) {
personalPageModeList = (json['personalPageModeList'] as List).map((e) => PersonalPageMode.fromJson(e)).toList(); personalPageModeList = (json['personalPageModeList'] as List)
.map((e) => PersonalPageMode.fromJson(e))
.toList();
} }
if (json['personalReaderModeList'] != null) { if (json['personalReaderModeList'] != null) {
personalReaderModeList = personalReaderModeList = (json['personalReaderModeList'] as List)
(json['personalReaderModeList'] as List).map((e) => PersonalReaderMode.fromJson(e)).toList(); .map((e) => PersonalReaderMode.fromJson(e))
.toList();
} }
pureBlackDarkMode = json['pureBlackDarkMode']; pureBlackDarkMode = json['pureBlackDarkMode'];
relativeTimesTamps = json['relativeTimesTamps']; relativeTimesTamps = json['relativeTimesTamps'];
saveAsCBZArchive = json['saveAsCBZArchive']; saveAsCBZArchive = json['saveAsCBZArchive'];
scaleType = ScaleType.values[json['scaleType'] ?? ScaleType.fitScreen.index]; scaleType =
ScaleType.values[json['scaleType'] ?? ScaleType.fitScreen.index];
showPagesNumber = json['showPagesNumber']; showPagesNumber = json['showPagesNumber'];
if (json['sortChapterList'] != null) { if (json['sortChapterList'] != null) {
sortChapterList = (json['sortChapterList'] as List).map((e) => SortChapter.fromJson(e)).toList(); sortChapterList = (json['sortChapterList'] as List)
.map((e) => SortChapter.fromJson(e))
.toList();
} }
sortLibraryAnime = json['sortLibraryAnime'] != null ? SortLibraryManga.fromJson(json['sortLibraryAnime']) : null; sortLibraryAnime = json['sortLibraryAnime'] != null
sortLibraryManga = json['sortLibraryManga'] != null ? SortLibraryManga.fromJson(json['sortLibraryManga']) : null; ? SortLibraryManga.fromJson(json['sortLibraryAnime'])
: null;
sortLibraryManga = json['sortLibraryManga'] != null
? SortLibraryManga.fromJson(json['sortLibraryManga'])
: null;
if (json['autoScrollPages'] != null) { if (json['autoScrollPages'] != null) {
autoScrollPages = (json['autoScrollPages'] as List).map((e) => AutoScrollPages.fromJson(e)).toList(); autoScrollPages = (json['autoScrollPages'] as List)
.map((e) => AutoScrollPages.fromJson(e))
.toList();
} }
themeIsDark = json['themeIsDark']; themeIsDark = json['themeIsDark'];
userAgent = json['userAgent']; userAgent = json['userAgent'];
@ -384,17 +415,22 @@ class Settings {
aniSkipTimeoutLength = json['aniSkipTimeoutLength']; aniSkipTimeoutLength = json['aniSkipTimeoutLength'];
btServerAddress = json['btServerAddress']; btServerAddress = json['btServerAddress'];
btServerPort = json['btServerPort']; btServerPort = json['btServerPort'];
customColorFilter = customColorFilter = json['customColorFilter'] != null
json['customColorFilter'] != null ? CustomColorFilter.fromJson(json['customColorFilter']) : null; ? CustomColorFilter.fromJson(json['customColorFilter'])
: null;
enableCustomColorFilter = json['enableCustomColorFilter']; enableCustomColorFilter = json['enableCustomColorFilter'];
colorFilterBlendMode = ColorFilterBlendMode.values[json['colorFilterBlendMode'] ?? ColorFilterBlendMode.none]; colorFilterBlendMode = ColorFilterBlendMode
playerSubtitleSettings = .values[json['colorFilterBlendMode'] ?? ColorFilterBlendMode.none];
json['playerSubtitleSettings'] != null ? PlayerSubtitleSettings.fromJson(json['playerSubtitleSettings']) : null; playerSubtitleSettings = json['playerSubtitleSettings'] != null
mangaHomeDisplayType = DisplayType.values[json['mangaHomeDisplayType'] ?? DisplayType.comfortableGrid.index]; ? PlayerSubtitleSettings.fromJson(json['playerSubtitleSettings'])
: null;
mangaHomeDisplayType = DisplayType.values[
json['mangaHomeDisplayType'] ?? DisplayType.comfortableGrid.index];
appFontFamily = json['appFontFamily']; appFontFamily = json['appFontFamily'];
mangaGridSize = json['mangaGridSize']; mangaGridSize = json['mangaGridSize'];
animeGridSize = json['animeGridSize']; animeGridSize = json['animeGridSize'];
disableSectionType = SectionType.values[json['disableSectionType'] ?? SectionType.all]; disableSectionType =
SectionType.values[json['disableSectionType'] ?? SectionType.all];
useLibass = json['useLibass']; useLibass = json['useLibass'];
} }
@ -404,16 +440,22 @@ class Settings {
'animeLibraryDownloadedChapters': animeLibraryDownloadedChapters, 'animeLibraryDownloadedChapters': animeLibraryDownloadedChapters,
'animeLibraryLocalSource': animeLibraryLocalSource, 'animeLibraryLocalSource': animeLibraryLocalSource,
'animeLibraryShowCategoryTabs': animeLibraryShowCategoryTabs, 'animeLibraryShowCategoryTabs': animeLibraryShowCategoryTabs,
'animeLibraryShowContinueReadingButton': animeLibraryShowContinueReadingButton, 'animeLibraryShowContinueReadingButton':
animeLibraryShowContinueReadingButton,
'animeLibraryShowLanguage': animeLibraryShowLanguage, 'animeLibraryShowLanguage': animeLibraryShowLanguage,
'animeLibraryShowNumbersOfItems': animeLibraryShowNumbersOfItems, 'animeLibraryShowNumbersOfItems': animeLibraryShowNumbersOfItems,
'autoExtensionsUpdates': autoExtensionsUpdates, 'autoExtensionsUpdates': autoExtensionsUpdates,
'backgroundColor': backgroundColor.index, 'backgroundColor': backgroundColor.index,
'chapterFilterBookmarkedList': chapterFilterBookmarkedList?.map((v) => v.toJson()).toList(), 'chapterFilterBookmarkedList':
'chapterFilterDownloadedList': chapterFilterDownloadedList?.map((v) => v.toJson()).toList(), chapterFilterBookmarkedList?.map((v) => v.toJson()).toList(),
'chapterFilterUnreadList': chapterFilterUnreadList?.map((v) => v.toJson()).toList(), 'chapterFilterDownloadedList':
'chapterPageIndexList': chapterPageIndexList?.map((v) => v.toJson()).toList(), chapterFilterDownloadedList?.map((v) => v.toJson()).toList(),
'chapterPageUrlsList': chapterPageUrlsList?.map((v) => v.toJson()).toList(), 'chapterFilterUnreadList':
chapterFilterUnreadList?.map((v) => v.toJson()).toList(),
'chapterPageIndexList':
chapterPageIndexList?.map((v) => v.toJson()).toList(),
'chapterPageUrlsList':
chapterPageUrlsList?.map((v) => v.toJson()).toList(),
'checkForExtensionUpdates': checkForExtensionUpdates, 'checkForExtensionUpdates': checkForExtensionUpdates,
'cookiesList': cookiesList, 'cookiesList': cookiesList,
'cropBorders': cropBorders, 'cropBorders': cropBorders,
@ -445,8 +487,10 @@ class Settings {
'locale': locale?.toJson(), 'locale': locale?.toJson(),
'onlyIncludePinnedSources': onlyIncludePinnedSources, 'onlyIncludePinnedSources': onlyIncludePinnedSources,
'pagePreloadAmount': pagePreloadAmount, 'pagePreloadAmount': pagePreloadAmount,
'personalPageModeList': personalPageModeList?.map((v) => v.toJson()).toList(), 'personalPageModeList':
'personalReaderModeList': personalReaderModeList?.map((v) => v.toJson()).toList(), personalPageModeList?.map((v) => v.toJson()).toList(),
'personalReaderModeList':
personalReaderModeList?.map((v) => v.toJson()).toList(),
'pureBlackDarkMode': pureBlackDarkMode, 'pureBlackDarkMode': pureBlackDarkMode,
'relativeTimesTamps': relativeTimesTamps, 'relativeTimesTamps': relativeTimesTamps,
'saveAsCBZArchive': saveAsCBZArchive, 'saveAsCBZArchive': saveAsCBZArchive,
@ -477,10 +521,12 @@ class Settings {
'btServerAddress': btServerAddress, 'btServerAddress': btServerAddress,
'btServerPort': btServerPort, 'btServerPort': btServerPort,
'fullScreenReader': fullScreenReader, 'fullScreenReader': fullScreenReader,
if (customColorFilter != null) 'customColorFilter': customColorFilter!.toJson(), if (customColorFilter != null)
'customColorFilter': customColorFilter!.toJson(),
'enableCustomColorFilter': enableCustomColorFilter, 'enableCustomColorFilter': enableCustomColorFilter,
'colorFilterBlendMode': colorFilterBlendMode.index, 'colorFilterBlendMode': colorFilterBlendMode.index,
if (playerSubtitleSettings != null) 'playerSubtitleSettings': playerSubtitleSettings!.toJson(), if (playerSubtitleSettings != null)
'playerSubtitleSettings': playerSubtitleSettings!.toJson(),
'mangaHomeDisplayType': mangaHomeDisplayType.index, 'mangaHomeDisplayType': mangaHomeDisplayType.index,
'appFontFamily': appFontFamily, 'appFontFamily': appFontFamily,
'mangaGridSize': mangaGridSize, 'mangaGridSize': mangaGridSize,
@ -549,7 +595,8 @@ class SortChapter {
reverse = json['reverse']; reverse = json['reverse'];
} }
Map<String, dynamic> toJson() => {'index': index, 'mangaId': mangaId, 'reverse': reverse}; Map<String, dynamic> toJson() =>
{'index': index, 'mangaId': mangaId, 'reverse': reverse};
} }
@embedded @embedded
@ -604,7 +651,8 @@ class ChapterPageurls {
urls = json['headers']?.cast<String>(); urls = json['headers']?.cast<String>();
} }
Map<String, dynamic> toJson() => {'chapterId': chapterId, 'urls': urls, 'headers': headers}; Map<String, dynamic> toJson() =>
{'chapterId': chapterId, 'urls': urls, 'headers': headers};
} }
@embedded @embedded
@ -634,7 +682,8 @@ class PersonalReaderMode {
readerMode = ReaderMode.values[json['readerMode']]; readerMode = ReaderMode.values[json['readerMode']];
} }
Map<String, dynamic> toJson() => {'mangaId': mangaId, 'readerMode': readerMode.index}; Map<String, dynamic> toJson() =>
{'mangaId': mangaId, 'readerMode': readerMode.index};
} }
@embedded @embedded
@ -642,7 +691,8 @@ class AutoScrollPages {
int? mangaId; int? mangaId;
double? pageOffset; double? pageOffset;
bool? autoScroll; bool? autoScroll;
AutoScrollPages({this.mangaId, this.pageOffset = 10, this.autoScroll = false}); AutoScrollPages(
{this.mangaId, this.pageOffset = 10, this.autoScroll = false});
AutoScrollPages.fromJson(Map<String, dynamic> json) { AutoScrollPages.fromJson(Map<String, dynamic> json) {
mangaId = json['mangaId']; mangaId = json['mangaId'];
@ -650,7 +700,8 @@ class AutoScrollPages {
autoScroll = json['autoScroll']; autoScroll = json['autoScroll'];
} }
Map<String, dynamic> toJson() => {'mangaId': mangaId, 'pageOffset': pageOffset, 'autoScroll': autoScroll}; Map<String, dynamic> toJson() =>
{'mangaId': mangaId, 'pageOffset': pageOffset, 'autoScroll': autoScroll};
} }
@embedded @embedded
@ -666,10 +717,18 @@ class PersonalPageMode {
pageMode = PageMode.values[json['pageMode']]; pageMode = PageMode.values[json['pageMode']];
} }
Map<String, dynamic> toJson() => {'mangaId': mangaId, 'pageMode': pageMode.index}; Map<String, dynamic> toJson() =>
{'mangaId': mangaId, 'pageMode': pageMode.index};
} }
enum ReaderMode { vertical, ltr, rtl, verticalContinuous, webtoon, horizontalContinuous } enum ReaderMode {
vertical,
ltr,
rtl,
verticalContinuous,
webtoon,
horizontalContinuous
}
enum PageMode { onePage, doublePage } enum PageMode { onePage, doublePage }
@ -684,7 +743,8 @@ class FilterScanlator {
scanlators = json['scanlators']?.cast<String>(); scanlators = json['scanlators']?.cast<String>();
} }
Map<String, dynamic> toJson() => {'mangaId': mangaId, 'scanlators': scanlators}; Map<String, dynamic> toJson() =>
{'mangaId': mangaId, 'scanlators': scanlators};
} }
@embedded @embedded
@ -698,7 +758,8 @@ class L10nLocale {
languageCode = json['languageCode']; languageCode = json['languageCode'];
} }
Map<String, dynamic> toJson() => {'countryCode': countryCode, 'languageCode': languageCode}; Map<String, dynamic> toJson() =>
{'countryCode': countryCode, 'languageCode': languageCode};
} }
@embedded @embedded

View file

@ -115,7 +115,8 @@ class Source {
additionalParams = json['additionalParams'] ?? ""; additionalParams = json['additionalParams'] ?? "";
isObsolete = json['isObsolete']; isObsolete = json['isObsolete'];
isLocal = json['isLocal']; isLocal = json['isLocal'];
sourceCodeLanguage = SourceCodeLanguage.values[json['sourceCodeLanguage'] ?? 0]; sourceCodeLanguage =
SourceCodeLanguage.values[json['sourceCodeLanguage'] ?? 0];
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

View file

@ -83,4 +83,14 @@ class Track {
}; };
} }
enum TrackStatus { reading, completed, onHold, dropped, planToRead, rereading, watching, planToWatch, reWatching } enum TrackStatus {
reading,
completed,
onHold,
dropped,
planToRead,
rereading,
watching,
planToWatch,
reWatching
}

View file

@ -26,5 +26,6 @@ class TrackPreference {
prefs = json['prefs']; prefs = json['prefs'];
} }
Map<String, dynamic> toJson() => {'syncId': syncId, 'username': username, 'oAuth': oAuth, 'prefs': prefs}; Map<String, dynamic> toJson() =>
{'syncId': syncId, 'username': username, 'oAuth': oAuth, 'prefs': prefs};
} }

View file

@ -8,13 +8,20 @@ class Video {
List<Track>? subtitles; List<Track>? subtitles;
List<Track>? audios; List<Track>? audios;
Video(this.url, this.quality, this.originalUrl, {this.headers, this.subtitles, this.audios}); Video(this.url, this.quality, this.originalUrl,
{this.headers, this.subtitles, this.audios});
factory Video.fromJson(Map<String, dynamic> json) { factory Video.fromJson(Map<String, dynamic> json) {
return Video( return Video(
json['url'].toString().trim(), json['quality'].toString().trim(), json['originalUrl'].toString().trim(), json['url'].toString().trim(),
json['quality'].toString().trim(),
json['originalUrl'].toString().trim(),
headers: (json['headers'] as Map?)?.toMapStringString, headers: (json['headers'] as Map?)?.toMapStringString,
subtitles: json['subtitles'] != null ? (json['subtitles'] as List).map((e) => Track.fromJson(e)).toList() : [], subtitles: json['subtitles'] != null
audios: json['audios'] != null ? (json['audios'] as List).map((e) => Track.fromJson(e)).toList() : []); ? (json['subtitles'] as List).map((e) => Track.fromJson(e)).toList()
: [],
audios: json['audios'] != null
? (json['audios'] as List).map((e) => Track.fromJson(e)).toList()
: []);
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'url': url, 'url': url,

View file

@ -50,7 +50,8 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
for (var infoHash in _infoHashList) { for (var infoHash in _infoHashList) {
MTorrentServer().removeTorrent(infoHash); MTorrentServer().removeTorrent(infoHash);
} }
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
super.dispose(); super.dispose();
} }
@ -64,13 +65,15 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversData = ref.watch(getVideoListProvider(episode: widget.episode)); final serversData =
ref.watch(getVideoListProvider(episode: widget.episode));
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return serversData.when( return serversData.when(
data: (data) { data: (data) {
final (videos, isLocal, infoHashList) = data; final (videos, isLocal, infoHashList) = data;
_infoHashList = infoHashList; _infoHashList = infoHashList;
if (videos.isEmpty && !(widget.episode.manga.value!.isLocalArchive ?? false)) { if (videos.isEmpty &&
!(widget.episode.manga.value!.isLocalArchive ?? false)) {
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar( appBar: AppBar(
@ -102,7 +105,8 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
title: const Text(''), title: const Text(''),
leading: BackButton( leading: BackButton(
onPressed: () { onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
@ -120,7 +124,8 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
leading: BackButton( leading: BackButton(
color: Colors.white, color: Colors.white,
onPressed: () { onPressed: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
@ -150,18 +155,24 @@ class AnimeStreamPage extends riv.ConsumerStatefulWidget {
riv.ConsumerState<AnimeStreamPage> createState() => _AnimeStreamPageState(); riv.ConsumerState<AnimeStreamPage> createState() => _AnimeStreamPageState();
} }
class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with TickerProviderStateMixin { class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
with TickerProviderStateMixin {
late final GlobalKey<VideoState> _key = GlobalKey<VideoState>(); late final GlobalKey<VideoState> _key = GlobalKey<VideoState>();
late final useLibass = ref.read(useLibassStateProvider); late final useLibass = ref.read(useLibassStateProvider);
late final Player _player = Player(configuration: PlayerConfiguration(libass: useLibass)); late final Player _player =
Player(configuration: PlayerConfiguration(libass: useLibass));
late final VideoController _controller = VideoController(_player); late final VideoController _controller = VideoController(_player);
late final _streamController = ref.read(animeStreamControllerProvider(episode: widget.episode).notifier); late final _streamController =
ref.read(animeStreamControllerProvider(episode: widget.episode).notifier);
late final _firstVid = widget.videos.first; late final _firstVid = widget.videos.first;
late final ValueNotifier<VideoPrefs?> _video = ValueNotifier(VideoPrefs( late final ValueNotifier<VideoPrefs?> _video = ValueNotifier(VideoPrefs(
videoTrack: VideoTrack(_firstVid.originalUrl, _firstVid.quality, _firstVid.quality), headers: _firstVid.headers)); videoTrack: VideoTrack(
_firstVid.originalUrl, _firstVid.quality, _firstVid.quality),
headers: _firstVid.headers));
final ValueNotifier<double> _playbackSpeed = ValueNotifier(1.0); final ValueNotifier<double> _playbackSpeed = ValueNotifier(1.0);
final ValueNotifier<bool> _enterFullScreen = ValueNotifier(false); final ValueNotifier<bool> _enterFullScreen = ValueNotifier(false);
late final ValueNotifier<Duration> _currentPosition = ValueNotifier(_streamController.geTCurrentPosition()); late final ValueNotifier<Duration> _currentPosition =
ValueNotifier(_streamController.geTCurrentPosition());
final ValueNotifier<Duration?> _currentTotalDuration = ValueNotifier(null); final ValueNotifier<Duration?> _currentTotalDuration = ValueNotifier(null);
final ValueNotifier<bool> _showFitLabel = ValueNotifier(false); final ValueNotifier<bool> _showFitLabel = ValueNotifier(false);
final ValueNotifier<bool> _isCompleted = ValueNotifier(false); final ValueNotifier<bool> _isCompleted = ValueNotifier(false);
@ -175,9 +186,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
bool _hasEndingSkip = false; bool _hasEndingSkip = false;
bool _initSubtitleAndAudio = true; bool _initSubtitleAndAudio = true;
late final StreamSubscription<Duration> _currentPositionSub = _player.stream.position.listen( late final StreamSubscription<Duration> _currentPositionSub =
_player.stream.position.listen(
(position) async { (position) async {
_isCompleted.value = _player.state.duration.inSeconds - _currentPosition.value.inSeconds <= 10; _isCompleted.value =
_player.state.duration.inSeconds - _currentPosition.value.inSeconds <=
10;
_currentPosition.value = position; _currentPosition.value = position;
if (_firstVid.subtitles?.isNotEmpty ?? false) { if (_firstVid.subtitles?.isNotEmpty ?? false) {
@ -191,8 +205,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} catch (_) {} } catch (_) {}
try { try {
if (_firstVid.audios?.isNotEmpty ?? false) { if (_firstVid.audios?.isNotEmpty ?? false) {
_player.setAudioTrack(AudioTrack.uri(_firstVid.audios!.first.file ?? "", _player.setAudioTrack(AudioTrack.uri(
title: _firstVid.audios!.first.label, language: _firstVid.audios!.first.label)); _firstVid.audios!.first.file ?? "",
title: _firstVid.audios!.first.label,
language: _firstVid.audios!.first.label));
} }
} catch (_) {} } catch (_) {}
} }
@ -201,13 +217,15 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
}, },
); );
late final StreamSubscription<Duration> _currentTotalDurationSub = _player.stream.duration.listen( late final StreamSubscription<Duration> _currentTotalDurationSub =
_player.stream.duration.listen(
(duration) { (duration) {
_currentTotalDuration.value = duration; _currentTotalDuration.value = duration;
}, },
); );
late final StreamSubscription<bool> _completed = _player.stream.completed.listen((val) { late final StreamSubscription<bool> _completed =
_player.stream.completed.listen((val) {
if (_streamController.getEpisodeIndex().$1 != 0 && val == true) { if (_streamController.getEpisodeIndex().$1 != 0 && val == true) {
if (mounted) { if (mounted) {
pushToNewEpisode(context, _streamController.getNextEpisode()); pushToNewEpisode(context, _streamController.getNextEpisode());
@ -231,12 +249,14 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
_loadAndroidFont().then( _loadAndroidFont().then(
(_) { (_) {
_player.open(Media(_video.value!.videoTrack!.id, _player.open(Media(_video.value!.videoTrack!.id,
httpHeaders: _video.value!.headers, start: _streamController.geTCurrentPosition())); httpHeaders: _video.value!.headers,
start: _streamController.geTCurrentPosition()));
if (widget.isTorrent) { if (widget.isTorrent) {
Future.delayed(const Duration(seconds: 10)).then((_) { Future.delayed(const Duration(seconds: 10)).then((_) {
if (mounted) { if (mounted) {
_player.open(Media(_video.value!.videoTrack!.id, _player.open(Media(_video.value!.videoTrack!.id,
httpHeaders: _video.value!.headers, start: _streamController.geTCurrentPosition())); httpHeaders: _video.value!.headers,
start: _streamController.geTCurrentPosition()));
} }
}); });
} }
@ -253,11 +273,14 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
final subDir = await getApplicationDocumentsDirectory(); final subDir = await getApplicationDocumentsDirectory();
final fontPath = path.join(subDir.path, 'subfont.ttf'); final fontPath = path.join(subDir.path, 'subfont.ttf');
final data = await rootBundle.load('assets/fonts/subfont.ttf'); final data = await rootBundle.load('assets/fonts/subfont.ttf');
final bytes = data.buffer.asInt8List(data.offsetInBytes, data.lengthInBytes); final bytes =
data.buffer.asInt8List(data.offsetInBytes, data.lengthInBytes);
final fontFile = await File(fontPath).create(recursive: true); final fontFile = await File(fontPath).create(recursive: true);
await fontFile.writeAsBytes(bytes); await fontFile.writeAsBytes(bytes);
await (_player.platform as NativePlayer).setProperty('sub-fonts-dir', subDir.path); await (_player.platform as NativePlayer)
await (_player.platform as NativePlayer).setProperty('sub-font', 'Droid Sans Fallback'); .setProperty('sub-fonts-dir', subDir.path);
await (_player.platform as NativePlayer)
.setProperty('sub-font', 'Droid Sans Fallback');
} catch (_) {} } catch (_) {}
} }
} }
@ -265,12 +288,14 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
void _initAniSkip() async { void _initAniSkip() async {
await _player.stream.buffer.first; await _player.stream.buffer.first;
_streamController.getAniSkipResults((result) { _streamController.getAniSkipResults((result) {
final openingRes = result.where((element) => element.skipType == "op").toList(); final openingRes =
result.where((element) => element.skipType == "op").toList();
_hasOpeningSkip = openingRes.isNotEmpty; _hasOpeningSkip = openingRes.isNotEmpty;
if (_hasOpeningSkip) { if (_hasOpeningSkip) {
_openingResult = openingRes.first; _openingResult = openingRes.first;
} }
final endingRes = result.where((element) => element.skipType == "ed").toList(); final endingRes =
result.where((element) => element.skipType == "ed").toList();
_hasEndingSkip = endingRes.isNotEmpty; _hasEndingSkip = endingRes.isNotEmpty;
if (_hasEndingSkip) { if (_hasEndingSkip) {
_endingResult = endingRes.first; _endingResult = endingRes.first;
@ -295,14 +320,17 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} }
void _setCurrentPosition(bool save) { void _setCurrentPosition(bool save) {
_streamController.setCurrentPosition(_currentPosition.value, _currentTotalDuration.value, save: save); _streamController.setCurrentPosition(
_currentPosition.value, _currentTotalDuration.value,
save: save);
_streamController.setAnimeHistoryUpdate(); _streamController.setAnimeHistoryUpdate();
_streamController.checkAndSyncProgress(); _streamController.checkAndSyncProgress();
} }
void _setLandscapeMode(bool state) { void _setLandscapeMode(bool state) {
if (state) { if (state) {
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]); SystemChrome.setPreferredOrientations(
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
} else { } else {
SystemChrome.setPreferredOrientations([ SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp, DeviceOrientation.portraitUp,
@ -317,7 +345,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
children: [ children: [
Flexible( Flexible(
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).padding.top), padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).padding.top),
child: Text(text, child: Text(text,
style: Theme.of(context).textTheme.bodyLarge!.copyWith( style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 16, fontSize: 16,
@ -331,7 +360,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
Widget _videoQualityWidget(BuildContext context) { Widget _videoQualityWidget(BuildContext context) {
List<VideoPrefs> videoQuality = _player.state.tracks.video List<VideoPrefs> videoQuality = _player.state.tracks.video
.where((element) => element.w != null && element.h != null && widget.isLocal) .where((element) =>
element.w != null && element.h != null && widget.isLocal)
.toList() .toList()
.map((e) => VideoPrefs(videoTrack: e, isLocal: true)) .map((e) => VideoPrefs(videoTrack: e, isLocal: true))
.toList(); .toList();
@ -339,7 +369,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
if (widget.videos.isNotEmpty && !widget.isLocal) { if (widget.videos.isNotEmpty && !widget.isLocal) {
for (var video in widget.videos) { for (var video in widget.videos) {
videoQuality.add(VideoPrefs( videoQuality.add(VideoPrefs(
videoTrack: VideoTrack(video.url, video.quality, video.quality), headers: video.headers, isLocal: false)); videoTrack: VideoTrack(video.url, video.quality, video.quality),
headers: video.headers,
isLocal: false));
} }
} }
@ -347,21 +379,27 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12), padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12),
child: Column( child: Column(
children: videoQuality.map((quality) { children: videoQuality.map((quality) {
final selected = _video.value!.videoTrack!.title == quality.videoTrack!.title || widget.isLocal; final selected =
_video.value!.videoTrack!.title == quality.videoTrack!.title ||
widget.isLocal;
return GestureDetector( return GestureDetector(
child: textWidget(widget.isLocal ? _firstVid.quality : quality.videoTrack!.title!, selected), child: textWidget(
widget.isLocal ? _firstVid.quality : quality.videoTrack!.title!,
selected),
onTap: () async { onTap: () async {
_video.value = quality; _video.value = quality;
if (quality.isLocal) { if (quality.isLocal) {
if (widget.isLocal) { if (widget.isLocal) {
_player.setVideoTrack(quality.videoTrack!); _player.setVideoTrack(quality.videoTrack!);
} else { } else {
_player _player.open(Media(quality.videoTrack!.id,
.open(Media(quality.videoTrack!.id, httpHeaders: quality.headers, start: _currentPosition.value)); httpHeaders: quality.headers,
start: _currentPosition.value));
} }
} else { } else {
_player _player.open(Media(quality.videoTrack!.id,
.open(Media(quality.videoTrack!.id, httpHeaders: quality.headers, start: _currentPosition.value)); httpHeaders: quality.headers,
start: _currentPosition.value));
} }
Navigator.pop(context); Navigator.pop(context);
}, },
@ -419,8 +457,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} }
Widget _videoSubtitle(BuildContext context, Function(bool) hasSubtitleTrack) { Widget _videoSubtitle(BuildContext context, Function(bool) hasSubtitleTrack) {
List<VideoPrefs> videoSubtitle = List<VideoPrefs> videoSubtitle = _player.state.tracks.subtitle
_player.state.tracks.subtitle.toList().map((e) => VideoPrefs(isLocal: true, subtitle: e)).toList(); .toList()
.map((e) => VideoPrefs(isLocal: true, subtitle: e))
.toList();
List<String> subs = []; List<String> subs = [];
if (widget.videos.isNotEmpty && !widget.isLocal) { if (widget.videos.isNotEmpty && !widget.isLocal) {
@ -443,7 +483,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
videoSubtitle = videoSubtitle videoSubtitle = videoSubtitle
.map((e) { .map((e) {
VideoPrefs vid = e; VideoPrefs vid = e;
vid.title = vid.subtitle?.title ?? vid.subtitle?.language ?? vid.subtitle?.channels ?? ""; vid.title = vid.subtitle?.title ??
vid.subtitle?.language ??
vid.subtitle?.channels ??
"";
return vid; return vid;
}) })
.toList() .toList()
@ -451,11 +494,16 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
.toList(); .toList();
videoSubtitle.sort((a, b) => a.title!.compareTo(b.title!)); videoSubtitle.sort((a, b) => a.title!.compareTo(b.title!));
hasSubtitleTrack.call(videoSubtitle.isNotEmpty); hasSubtitleTrack.call(videoSubtitle.isNotEmpty);
videoSubtitle.insert(0, VideoPrefs(isLocal: false, subtitle: SubtitleTrack.no())); videoSubtitle.insert(
0, VideoPrefs(isLocal: false, subtitle: SubtitleTrack.no()));
List<VideoPrefs> videoSubtitleLast = []; List<VideoPrefs> videoSubtitleLast = [];
for (var element in videoSubtitle) { for (var element in videoSubtitle) {
final contains = videoSubtitleLast.any((sub) { final contains = videoSubtitleLast.any((sub) {
return (sub.title ?? sub.subtitle?.title ?? sub.subtitle?.language ?? sub.subtitle?.channels ?? "None") == return (sub.title ??
sub.subtitle?.title ??
sub.subtitle?.language ??
sub.subtitle?.channels ??
"None") ==
(element.title ?? (element.title ??
element.subtitle?.title ?? element.subtitle?.title ??
element.subtitle?.language ?? element.subtitle?.language ??
@ -470,9 +518,17 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12), padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12),
child: Column( child: Column(
children: videoSubtitleLast.toSet().toList().map((sub) { children: videoSubtitleLast.toSet().toList().map((sub) {
final title = sub.title ?? sub.subtitle?.title ?? sub.subtitle?.language ?? sub.subtitle?.channels ?? "None"; final title = sub.title ??
sub.subtitle?.title ??
sub.subtitle?.language ??
sub.subtitle?.channels ??
"None";
final selected = (title == (subtitle.title ?? subtitle.language ?? subtitle.channels ?? "None")) || final selected = (title ==
(subtitle.title ??
subtitle.language ??
subtitle.channels ??
"None")) ||
(subtitle.id == "no" && title == "None"); (subtitle.id == "no" && title == "None");
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
@ -489,8 +545,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} }
Widget _videoAudios(BuildContext context) { Widget _videoAudios(BuildContext context) {
List<VideoPrefs> videoAudio = List<VideoPrefs> videoAudio = _player.state.tracks.audio
_player.state.tracks.audio.toList().map((e) => VideoPrefs(isLocal: true, audio: e)).toList(); .toList()
.map((e) => VideoPrefs(isLocal: true, audio: e))
.toList();
List<String> audios = []; List<String> audios = [];
if (widget.videos.isNotEmpty && !widget.isLocal) { if (widget.videos.isNotEmpty && !widget.isLocal) {
@ -498,7 +556,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
for (var audio in video.audios ?? []) { for (var audio in video.audios ?? []) {
if (!audios.contains(audio.file)) { if (!audios.contains(audio.file)) {
videoAudio.add(VideoPrefs( videoAudio.add(VideoPrefs(
isLocal: false, audio: AudioTrack.uri(audio.file!, title: audio.label, language: audio.label))); isLocal: false,
audio: AudioTrack.uri(audio.file!,
title: audio.label, language: audio.label)));
audios.add(audio.file!); audios.add(audio.file!);
} }
} }
@ -508,7 +568,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
videoAudio = videoAudio videoAudio = videoAudio
.map((e) { .map((e) {
VideoPrefs vid = e; VideoPrefs vid = e;
vid.title = vid.audio?.title ?? vid.audio?.language ?? vid.audio?.channels ?? ""; vid.title = vid.audio?.title ??
vid.audio?.language ??
vid.audio?.channels ??
"";
return vid; return vid;
}) })
.toList() .toList()
@ -520,8 +583,13 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12), padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 12),
child: Column( child: Column(
children: videoAudio.toSet().toList().map((aud) { children: videoAudio.toSet().toList().map((aud) {
final title = aud.title ?? aud.audio?.title ?? aud.audio?.language ?? aud.audio?.channels ?? "None"; final title = aud.title ??
final selected = (aud.audio == audio) || (audio.id == "no" && title == "None"); aud.audio?.title ??
aud.audio?.language ??
aud.audio?.channels ??
"None";
final selected =
(aud.audio == audio) || (audio.id == "no" && title == "None");
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
@ -542,8 +610,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
void _togglePlaybackSpeed() { void _togglePlaybackSpeed() {
List<double> allowedSpeeds = [0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75, 2.0]; List<double> allowedSpeeds = [0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75, 2.0];
if (allowedSpeeds.indexOf(_playbackSpeed.value) < allowedSpeeds.length - 1) { if (allowedSpeeds.indexOf(_playbackSpeed.value) <
_setPlaybackSpeed(allowedSpeeds[allowedSpeeds.indexOf(_playbackSpeed.value) + 1]); allowedSpeeds.length - 1) {
_setPlaybackSpeed(
allowedSpeeds[allowedSpeeds.indexOf(_playbackSpeed.value) + 1]);
} else { } else {
_setPlaybackSpeed(allowedSpeeds[0]); _setPlaybackSpeed(allowedSpeeds[0]);
} }
@ -576,20 +646,26 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} }
Widget _seekToWidget() { Widget _seekToWidget() {
final defaultSkipIntroLength = ref.watch(defaultSkipIntroLengthStateProvider); final defaultSkipIntroLength =
ref.watch(defaultSkipIntroLengthStateProvider);
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.symmetric(vertical: 5),
child: SizedBox( child: SizedBox(
height: 35, height: 35,
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
_tempPosition.value = Duration(seconds: defaultSkipIntroLength + _currentPosition.value.inSeconds); _tempPosition.value = Duration(
await _player.seek(Duration(seconds: _currentPosition.value.inSeconds + defaultSkipIntroLength)); seconds: defaultSkipIntroLength +
_currentPosition.value.inSeconds);
await _player.seek(Duration(
seconds: _currentPosition.value.inSeconds +
defaultSkipIntroLength));
_tempPosition.value = null; _tempPosition.value = null;
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text("+$defaultSkipIntroLength", style: const TextStyle(fontWeight: FontWeight.w100)), child: Text("+$defaultSkipIntroLength",
style: const TextStyle(fontWeight: FontWeight.w100)),
)), )),
), ),
); );
@ -631,7 +707,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
_togglePlaybackSpeed(); _togglePlaybackSpeed();
}), }),
IconButton( IconButton(
icon: const Icon(Icons.fit_screen_outlined, color: Colors.white), icon: const Icon(Icons.fit_screen_outlined,
color: Colors.white),
onPressed: () async { onPressed: () async {
_changeFitLabel(ref); _changeFitLabel(ref);
}, },
@ -644,7 +721,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
_setLandscapeMode(!snapshot); _setLandscapeMode(!snapshot);
_enterFullScreen.value = !snapshot; _enterFullScreen.value = !snapshot;
}, },
icon: Icon(snapshot ? Icons.fullscreen_exit : Icons.fullscreen), icon: Icon(snapshot
? Icons.fullscreen_exit
: Icons.fullscreen),
iconSize: 25, iconSize: 25,
color: Colors.white, color: Colors.white,
); );
@ -661,7 +740,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
Widget _desktopBottomButtonBar(BuildContext context) { Widget _desktopBottomButtonBar(BuildContext context) {
bool hasPrevEpisode = _streamController.getEpisodeIndex().$1 + 1 != bool hasPrevEpisode = _streamController.getEpisodeIndex().$1 + 1 !=
_streamController.getEpisodesLength(_streamController.getEpisodeIndex().$2); _streamController
.getEpisodesLength(_streamController.getEpisodeIndex().$2);
bool hasNextEpisode = _streamController.getEpisodeIndex().$1 != 0; bool hasNextEpisode = _streamController.getEpisodeIndex().$1 != 0;
final skipDuration = ref.watch(defaultDoubleTapToSkipLengthStateProvider); final skipDuration = ref.watch(defaultDoubleTapToSkipLengthStateProvider);
return Column( return Column(
@ -675,7 +755,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
if (hasPrevEpisode) if (hasPrevEpisode)
IconButton( IconButton(
onPressed: () { onPressed: () {
pushToNewEpisode(context, _streamController.getPrevEpisode()); pushToNewEpisode(
context, _streamController.getPrevEpisode());
}, },
icon: const Icon( icon: const Icon(
Icons.skip_previous, Icons.skip_previous,
@ -688,7 +769,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
if (hasNextEpisode) if (hasNextEpisode)
IconButton( IconButton(
onPressed: () async { onPressed: () async {
pushToNewEpisode(context, _streamController.getNextEpisode()); pushToNewEpisode(
context, _streamController.getNextEpisode());
}, },
icon: const Icon(Icons.skip_next, color: Colors.white), icon: const Icon(Icons.skip_next, color: Colors.white),
), ),
@ -697,8 +779,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
width: 50, width: 50,
child: IconButton( child: IconButton(
onPressed: () async { onPressed: () async {
_tempPosition.value = Duration(seconds: skipDuration - _currentPosition.value.inSeconds); _tempPosition.value = Duration(
await _player.seek(Duration(seconds: _currentPosition.value.inSeconds - skipDuration)); seconds:
skipDuration - _currentPosition.value.inSeconds);
await _player.seek(Duration(
seconds:
_currentPosition.value.inSeconds - skipDuration));
_tempPosition.value = null; _tempPosition.value = null;
}, },
icon: Stack( icon: Stack(
@ -716,7 +802,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.only(top: 2), padding: const EdgeInsets.only(top: 2),
child: Text( child: Text(
skipDuration.toString(), skipDuration.toString(),
style: const TextStyle(fontSize: 9, color: Colors.white), style: const TextStyle(
fontSize: 9, color: Colors.white),
), ),
)), )),
), ),
@ -729,8 +816,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
width: 50, width: 50,
child: IconButton( child: IconButton(
onPressed: () async { onPressed: () async {
_tempPosition.value = Duration(seconds: skipDuration + _currentPosition.value.inSeconds); _tempPosition.value = Duration(
await _player.seek(Duration(seconds: _currentPosition.value.inSeconds + skipDuration)); seconds:
skipDuration + _currentPosition.value.inSeconds);
await _player.seek(Duration(
seconds:
_currentPosition.value.inSeconds + skipDuration));
_tempPosition.value = null; _tempPosition.value = null;
}, },
icon: Stack( icon: Stack(
@ -748,7 +839,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
padding: const EdgeInsets.only(top: 2), padding: const EdgeInsets.only(top: 2),
child: Text( child: Text(
skipDuration.toString(), skipDuration.toString(),
style: const TextStyle(fontSize: 9, color: Colors.white), style: const TextStyle(
fontSize: 9, color: Colors.white),
), ),
)), )),
), ),
@ -762,7 +854,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
ValueListenableBuilder( ValueListenableBuilder(
valueListenable: _tempPosition, valueListenable: _tempPosition,
builder: (context, value, child) => builder: (context, value, child) =>
CustomMaterialDesktopPositionIndicator(delta: value, controller: _controller), CustomMaterialDesktopPositionIndicator(
delta: value, controller: _controller),
) )
], ],
), ),
@ -789,7 +882,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
_togglePlaybackSpeed(); _togglePlaybackSpeed();
}), }),
IconButton( IconButton(
icon: const Icon(Icons.fit_screen_outlined, color: Colors.white), icon: const Icon(Icons.fit_screen_outlined,
color: Colors.white),
onPressed: () async { onPressed: () async {
_changeFitLabel(ref); _changeFitLabel(ref);
}, },
@ -810,7 +904,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
valueListenable: _enterFullScreen, valueListenable: _enterFullScreen,
builder: (context, fullScreen, _) { builder: (context, fullScreen, _) {
return Padding( return Padding(
padding: EdgeInsets.only(top: !_isDesktop && !fullScreen ? MediaQuery.of(context).padding.top : 0), padding: EdgeInsets.only(
top: !_isDesktop && !fullScreen
? MediaQuery.of(context).padding.top
: 0),
child: Row( child: Row(
children: [ children: [
BackButton( BackButton(
@ -825,7 +922,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} }
} }
} else { } else {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
if (mounted) { if (mounted) {
Navigator.pop(context); Navigator.pop(context);
} }
@ -839,7 +937,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
width: context.width(0.8), width: context.width(0.8),
child: Text( child: Text(
widget.episode.manga.value!.name!, widget.episode.manga.value!.name!,
style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white), style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.white),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
@ -848,7 +947,9 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
child: Text( child: Text(
widget.episode.name!, widget.episode.name!,
style: TextStyle( style: TextStyle(
fontSize: 12, fontWeight: FontWeight.w400, color: Colors.white.withValues(alpha: 0.7)), fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.white.withValues(alpha: 0.7)),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
@ -924,7 +1025,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
void _resize(BoxFit fit) async { void _resize(BoxFit fit) async {
await Future.delayed(const Duration(milliseconds: 100)); await Future.delayed(const Duration(milliseconds: 100));
if (mounted) { if (mounted) {
_key.currentState?.update(fit: fit, width: context.width(1), height: context.height(1)); _key.currentState?.update(
fit: fit, width: context.width(1), height: context.height(1));
} }
} }
@ -934,7 +1036,8 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
return Stack( return Stack(
children: [ children: [
Video( Video(
subtitleViewConfiguration: SubtitleViewConfiguration(visible: false, style: subtileTextStyle(ref)), subtitleViewConfiguration: SubtitleViewConfiguration(
visible: false, style: subtileTextStyle(ref)),
fit: fit, fit: fit,
key: _key, key: _key,
controls: (state) => _isDesktop controls: (state) => _isDesktop
@ -976,8 +1079,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
builder: (context, value, child) { builder: (context, value, child) {
if (_hasOpeningSkip || _hasEndingSkip) { if (_hasOpeningSkip || _hasEndingSkip) {
if (_hasOpeningSkip) { if (_hasOpeningSkip) {
if (_openingResult!.interval!.startTime!.ceil() <= value.inSeconds && if (_openingResult!.interval!.startTime!.ceil() <=
_openingResult!.interval!.endTime!.toInt() > value.inSeconds) { value.inSeconds &&
_openingResult!.interval!.endTime!.toInt() >
value.inSeconds) {
_showAniSkipOpeningButton.value = true; _showAniSkipOpeningButton.value = true;
_showAniSkipEndingButton.value = false; _showAniSkipEndingButton.value = false;
} else { } else {
@ -985,8 +1090,10 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} }
} }
if (_hasEndingSkip) { if (_hasEndingSkip) {
if (_endingResult!.interval!.startTime!.ceil() <= value.inSeconds && if (_endingResult!.interval!.startTime!.ceil() <=
_endingResult!.interval!.endTime!.toInt() > value.inSeconds) { value.inSeconds &&
_endingResult!.interval!.endTime!.toInt() >
value.inSeconds) {
_showAniSkipEndingButton.value = true; _showAniSkipEndingButton.value = true;
_showAniSkipOpeningButton.value = false; _showAniSkipOpeningButton.value = false;
} }
@ -995,9 +1102,12 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage> with Tick
} }
} }
return Consumer(builder: (context, ref, _) { return Consumer(builder: (context, ref, _) {
late final enableAniSkip = ref.watch(enableAniSkipStateProvider); late final enableAniSkip =
late final enableAutoSkip = ref.watch(enableAutoSkipStateProvider); ref.watch(enableAniSkipStateProvider);
late final aniSkipTimeoutLength = ref.watch(aniSkipTimeoutLengthStateProvider); late final enableAutoSkip =
ref.watch(enableAutoSkipStateProvider);
late final aniSkipTimeoutLength =
ref.watch(aniSkipTimeoutLengthStateProvider);
return ValueListenableBuilder( return ValueListenableBuilder(
valueListenable: _showAniSkipOpeningButton, valueListenable: _showAniSkipOpeningButton,
builder: (context, showAniSkipOpENINGButton, child) { builder: (context, showAniSkipOpENINGButton, child) {
@ -1055,11 +1165,13 @@ Widget seekIndicatorTextWidget(Duration duration, Duration currentPosition) {
children: [ children: [
Text( Text(
Duration(seconds: value).label(), Duration(seconds: value).label(),
style: const TextStyle(fontSize: 65.0, fontWeight: FontWeight.bold, color: Colors.white), style: const TextStyle(
fontSize: 65.0, fontWeight: FontWeight.bold, color: Colors.white),
), ),
Text( Text(
"[${swipeDuration > 0 ? "+${Duration(seconds: swipeDuration).label()}" : "-${Duration(seconds: swipeDuration).label()}"}]", "[${swipeDuration > 0 ? "+${Duration(seconds: swipeDuration).label()}" : "-${Duration(seconds: swipeDuration).label()}"}]",
style: const TextStyle(fontSize: 40.0, color: Colors.white, fontWeight: FontWeight.bold), style: const TextStyle(
fontSize: 40.0, color: Colors.white, fontWeight: FontWeight.bold),
), ),
], ],
); );
@ -1072,5 +1184,11 @@ class VideoPrefs {
AudioTrack? audio; AudioTrack? audio;
bool isLocal; bool isLocal;
final Map<String, String>? headers; final Map<String, String>? headers;
VideoPrefs({this.videoTrack, this.isLocal = true, this.headers, this.subtitle, this.audio, this.title}); VideoPrefs(
{this.videoTrack,
this.isLocal = true,
this.headers,
this.subtitle,
this.audio,
this.title});
} }

View file

@ -104,13 +104,17 @@ class AnimeStreamController extends _$AnimeStreamController {
} }
int getEpisodesLength(bool isInFilterList) { int getEpisodesLength(bool isInFilterList) {
return isInFilterList ? getAnime().getFilteredChapterList().length : getAnime().chapters.length; return isInFilterList
? getAnime().getFilteredChapterList().length
: getAnime().chapters.length;
} }
Duration geTCurrentPosition() { Duration geTCurrentPosition() {
if (incognitoMode) return Duration.zero; if (incognitoMode) return Duration.zero;
String position = episode.lastPageRead ?? "0"; String position = episode.lastPageRead ?? "0";
return Duration(milliseconds: episode.isRead! ? 0 : int.parse(position.isEmpty ? "0" : position)); return Duration(
milliseconds:
episode.isRead! ? 0 : int.parse(position.isEmpty ? "0" : position));
} }
void setAnimeHistoryUpdate() { void setAnimeHistoryUpdate() {
@ -122,7 +126,8 @@ class AnimeStreamController extends _$AnimeStreamController {
}); });
History? history; History? history;
final empty = isar.historys.filter().mangaIdEqualTo(getAnime().id).isEmptySync(); final empty =
isar.historys.filter().mangaIdEqualTo(getAnime().id).isEmptySync();
if (empty) { if (empty) {
history = History( history = History(
@ -132,7 +137,10 @@ class AnimeStreamController extends _$AnimeStreamController {
chapterId: episode.id) chapterId: episode.id)
..chapter.value = episode; ..chapter.value = episode;
} else { } else {
history = (isar.historys.filter().mangaIdEqualTo(getAnime().id).findFirstSync())! history = (isar.historys
.filter()
.mangaIdEqualTo(getAnime().id)
.findFirstSync())!
..chapterId = episode.id ..chapterId = episode.id
..chapter.value = episode ..chapter.value = episode
..date = DateTime.now().millisecondsSinceEpoch.toString(); ..date = DateTime.now().millisecondsSinceEpoch.toString();
@ -150,19 +158,25 @@ class AnimeStreamController extends _$AnimeStreamController {
} }
} }
void setCurrentPosition(Duration duration, Duration? totalDuration, {bool save = false}) { void setCurrentPosition(Duration duration, Duration? totalDuration,
{bool save = false}) {
if (episode.isRead!) return; if (episode.isRead!) return;
if (incognitoMode) return; if (incognitoMode) return;
final markEpisodeAsSeenType = ref.watch(markEpisodeAsSeenTypeStateProvider); final markEpisodeAsSeenType = ref.watch(markEpisodeAsSeenTypeStateProvider);
final isWatch = totalDuration != null && totalDuration != Duration.zero && duration != Duration.zero final isWatch = totalDuration != null &&
? duration.inSeconds >= ((totalDuration.inSeconds * markEpisodeAsSeenType) / 100).ceil() totalDuration != Duration.zero &&
duration != Duration.zero
? duration.inSeconds >=
((totalDuration.inSeconds * markEpisodeAsSeenType) / 100).ceil()
: false; : false;
if (isWatch || save) { if (isWatch || save) {
final ep = episode; final ep = episode;
isar.writeTxnSync(() { isar.writeTxnSync(() {
ep.isRead = isWatch; ep.isRead = isWatch;
ep.lastPageRead = (duration.inMilliseconds).toString(); ep.lastPageRead = (duration.inMilliseconds).toString();
ref.read(changedItemsManagerProvider(managerId: 1).notifier).addUpdatedChapter(ep, false, false); ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(ep, false, false);
isar.chapters.putSync(ep); isar.chapters.putSync(ep);
}); });
if (isWatch) { if (isWatch) {
@ -172,10 +186,18 @@ class AnimeStreamController extends _$AnimeStreamController {
} }
(int, int)? _getTrackId() { (int, int)? _getTrackId() {
final malId = final malId = isar.tracks
isar.tracks.filter().syncIdEqualTo(1).mangaIdEqualTo(episode.manga.value!.id!).findFirstSync()?.mediaId; .filter()
final aniId = .syncIdEqualTo(1)
isar.tracks.filter().syncIdEqualTo(2).mangaIdEqualTo(episode.manga.value!.id!).findFirstSync()?.mediaId; .mangaIdEqualTo(episode.manga.value!.id!)
.findFirstSync()
?.mediaId;
final aniId = isar.tracks
.filter()
.syncIdEqualTo(2)
.mangaIdEqualTo(episode.manga.value!.id!)
.findFirstSync()
?.mediaId;
return switch (malId) { return switch (malId) {
!= null => (malId, 1), != null => (malId, 1),
== null => switch (aniId) { != null => (aniId, 2), _ => null }, == null => switch (aniId) { != null => (aniId, 2), _ => null },
@ -183,14 +205,17 @@ class AnimeStreamController extends _$AnimeStreamController {
}; };
} }
Future<List<Results>?> getAniSkipResults(Function(List<Results>) result) async { Future<List<Results>?> getAniSkipResults(
Function(List<Results>) result) async {
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
if (ref.watch(enableAniSkipStateProvider)) { if (ref.watch(enableAniSkipStateProvider)) {
final id = _getTrackId(); final id = _getTrackId();
if (id != null) { if (id != null) {
final res = await ref final res = await ref.read(aniSkipProvider.notifier).getResult(
.read(aniSkipProvider.notifier) id,
.getResult(id, ChapterRecognition().parseChapterNumber(episode.manga.value!.name!, episode.name!), 0); ChapterRecognition()
.parseChapterNumber(episode.manga.value!.name!, episode.name!),
0);
result.call(res ?? []); result.call(res ?? []);
return res; return res;
} }

View file

@ -19,15 +19,21 @@ class SubtitleSettingsState extends _$SubtitleSettingsState {
final settings = isar.settings.getSync(227); final settings = isar.settings.getSync(227);
state = value; state = value;
if (end) { if (end) {
isar.writeTxnSync(() => isar.settings.putSync(settings!..playerSubtitleSettings = value)); isar.writeTxnSync(() =>
isar.settings.putSync(settings!..playerSubtitleSettings = value));
} }
} }
void resetColor() { void resetColor() {
final settings = isar.settings.getSync(227); final settings = isar.settings.getSync(227);
state = PlayerSubtitleSettings(fontSize: state.fontSize, useBold: state.useBold, useItalic: state.useItalic); state = PlayerSubtitleSettings(
fontSize: state.fontSize,
useBold: state.useBold,
useItalic: state.useItalic);
isar.writeTxnSync(() => isar.settings.putSync(settings! isar.writeTxnSync(() => isar.settings.putSync(settings!
..playerSubtitleSettings = ..playerSubtitleSettings = PlayerSubtitleSettings(
PlayerSubtitleSettings(fontSize: state.fontSize, useBold: state.useBold, useItalic: state.useItalic))); fontSize: state.fontSize,
useBold: state.useBold,
useItalic: state.useItalic)));
} }
} }

View file

@ -20,14 +20,18 @@ class AniSkipCountDownButton extends ConsumerStatefulWidget {
required this.timeoutLength}); required this.timeoutLength});
@override @override
ConsumerState<AniSkipCountDownButton> createState() => _AniSkipCountDownButtonState(); ConsumerState<AniSkipCountDownButton> createState() =>
_AniSkipCountDownButtonState();
} }
class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton> with TickerProviderStateMixin { class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton>
with TickerProviderStateMixin {
late AnimationController _controller; late AnimationController _controller;
@override @override
void initState() { void initState() {
_controller = AnimationController(vsync: this, duration: Duration(seconds: widget.timeoutLength))..forward(); _controller = AnimationController(
vsync: this, duration: Duration(seconds: widget.timeoutLength))
..forward();
super.initState(); super.initState();
if (widget.active) { if (widget.active) {
if (widget.autoSkip) { if (widget.autoSkip) {
@ -50,7 +54,8 @@ class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton>
_isCompleted = true; _isCompleted = true;
}); });
_controller.reset(); _controller.reset();
widget.player.seek(Duration(seconds: widget.aniSkipResult!.interval!.endTime!.ceil())); widget.player.seek(
Duration(seconds: widget.aniSkipResult!.interval!.endTime!.ceil()));
} }
bool _isCompleted = false; bool _isCompleted = false;
@ -72,7 +77,8 @@ class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton>
padding: const EdgeInsets.symmetric(horizontal: 40), padding: const EdgeInsets.symmetric(horizontal: 40),
child: MaterialButton( child: MaterialButton(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: () { onPressed: () {
_seekTo(); _seekTo();
}, },
@ -103,15 +109,21 @@ class _AniSkipCountDownButtonState extends ConsumerState<AniSkipCountDownButton>
), ),
Positioned.fill( Positioned.fill(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10), padding:
const EdgeInsets.symmetric(horizontal: 10),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [ children: [
Text( Text(
widget.skipTypeText.toUpperCase(), widget.skipTypeText.toUpperCase(),
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(
fontWeight: FontWeight.bold),
), ),
Text((widget.timeoutLength - (_controller.duration! * _controller.value).inSeconds) Text((widget.timeoutLength -
(_controller.duration! *
_controller.value)
.inSeconds)
.toString()), .toString()),
], ],
), ),

View file

@ -10,7 +10,12 @@ class CustomSeekBar extends StatefulWidget {
final Function(Duration)? onSeekStart; final Function(Duration)? onSeekStart;
final Function(Duration)? onSeekEnd; final Function(Duration)? onSeekEnd;
const CustomSeekBar({super.key, this.onSeekStart, this.onSeekEnd, required this.player, this.delta}); const CustomSeekBar(
{super.key,
this.onSeekStart,
this.onSeekEnd,
required this.player,
this.delta});
@override @override
CustomSeekBarState createState() => CustomSeekBarState(); CustomSeekBarState createState() => CustomSeekBarState();
@ -64,7 +69,8 @@ class CustomSeekBarState extends State<CustomSeekBar> {
width: 70, width: 70,
child: Center( child: Center(
child: Text( child: Text(
(widget.delta ?? tempPosition ?? position).label(reference: duration), (widget.delta ?? tempPosition ?? position)
.label(reference: duration),
style: const TextStyle( style: const TextStyle(
height: 1.0, height: 1.0,
fontSize: 12.0, fontSize: 12.0,
@ -79,10 +85,15 @@ class CustomSeekBarState extends State<CustomSeekBar> {
), ),
child: Slider( child: Slider(
max: max(duration.inMilliseconds.toDouble(), 0), max: max(duration.inMilliseconds.toDouble(), 0),
value: max((widget.delta ?? tempPosition ?? position).inMilliseconds.toDouble(), 0), value: max(
(widget.delta ?? tempPosition ?? position)
.inMilliseconds
.toDouble(),
0),
secondaryTrackValue: max(buffer.inMilliseconds.toDouble(), 0), secondaryTrackValue: max(buffer.inMilliseconds.toDouble(), 0),
onChanged: (value) { onChanged: (value) {
widget.onSeekStart?.call(Duration(milliseconds: value.toInt() - position.inMilliseconds)); widget.onSeekStart?.call(Duration(
milliseconds: value.toInt() - position.inMilliseconds));
if (mounted) { if (mounted) {
setState(() { setState(() {
tempPosition = Duration(milliseconds: value.toInt()); tempPosition = Duration(milliseconds: value.toInt());
@ -90,7 +101,8 @@ class CustomSeekBarState extends State<CustomSeekBar> {
} }
}, },
onChangeEnd: (value) async { onChangeEnd: (value) async {
widget.onSeekEnd?.call(Duration(milliseconds: value.toInt() - position.inMilliseconds)); widget.onSeekEnd?.call(Duration(
milliseconds: value.toInt() - position.inMilliseconds));
widget.player.seek(Duration(milliseconds: value.toInt())); widget.player.seek(Duration(milliseconds: value.toInt()));
}, },
), ),

View file

@ -32,7 +32,8 @@ class DesktopControllerWidget extends StatefulWidget {
required this.tempDuration}); required this.tempDuration});
@override @override
State<DesktopControllerWidget> createState() => _DesktopControllerWidgetState(); State<DesktopControllerWidget> createState() =>
_DesktopControllerWidgetState();
} }
class _DesktopControllerWidgetState extends State<DesktopControllerWidget> { class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
@ -151,26 +152,36 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
bindings: { bindings: {
// Default key-board shortcuts. // Default key-board shortcuts.
// https://support.google.com/youtube/answer/7631406 // https://support.google.com/youtube/answer/7631406
const SingleActivator(LogicalKeyboardKey.mediaPlay): () => widget.videoController.player.play(), const SingleActivator(LogicalKeyboardKey.mediaPlay): () =>
const SingleActivator(LogicalKeyboardKey.mediaPause): () => widget.videoController.player.pause(), widget.videoController.player.play(),
const SingleActivator(LogicalKeyboardKey.mediaPlayPause): () => widget.videoController.player.playOrPause(), const SingleActivator(LogicalKeyboardKey.mediaPause): () =>
const SingleActivator(LogicalKeyboardKey.mediaTrackNext): () => widget.videoController.player.next(), widget.videoController.player.pause(),
const SingleActivator(LogicalKeyboardKey.mediaTrackPrevious): () => widget.videoController.player.previous(), const SingleActivator(LogicalKeyboardKey.mediaPlayPause): () =>
const SingleActivator(LogicalKeyboardKey.space): () => widget.videoController.player.playOrPause(), widget.videoController.player.playOrPause(),
const SingleActivator(LogicalKeyboardKey.mediaTrackNext): () =>
widget.videoController.player.next(),
const SingleActivator(LogicalKeyboardKey.mediaTrackPrevious): () =>
widget.videoController.player.previous(),
const SingleActivator(LogicalKeyboardKey.space): () =>
widget.videoController.player.playOrPause(),
const SingleActivator(LogicalKeyboardKey.keyJ): () { const SingleActivator(LogicalKeyboardKey.keyJ): () {
final rate = widget.videoController.player.state.position - const Duration(seconds: 10); final rate = widget.videoController.player.state.position -
const Duration(seconds: 10);
widget.videoController.player.seek(rate); widget.videoController.player.seek(rate);
}, },
const SingleActivator(LogicalKeyboardKey.keyL): () { const SingleActivator(LogicalKeyboardKey.keyL): () {
final rate = widget.videoController.player.state.position + const Duration(seconds: 10); final rate = widget.videoController.player.state.position +
const Duration(seconds: 10);
widget.videoController.player.seek(rate); widget.videoController.player.seek(rate);
}, },
const SingleActivator(LogicalKeyboardKey.arrowLeft): () { const SingleActivator(LogicalKeyboardKey.arrowLeft): () {
final rate = widget.videoController.player.state.position - const Duration(seconds: 5); final rate = widget.videoController.player.state.position -
const Duration(seconds: 5);
widget.videoController.player.seek(rate); widget.videoController.player.seek(rate);
}, },
const SingleActivator(LogicalKeyboardKey.arrowRight): () { const SingleActivator(LogicalKeyboardKey.arrowRight): () {
final rate = widget.videoController.player.state.position + const Duration(seconds: 5); final rate = widget.videoController.player.state.position +
const Duration(seconds: 5);
widget.videoController.player.seek(rate); widget.videoController.player.seek(rate);
}, },
const SingleActivator(LogicalKeyboardKey.arrowUp): () { const SingleActivator(LogicalKeyboardKey.arrowUp): () {
@ -182,7 +193,8 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
widget.videoController.player.setVolume(volume.clamp(0.0, 100.0)); widget.videoController.player.setVolume(volume.clamp(0.0, 100.0));
}, },
const SingleActivator(LogicalKeyboardKey.keyF): () => setFullScreen(), const SingleActivator(LogicalKeyboardKey.keyF): () => setFullScreen(),
const SingleActivator(LogicalKeyboardKey.escape): () => setFullScreen(value: false), const SingleActivator(LogicalKeyboardKey.escape): () =>
setFullScreen(value: false),
}, },
child: Stack( child: Stack(
children: [ children: [
@ -192,7 +204,8 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
: Positioned( : Positioned(
child: CustomSubtitleView( child: CustomSubtitleView(
controller: widget.videoController, controller: widget.videoController,
configuration: SubtitleViewConfiguration(style: subtileTextStyle(ref)), configuration:
SubtitleViewConfiguration(style: subtileTextStyle(ref)),
)), )),
), ),
Focus( Focus(
@ -202,12 +215,16 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
? (e) { ? (e) {
if (e is PointerScrollEvent) { if (e is PointerScrollEvent) {
if (e.delta.dy > 0) { if (e.delta.dy > 0) {
final volume = widget.videoController.player.state.volume - 5.0; final volume =
widget.videoController.player.setVolume(volume.clamp(0.0, 100.0)); widget.videoController.player.state.volume - 5.0;
widget.videoController.player
.setVolume(volume.clamp(0.0, 100.0));
} }
if (e.delta.dy < 0) { if (e.delta.dy < 0) {
final volume = widget.videoController.player.state.volume + 5.0; final volume =
widget.videoController.player.setVolume(volume.clamp(0.0, 100.0)); widget.videoController.player.state.volume + 5.0;
widget.videoController.player
.setVolume(volume.clamp(0.0, 100.0));
} }
} }
} }
@ -226,12 +243,16 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
onPanUpdate: modifyVolumeOnScroll onPanUpdate: modifyVolumeOnScroll
? (e) { ? (e) {
if (e.delta.dy > 0) { if (e.delta.dy > 0) {
final volume = widget.videoController.player.state.volume - 5.0; final volume =
widget.videoController.player.setVolume(volume.clamp(0.0, 100.0)); widget.videoController.player.state.volume - 5.0;
widget.videoController.player
.setVolume(volume.clamp(0.0, 100.0));
} }
if (e.delta.dy < 0) { if (e.delta.dy < 0) {
final volume = widget.videoController.player.state.volume + 5.0; final volume =
widget.videoController.player.setVolume(volume.clamp(0.0, 100.0)); widget.videoController.player.state.volume + 5.0;
widget.videoController.player
.setVolume(volume.clamp(0.0, 100.0));
} }
} }
: null, : null,
@ -239,7 +260,9 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
onHover: (_) => onHover(), onHover: (_) => onHover(),
onEnter: (_) => onEnter(), onEnter: (_) => onEnter(),
onExit: (_) => onExit(), onExit: (_) => onExit(),
cursor: cursorVisible ? SystemMouseCursors.basic : SystemMouseCursors.none, cursor: cursorVisible
? SystemMouseCursors.basic
: SystemMouseCursors.none,
child: Stack( child: Stack(
children: [ children: [
AnimatedOpacity( AnimatedOpacity(
@ -297,7 +320,9 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
Padding( Padding(
padding: ( padding: (
// Add padding in fullscreen! // Add padding in fullscreen!
isFullscreen(context) ? MediaQuery.of(context).padding : EdgeInsets.zero), isFullscreen(context)
? MediaQuery.of(context).padding
: EdgeInsets.zero),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
@ -315,20 +340,29 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
: 1.0, : 1.0,
duration: controlsTransitionDuration, duration: controlsTransitionDuration,
child: Center( child: Center(
child: seekIndicatorTextWidget(Duration(seconds: swipeDuration), child: seekIndicatorTextWidget(
widget.videoController.player.state.position))), Duration(
seconds: swipeDuration),
widget.videoController.player
.state.position))),
), ),
widget.seekToWidget, widget.seekToWidget,
Transform.translate( Transform.translate(
offset: Offset.zero, offset: Offset.zero,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5), padding: const EdgeInsets.symmetric(
horizontal: 5),
child: CustomSeekBar( child: CustomSeekBar(
onSeekStart: (value) { onSeekStart: (value) {
setState(() { setState(() {
swipeDuration = value.inSeconds; swipeDuration = value.inSeconds;
showSwipeDuration = true; showSwipeDuration = true;
widget.tempDuration(widget.videoController.player.state.position + value); widget.tempDuration(widget
.videoController
.player
.state
.position +
value);
}); });
_timer?.cancel(); _timer?.cancel();
}, },
@ -364,7 +398,9 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
child: Padding( child: Padding(
padding: ( padding: (
// Add padding in fullscreen! // Add padding in fullscreen!
isFullscreen(context) ? MediaQuery.of(context).padding : EdgeInsets.zero), isFullscreen(context)
? MediaQuery.of(context).padding
: EdgeInsets.zero),
child: Column( child: Column(
children: [ children: [
Container( Container(
@ -430,10 +466,12 @@ class CustomeMaterialDesktopPlayOrPauseButton extends StatefulWidget {
}); });
@override @override
CustomeMaterialDesktopPlayOrPauseButtonState createState() => CustomeMaterialDesktopPlayOrPauseButtonState(); CustomeMaterialDesktopPlayOrPauseButtonState createState() =>
CustomeMaterialDesktopPlayOrPauseButtonState();
} }
class CustomeMaterialDesktopPlayOrPauseButtonState extends State<CustomeMaterialDesktopPlayOrPauseButton> class CustomeMaterialDesktopPlayOrPauseButtonState
extends State<CustomeMaterialDesktopPlayOrPauseButton>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late final animation = AnimationController( late final animation = AnimationController(
vsync: this, vsync: this,
@ -497,10 +535,12 @@ class CustomMaterialDesktopVolumeButton extends StatefulWidget {
}); });
@override @override
CustomMaterialDesktopVolumeButtonState createState() => CustomMaterialDesktopVolumeButtonState(); CustomMaterialDesktopVolumeButtonState createState() =>
CustomMaterialDesktopVolumeButtonState();
} }
class CustomMaterialDesktopVolumeButtonState extends State<CustomMaterialDesktopVolumeButton> class CustomMaterialDesktopVolumeButtonState
extends State<CustomMaterialDesktopVolumeButton>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late double volume = widget.controller.player.state.volume; late double volume = widget.controller.player.state.volume;
@ -663,13 +703,16 @@ class CustomMaterialDesktopPositionIndicator extends StatefulWidget {
final VideoController controller; final VideoController controller;
final Duration? delta; final Duration? delta;
const CustomMaterialDesktopPositionIndicator({super.key, required this.controller, this.delta}); const CustomMaterialDesktopPositionIndicator(
{super.key, required this.controller, this.delta});
@override @override
CustomMaterialDesktopPositionIndicatorState createState() => CustomMaterialDesktopPositionIndicatorState(); CustomMaterialDesktopPositionIndicatorState createState() =>
CustomMaterialDesktopPositionIndicatorState();
} }
class CustomMaterialDesktopPositionIndicatorState extends State<CustomMaterialDesktopPositionIndicator> { class CustomMaterialDesktopPositionIndicatorState
extends State<CustomMaterialDesktopPositionIndicator> {
late Duration position = widget.controller.player.state.position; late Duration position = widget.controller.player.state.position;
late Duration duration = widget.controller.player.state.duration; late Duration duration = widget.controller.player.state.duration;
@ -755,10 +798,12 @@ class CustomMaterialDesktopFullscreenButton extends StatefulWidget {
}); });
@override @override
State<CustomMaterialDesktopFullscreenButton> createState() => _CustomMaterialDesktopFullscreenButtonState(); State<CustomMaterialDesktopFullscreenButton> createState() =>
_CustomMaterialDesktopFullscreenButtonState();
} }
class _CustomMaterialDesktopFullscreenButtonState extends State<CustomMaterialDesktopFullscreenButton> { class _CustomMaterialDesktopFullscreenButtonState
extends State<CustomMaterialDesktopFullscreenButton> {
bool _isFullscreen = false; bool _isFullscreen = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -769,7 +814,9 @@ class _CustomMaterialDesktopFullscreenButtonState extends State<CustomMaterialDe
_isFullscreen = isFullScreen; _isFullscreen = isFullScreen;
}); });
}, },
icon: _isFullscreen ? const Icon(Icons.fullscreen_exit) : const Icon(Icons.fullscreen), icon: _isFullscreen
? const Icon(Icons.fullscreen_exit)
: const Icon(Icons.fullscreen),
iconSize: 25, iconSize: 25,
color: Colors.white, color: Colors.white,
); );

View file

@ -3,7 +3,8 @@ import 'package:flutter/material.dart';
class MediaIndicatorBuilder extends StatelessWidget { class MediaIndicatorBuilder extends StatelessWidget {
final bool isVolumeIndicator; final bool isVolumeIndicator;
final ValueNotifier<double> value; final ValueNotifier<double> value;
const MediaIndicatorBuilder({super.key, required this.value, required this.isVolumeIndicator}); const MediaIndicatorBuilder(
{super.key, required this.value, required this.isVolumeIndicator});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -12,7 +13,9 @@ class MediaIndicatorBuilder extends StatelessWidget {
builder: (context, value, child) => Padding( builder: (context, value, child) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 40), padding: const EdgeInsets.symmetric(horizontal: 40),
child: Row( child: Row(
mainAxisAlignment: isVolumeIndicator ? MainAxisAlignment.start : MainAxisAlignment.end, mainAxisAlignment: isVolumeIndicator
? MainAxisAlignment.start
: MainAxisAlignment.end,
children: [ children: [
Container( Container(
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
@ -42,8 +45,9 @@ class MediaIndicatorBuilder extends StatelessWidget {
), ),
child: SizedBox.fromSize( child: SizedBox.fromSize(
size: const Size(130, 20), size: const Size(130, 20),
child: child: LinearProgressIndicator(
LinearProgressIndicator(value: value, backgroundColor: Colors.transparent)), value: value,
backgroundColor: Colors.transparent)),
), ),
), ),
), ),

View file

@ -30,16 +30,19 @@ class MobileControllerWidget extends ConsumerStatefulWidget {
required this.videoStatekey}); required this.videoStatekey});
@override @override
ConsumerState<MobileControllerWidget> createState() => _MobileControllerWidgetState(); ConsumerState<MobileControllerWidget> createState() =>
_MobileControllerWidgetState();
} }
class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget> { class _MobileControllerWidgetState
extends ConsumerState<MobileControllerWidget> {
bool mount = true; bool mount = true;
bool visible = true; bool visible = true;
Duration controlsTransitionDuration = const Duration(milliseconds: 300); Duration controlsTransitionDuration = const Duration(milliseconds: 300);
Color backdropColor = const Color(0x66000000); Color backdropColor = const Color(0x66000000);
Timer? _timer; Timer? _timer;
late final skipDuration = ref.watch(defaultDoubleTapToSkipLengthStateProvider); late final skipDuration =
ref.watch(defaultDoubleTapToSkipLengthStateProvider);
final ValueNotifier<double> _brightnessValue = ValueNotifier(0.0); final ValueNotifier<double> _brightnessValue = ValueNotifier(0.0);
final ValueNotifier<bool> _brightnessIndicator = ValueNotifier(false); final ValueNotifier<bool> _brightnessIndicator = ValueNotifier(false);
Timer? _brightnessTimer; Timer? _brightnessTimer;
@ -50,7 +53,8 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
// The default event stream in package:volume_controller is buggy. // The default event stream in package:volume_controller is buggy.
bool _volumeInterceptEventStream = false; bool _volumeInterceptEventStream = false;
Offset _dragInitialDelta = Offset.zero; // Initial position for horizontal drag Offset _dragInitialDelta =
Offset.zero; // Initial position for horizontal drag
int swipeDuration = 0; // Duration to seek in video int swipeDuration = 0; // Duration to seek in video
bool showSwipeDuration = false; // Whether to show the seek duration overlay bool showSwipeDuration = false; // Whether to show the seek duration overlay
@ -188,15 +192,17 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
setState(() { setState(() {
swipeDuration = seconds; swipeDuration = seconds;
showSwipeDuration = true; showSwipeDuration = true;
_seekBarDeltaValueNotifier = _seekBarDeltaValueNotifier = Duration(
Duration(seconds: widget.videoController.player.state.position.inSeconds + seconds); seconds: widget.videoController.player.state.position.inSeconds +
seconds);
}); });
} }
} }
void onHorizontalDragEnd() { void onHorizontalDragEnd() {
if (swipeDuration != 0) { if (swipeDuration != 0) {
Duration newPosition = widget.videoController.player.state.position + Duration(seconds: swipeDuration); Duration newPosition = widget.videoController.player.state.position +
Duration(seconds: swipeDuration);
newPosition = newPosition.clamp( newPosition = newPosition.clamp(
Duration.zero, Duration.zero,
widget.videoController.player.state.duration, widget.videoController.player.state.duration,
@ -233,7 +239,8 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
Future.microtask(() async { Future.microtask(() async {
try { try {
_brightnessValue.value = await ScreenBrightness.instance.application; _brightnessValue.value = await ScreenBrightness.instance.application;
ScreenBrightness.instance.onApplicationScreenBrightnessChanged.listen((value) { ScreenBrightness.instance.onApplicationScreenBrightnessChanged
.listen((value) {
if (mounted) { if (mounted) {
_brightnessValue.value = value; _brightnessValue.value = value;
} }
@ -288,7 +295,8 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
: Positioned( : Positioned(
child: CustomSubtitleView( child: CustomSubtitleView(
controller: widget.videoController, controller: widget.videoController,
configuration: SubtitleViewConfiguration(style: subtileTextStyle(ref)), configuration:
SubtitleViewConfiguration(style: subtileTextStyle(ref)),
)), )),
), ),
Focus( Focus(
@ -329,7 +337,9 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
onTap: onTap, onTap: onTap,
onDoubleTapDown: _handleTapDown, onDoubleTapDown: _handleTapDown,
onDoubleTap: () { onDoubleTap: () {
if (_tapPosition != null && _tapPosition!.dx > MediaQuery.of(context).size.width / 2) { if (_tapPosition != null &&
_tapPosition!.dx >
MediaQuery.of(context).size.width / 2) {
onDoubleTapSeekForward(); onDoubleTapSeekForward();
} else { } else {
onDoubleTapSeekBackward(); onDoubleTapSeekBackward();
@ -345,16 +355,19 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
final delta = e.delta.dy; final delta = e.delta.dy;
final Offset position = e.localPosition; final Offset position = e.localPosition;
if (position.dx <= MediaQuery.of(context).size.width / 2) { if (position.dx <=
MediaQuery.of(context).size.width / 2) {
// Left side of screen swiped // Left side of screen swiped
final brightness = _brightnessValue.value - delta / verticalGestureSensitivity; final brightness = _brightnessValue.value -
delta / verticalGestureSensitivity;
final result = brightness.clamp(0.0, 1.0); final result = brightness.clamp(0.0, 1.0);
setBrightness(result); setBrightness(result);
} else { } else {
// Right side of screen swiped // Right side of screen swiped
final volume = _volumeValue.value - delta / verticalGestureSensitivity; final volume = _volumeValue.value -
delta / verticalGestureSensitivity;
final result = volume.clamp(0.0, 1.0); final result = volume.clamp(0.0, 1.0);
setVolume(result); setVolume(result);
} }
@ -368,7 +381,9 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
Padding( Padding(
padding: ( padding: (
// Add padding in fullscreen! // Add padding in fullscreen!
isFullscreen(context) ? MediaQuery.of(context).padding : EdgeInsets.zero), isFullscreen(context)
? MediaQuery.of(context).padding
: EdgeInsets.zero),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
@ -387,8 +402,11 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
duration: controlsTransitionDuration, duration: controlsTransitionDuration,
child: Center( child: Center(
child: Row( child: Row(
children: mobilePrimaryButtonBar(context, widget.videoStatekey, children: mobilePrimaryButtonBar(
widget.streamController, widget.videoController)), context,
widget.videoStatekey,
widget.streamController,
widget.videoController)),
), ),
), ),
), ),
@ -434,7 +452,9 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
), ),
// // Double-Tap Seek Seek-Bar: // // Double-Tap Seek Seek-Bar:
if (!mount) if (!mount)
if (_mountSeekBackwardButton || _mountSeekForwardButton || showSwipeDuration) if (_mountSeekBackwardButton ||
_mountSeekForwardButton ||
showSwipeDuration)
Column( Column(
children: [ children: [
const Spacer(), const Spacer(),
@ -443,8 +463,9 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10),
child: child: CustomSeekBar(
CustomSeekBar(delta: _seekBarDeltaValueNotifier, player: widget.videoController.player), delta: _seekBarDeltaValueNotifier,
player: widget.videoController.player),
), ),
], ],
), ),
@ -455,7 +476,9 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
child: Padding( child: Padding(
padding: ( padding: (
// Add padding in fullscreen! // Add padding in fullscreen!
isFullscreen(context) ? MediaQuery.of(context).padding : EdgeInsets.zero), isFullscreen(context)
? MediaQuery.of(context).padding
: EdgeInsets.zero),
child: Column( child: Column(
children: [ children: [
Container( Container(
@ -503,7 +526,8 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
curve: Curves.easeInOut, curve: Curves.easeInOut,
opacity: value ? 1.0 : 0.0, opacity: value ? 1.0 : 0.0,
duration: controlsTransitionDuration, duration: controlsTransitionDuration,
child: MediaIndicatorBuilder(value: _volumeValue, isVolumeIndicator: true)), child: MediaIndicatorBuilder(
value: _volumeValue, isVolumeIndicator: true)),
), ),
), ),
// // Brightness Indicator. // // Brightness Indicator.
@ -514,7 +538,8 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
curve: Curves.easeInOut, curve: Curves.easeInOut,
opacity: value ? 1.0 : 0.0, opacity: value ? 1.0 : 0.0,
duration: controlsTransitionDuration, duration: controlsTransitionDuration,
child: MediaIndicatorBuilder(value: _brightnessValue, isVolumeIndicator: false)), child: MediaIndicatorBuilder(
value: _brightnessValue, isVolumeIndicator: false)),
), ),
), ),
// Seek Indicator. // Seek Indicator.
@ -523,7 +548,8 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
duration: controlsTransitionDuration, duration: controlsTransitionDuration,
opacity: showSwipeDuration ? 1 : 0, opacity: showSwipeDuration ? 1 : 0,
child: seekIndicatorTextWidget( child: seekIndicatorTextWidget(
Duration(seconds: swipeDuration), widget.videoController.player.state.position)), Duration(seconds: swipeDuration),
widget.videoController.player.state.position)),
), ),
// Double-Tap Seek Button(s): // Double-Tap Seek Button(s):
@ -554,20 +580,28 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
child: _BackwardSeekIndicator( child: _BackwardSeekIndicator(
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
_seekBarDeltaValueNotifier = _seekBarDeltaValueNotifier = widget
widget.videoController.player.state.position - value; .videoController
.player
.state
.position -
value;
}); });
}, },
onSubmitted: (value) { onSubmitted: (value) {
setState(() { setState(() {
_hideSeekBackwardButton = true; _hideSeekBackwardButton = true;
}); });
var result = widget.videoController.player.state.position - value; var result = widget.videoController.player
.state.position -
value;
result = result.clamp( result = result.clamp(
Duration.zero, Duration.zero,
widget.videoController.player.state.duration, widget.videoController.player.state
.duration,
); );
widget.videoController.player.seek(result); widget.videoController.player
.seek(result);
}, },
skipDuration: skipDuration), skipDuration: skipDuration),
) )
@ -596,20 +630,28 @@ class _MobileControllerWidgetState extends ConsumerState<MobileControllerWidget>
child: _ForwardSeekIndicator( child: _ForwardSeekIndicator(
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
_seekBarDeltaValueNotifier = _seekBarDeltaValueNotifier = widget
widget.videoController.player.state.position + value; .videoController
.player
.state
.position +
value;
}); });
}, },
onSubmitted: (value) { onSubmitted: (value) {
setState(() { setState(() {
_hideSeekForwardButton = true; _hideSeekForwardButton = true;
}); });
var result = widget.videoController.player.state.position + value; var result = widget.videoController.player
.state.position +
value;
result = result.clamp( result = result.clamp(
Duration.zero, Duration.zero,
widget.videoController.player.state.duration, widget.videoController.player.state
.duration,
); );
widget.videoController.player.seek(result); widget.videoController.player
.seek(result);
}, },
skipDuration: skipDuration), skipDuration: skipDuration),
) )
@ -814,10 +856,12 @@ class CustomMaterialPlayOrPauseButton extends StatefulWidget {
}); });
@override @override
CustomMaterialPlayOrPauseButtonState createState() => CustomMaterialPlayOrPauseButtonState(); CustomMaterialPlayOrPauseButtonState createState() =>
CustomMaterialPlayOrPauseButtonState();
} }
class CustomMaterialPlayOrPauseButtonState extends State<CustomMaterialPlayOrPauseButton> class CustomMaterialPlayOrPauseButtonState
extends State<CustomMaterialPlayOrPauseButton>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late final animation = AnimationController( late final animation = AnimationController(
vsync: this, vsync: this,
@ -871,8 +915,11 @@ class CustomMaterialPlayOrPauseButtonState extends State<CustomMaterialPlayOrPau
} }
} }
List<Widget> mobilePrimaryButtonBar(BuildContext context, GlobalKey<VideoState> key, List<Widget> mobilePrimaryButtonBar(
AnimeStreamController streamController, VideoController controller) { BuildContext context,
GlobalKey<VideoState> key,
AnimeStreamController streamController,
VideoController controller) {
bool hasPrevEpisode = streamController.getEpisodeIndex().$1 + 1 != bool hasPrevEpisode = streamController.getEpisodeIndex().$1 + 1 !=
streamController.getEpisodesLength(streamController.getEpisodeIndex().$2); streamController.getEpisodesLength(streamController.getEpisodeIndex().$2);
bool hasNextEpisode = streamController.getEpisodeIndex().$1 != 0; bool hasNextEpisode = streamController.getEpisodeIndex().$1 != 0;
@ -885,7 +932,8 @@ List<Widget> mobilePrimaryButtonBar(BuildContext context, GlobalKey<VideoState>
if (isFullScreen) { if (isFullScreen) {
key.currentState?.exitFullscreen(); key.currentState?.exitFullscreen();
} }
pushReplacementMangaReaderView(context: context, chapter: streamController.getPrevEpisode()); pushReplacementMangaReaderView(
context: context, chapter: streamController.getPrevEpisode());
} }
: null, : null,
icon: Icon( icon: Icon(
@ -909,7 +957,8 @@ List<Widget> mobilePrimaryButtonBar(BuildContext context, GlobalKey<VideoState>
); );
} }
: null, : null,
icon: Icon(Icons.skip_next, size: 35, color: hasPrevEpisode ? Colors.white : Colors.grey), icon: Icon(Icons.skip_next,
size: 35, color: hasPrevEpisode ? Colors.white : Colors.grey),
), ),
const Spacer(flex: 3) const Spacer(flex: 3)
]; ];

View file

@ -43,9 +43,9 @@ class _FontSettingWidgetState extends ConsumerState<FontSettingWidget> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
iconButton(Icons.remove, () { iconButton(Icons.remove, () {
ref ref.read(subtitleSettingsStateProvider.notifier).set(
.read(subtitleSettingsStateProvider.notifier) subtitleSettings..fontSize = subtitleSettings.fontSize! - 1,
.set(subtitleSettings..fontSize = subtitleSettings.fontSize! - 1, true); true);
setState(() {}); setState(() {});
}, },
backgroundColor: context.dynamicWhiteBlackColor, backgroundColor: context.dynamicWhiteBlackColor,
@ -54,12 +54,15 @@ class _FontSettingWidgetState extends ConsumerState<FontSettingWidget> {
SizedBox( SizedBox(
width: 200, width: 200,
child: TextFormField( child: TextFormField(
controller: TextEditingController(text: subtitleSettings.fontSize.toString()), controller: TextEditingController(
text: subtitleSettings.fontSize.toString()),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
onChanged: (v) { onChanged: (v) {
final val = int.tryParse(v); final val = int.tryParse(v);
if (val != null) { if (val != null) {
ref.read(subtitleSettingsStateProvider.notifier).set(subtitleSettings..fontSize = val, true); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subtitleSettings..fontSize = val, true);
} }
}, },
decoration: InputDecoration( decoration: InputDecoration(
@ -67,40 +70,51 @@ class _FontSettingWidgetState extends ConsumerState<FontSettingWidget> {
isDense: true, isDense: true,
filled: true, filled: true,
fillColor: Colors.transparent, fillColor: Colors.transparent,
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor)), enabledBorder: OutlineInputBorder(
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor)), borderSide:
border: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor))), BorderSide(color: context.dynamicThemeColor)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: context.dynamicThemeColor)),
border: OutlineInputBorder(
borderSide:
BorderSide(color: context.dynamicThemeColor))),
), ),
), ),
iconButton(Icons.add, () { iconButton(Icons.add, () {
ref ref.read(subtitleSettingsStateProvider.notifier).set(
.read(subtitleSettingsStateProvider.notifier) subtitleSettings..fontSize = subtitleSettings.fontSize! + 1,
.set(subtitleSettings..fontSize = subtitleSettings.fontSize! + 1, true); true);
setState(() {}); setState(() {});
}, },
backgroundColor: context.dynamicWhiteBlackColor, backgroundColor: context.dynamicWhiteBlackColor,
iconColors: context.isLight ? Colors.white : Colors.black, iconColors: context.isLight ? Colors.white : Colors.black,
size: 25), size: 25),
iconButton(Icons.format_bold, () { iconButton(Icons.format_bold, () {
ref ref.read(subtitleSettingsStateProvider.notifier).set(
.read(subtitleSettingsStateProvider.notifier) subtitleSettings..useBold = !subtitleSettings.useBold!,
.set(subtitleSettings..useBold = !subtitleSettings.useBold!, true); true);
setState(() {});
}, iconColors: subtitleSettings.useBold! ? null : context.dynamicWhiteBlackColor.withValues(alpha: 0.5)),
iconButton(Icons.format_italic, () {
ref
.read(subtitleSettingsStateProvider.notifier)
.set(subtitleSettings..useItalic = !subtitleSettings.useItalic!, true);
setState(() {}); setState(() {});
}, },
iconColors: iconColors: subtitleSettings.useBold!
subtitleSettings.useItalic! ? null : context.dynamicWhiteBlackColor.withValues(alpha: 0.5)), ? null
: context.dynamicWhiteBlackColor.withValues(alpha: 0.5)),
iconButton(Icons.format_italic, () {
ref.read(subtitleSettingsStateProvider.notifier).set(
subtitleSettings..useItalic = !subtitleSettings.useItalic!,
true);
setState(() {});
},
iconColors: subtitleSettings.useItalic!
? null
: context.dynamicWhiteBlackColor.withValues(alpha: 0.5)),
], ],
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text("Lorem ipsum dolor sit amet", child: Text("Lorem ipsum dolor sit amet",
style: subtileTextStyle(ref).copyWith(fontSize: 22), textAlign: TextAlign.center), style: subtileTextStyle(ref).copyWith(fontSize: 22),
textAlign: TextAlign.center),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
@ -154,7 +168,8 @@ class _ColorSettingWidgetState extends ConsumerState<ColorSettingWidget> {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
color: color, color: color,
border: Border.all(width: 2, color: context.dynamicWhiteBlackColor)), border: Border.all(
width: 2, color: context.dynamicWhiteBlackColor)),
), ),
), ),
Text("#${color.hexCode}", style: TextStyle(color: context.textColor)), Text("#${color.hexCode}", style: TextStyle(color: context.textColor)),
@ -170,12 +185,15 @@ class _ColorSettingWidgetState extends ConsumerState<ColorSettingWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final subSets = ref.watch(subtitleSettingsStateProvider); final subSets = ref.watch(subtitleSettingsStateProvider);
final textColor = final textColor = Color.fromARGB(subSets.textColorA!, subSets.textColorR!,
Color.fromARGB(subSets.textColorA!, subSets.textColorR!, subSets.textColorG!, subSets.textColorB!); subSets.textColorG!, subSets.textColorB!);
final borderColor = final borderColor = Color.fromARGB(subSets.borderColorA!,
Color.fromARGB(subSets.borderColorA!, subSets.borderColorR!, subSets.borderColorG!, subSets.borderColorB!); subSets.borderColorR!, subSets.borderColorG!, subSets.borderColorB!);
final backgroundColor = Color.fromARGB( final backgroundColor = Color.fromARGB(
subSets.backgroundColorA!, subSets.backgroundColorR!, subSets.backgroundColorG!, subSets.backgroundColorB!); subSets.backgroundColorA!,
subSets.backgroundColorR!,
subSets.backgroundColorG!,
subSets.backgroundColorB!);
return Padding( return Padding(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
child: Column( child: Column(
@ -198,45 +216,72 @@ class _ColorSettingWidgetState extends ConsumerState<ColorSettingWidget> {
), ),
Row( Row(
children: [ children: [
Expanded(flex: 3, child: button(context.l10n.text, "text", textColor)), Expanded(
Expanded(flex: 3, child: button(context.l10n.border, "border", borderColor)), flex: 3, child: button(context.l10n.text, "text", textColor)),
Expanded(flex: 3, child: button(context.l10n.background, "backgroud", backgroundColor)), Expanded(
flex: 3,
child: button(context.l10n.border, "border", borderColor)),
Expanded(
flex: 3,
child: button(
context.l10n.background, "backgroud", backgroundColor)),
], ],
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text("Lorem ipsum dolor sit amet", child: Text("Lorem ipsum dolor sit amet",
style: subtileTextStyle(ref).copyWith(fontSize: 22), textAlign: TextAlign.center), style: subtileTextStyle(ref).copyWith(fontSize: 22),
textAlign: TextAlign.center),
), ),
if (selector == "text") ...[ if (selector == "text") ...[
rgbaFilterWidget(subSets.textColorA!, subSets.textColorR!, subSets.textColorG!, subSets.textColorB!, (val) { rgbaFilterWidget(subSets.textColorA!, subSets.textColorR!,
subSets.textColorG!, subSets.textColorB!, (val) {
if (val.$3 == "r") { if (val.$3 == "r") {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..textColorR = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..textColorR = val.$1.toInt(), val.$2);
} else if (val.$3 == "g") { } else if (val.$3 == "g") {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..textColorG = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..textColorG = val.$1.toInt(), val.$2);
} else if (val.$3 == "b") { } else if (val.$3 == "b") {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..textColorB = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..textColorB = val.$1.toInt(), val.$2);
} else { } else {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..textColorA = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..textColorA = val.$1.toInt(), val.$2);
} }
setState(() {}); setState(() {});
}, context), }, context),
] else if (selector == "border") ...[ ] else if (selector == "border") ...[
rgbaFilterWidget(subSets.borderColorA!, subSets.borderColorR!, subSets.borderColorG!, subSets.borderColorB!, rgbaFilterWidget(subSets.borderColorA!, subSets.borderColorR!,
(val) { subSets.borderColorG!, subSets.borderColorB!, (val) {
if (val.$3 == "r") { if (val.$3 == "r") {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..borderColorR = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..borderColorR = val.$1.toInt(), val.$2);
} else if (val.$3 == "g") { } else if (val.$3 == "g") {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..borderColorG = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..borderColorG = val.$1.toInt(), val.$2);
} else if (val.$3 == "b") { } else if (val.$3 == "b") {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..borderColorB = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..borderColorB = val.$1.toInt(), val.$2);
} else { } else {
ref.read(subtitleSettingsStateProvider.notifier).set(subSets..borderColorA = val.$1.toInt(), val.$2); ref
.read(subtitleSettingsStateProvider.notifier)
.set(subSets..borderColorA = val.$1.toInt(), val.$2);
} }
setState(() {}); setState(() {});
}, context), }, context),
] else ...[ ] else ...[
rgbaFilterWidget(subSets.backgroundColorA!, subSets.backgroundColorR!, subSets.backgroundColorG!, rgbaFilterWidget(
subSets.backgroundColorA!,
subSets.backgroundColorR!,
subSets.backgroundColorG!,
subSets.backgroundColorB!, (val) { subSets.backgroundColorB!, (val) {
if (val.$3 == "r") { if (val.$3 == "r") {
ref ref
@ -279,7 +324,8 @@ Widget iconButton(IconData icon, void Function()? onPressed,
width: size, width: size,
child: IconButton( child: IconButton(
iconSize: size * 0.9, iconSize: size * 0.9,
style: ButtonStyle(backgroundColor: WidgetStatePropertyAll(backgroundColor)), style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll(backgroundColor)),
padding: const EdgeInsets.all(1), padding: const EdgeInsets.all(1),
onPressed: onPressed, onPressed: onPressed,
icon: Icon(icon, color: iconColors)), icon: Icon(icon, color: iconColors)),

View file

@ -77,10 +77,12 @@ class _CustomSubtitleViewState extends ConsumerState<CustomSubtitleView> {
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
final nr = (constraints.maxWidth * constraints.maxHeight); final nr = (constraints.maxWidth * constraints.maxHeight);
const dr = kTextScaleFactorReferenceWidth * kTextScaleFactorReferenceHeight; const dr =
kTextScaleFactorReferenceWidth * kTextScaleFactorReferenceHeight;
final textScaleFactor = sqrt((nr / dr).clamp(0.0, 1.0)); final textScaleFactor = sqrt((nr / dr).clamp(0.0, 1.0));
final textScaler = widget.configuration.textScaler ?? TextScaler.linear(textScaleFactor); final textScaler = widget.configuration.textScaler ??
TextScaler.linear(textScaleFactor);
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
child: AnimatedContainer( child: AnimatedContainer(
@ -105,19 +107,35 @@ class _CustomSubtitleViewState extends ConsumerState<CustomSubtitleView> {
TextStyle subtileTextStyle(WidgetRef ref) { TextStyle subtileTextStyle(WidgetRef ref) {
final subSets = ref.watch(subtitleSettingsStateProvider); final subSets = ref.watch(subtitleSettingsStateProvider);
final borderColor = final borderColor = Color.fromARGB(subSets.borderColorA!,
Color.fromARGB(subSets.borderColorA!, subSets.borderColorR!, subSets.borderColorG!, subSets.borderColorB!); subSets.borderColorR!, subSets.borderColorG!, subSets.borderColorB!);
return TextStyle( return TextStyle(
fontSize: subSets.fontSize!.toDouble(), fontSize: subSets.fontSize!.toDouble(),
fontWeight: subSets.useBold! ? FontWeight.bold : null, fontWeight: subSets.useBold! ? FontWeight.bold : null,
fontStyle: subSets.useItalic! ? FontStyle.italic : null, fontStyle: subSets.useItalic! ? FontStyle.italic : null,
color: Color.fromARGB(subSets.textColorA!, subSets.textColorR!, subSets.textColorG!, subSets.textColorB!), color: Color.fromARGB(subSets.textColorA!, subSets.textColorR!,
subSets.textColorG!, subSets.textColorB!),
shadows: [ shadows: [
Shadow(offset: const Offset(-1.5, -1.5), color: borderColor, blurRadius: 1.4), Shadow(
Shadow(offset: const Offset(1.5, -1.5), color: borderColor, blurRadius: 1.4), offset: const Offset(-1.5, -1.5),
Shadow(offset: const Offset(1.5, 1.5), color: borderColor, blurRadius: 1.4), color: borderColor,
Shadow(offset: const Offset(-1.5, 1.5), color: borderColor, blurRadius: 1.4) blurRadius: 1.4),
Shadow(
offset: const Offset(1.5, -1.5),
color: borderColor,
blurRadius: 1.4),
Shadow(
offset: const Offset(1.5, 1.5),
color: borderColor,
blurRadius: 1.4),
Shadow(
offset: const Offset(-1.5, 1.5),
color: borderColor,
blurRadius: 1.4)
], ],
backgroundColor: Color.fromARGB( backgroundColor: Color.fromARGB(
subSets.backgroundColorA!, subSets.backgroundColorR!, subSets.backgroundColorG!, subSets.backgroundColorB!)); subSets.backgroundColorA!,
subSets.backgroundColorR!,
subSets.backgroundColorG!,
subSets.backgroundColorB!));
} }

View file

@ -18,7 +18,8 @@ class BrowseScreen extends ConsumerStatefulWidget {
ConsumerState<BrowseScreen> createState() => _BrowseScreenState(); ConsumerState<BrowseScreen> createState() => _BrowseScreenState();
} }
class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProviderStateMixin { class _BrowseScreenState extends ConsumerState<BrowseScreen>
with TickerProviderStateMixin {
late TabController _tabBarController; late TabController _tabBarController;
@override @override
@ -74,26 +75,33 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProvider
) )
: Row( : Row(
children: [ children: [
if (_tabBarController.index == 2 || _tabBarController.index == 3) if (_tabBarController.index == 2 ||
_tabBarController.index == 3)
IconButton( IconButton(
onPressed: () { onPressed: () {
context.push('/createExtension'); context.push('/createExtension');
}, },
icon: Icon(Icons.add_outlined, color: Theme.of(context).hintColor)), icon: Icon(Icons.add_outlined,
color: Theme.of(context).hintColor)),
_tabBarController.index != 4 _tabBarController.index != 4
? IconButton( ? IconButton(
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
if (_tabBarController.index != 1 && _tabBarController.index != 0) { if (_tabBarController.index != 1 &&
_tabBarController.index != 0) {
setState(() { setState(() {
_isSearch = true; _isSearch = true;
}); });
} else { } else {
context.push('/globalSearch', extra: _tabBarController.index == 0 ? true : false); context.push('/globalSearch',
extra: _tabBarController.index == 0
? true
: false);
} }
}, },
icon: Icon( icon: Icon(
_tabBarController.index == 0 || _tabBarController.index == 1 _tabBarController.index == 0 ||
_tabBarController.index == 1
? Icons.travel_explore_rounded ? Icons.travel_explore_rounded
: Icons.search_rounded, : Icons.search_rounded,
color: Theme.of(context).hintColor)) color: Theme.of(context).hintColor))
@ -118,7 +126,8 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProvider
icon: Icon( icon: Icon(
_tabBarController.index == 0 || _tabBarController.index == 1 _tabBarController.index == 0 || _tabBarController.index == 1
? Icons.filter_list_sharp ? Icons.filter_list_sharp
: _tabBarController.index == 2 || _tabBarController.index == 3 : _tabBarController.index == 2 ||
_tabBarController.index == 3
? Icons.translate_rounded ? Icons.translate_rounded
: Icons.help_outline_outlined, : Icons.help_outline_outlined,
color: Theme.of(context).hintColor)), color: Theme.of(context).hintColor)),
@ -132,7 +141,11 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen> with TickerProvider
Tab(text: l10n.anime_sources), Tab(text: l10n.anime_sources),
Tab( Tab(
child: Row( child: Row(
children: [Text(l10n.manga_extensions), const SizedBox(width: 8), _extensionUpdateNumbers(ref, true)], children: [
Text(l10n.manga_extensions),
const SizedBox(width: 8),
_extensionUpdateNumbers(ref, true)
],
), ),
), ),
Tab( Tab(
@ -187,18 +200,23 @@ Widget _extensionUpdateNumbers(WidgetRef ref, bool isManga) {
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final entries = final entries = snapshot.data!
snapshot.data!.where((element) => compareVersions(element.version!, element.versionLast!) < 0).toList(); .where((element) =>
compareVersions(element.version!, element.versionLast!) < 0)
.toList();
return entries.isEmpty return entries.isEmpty
? Container() ? Container()
: Container( : Container(
decoration: decoration: BoxDecoration(
BoxDecoration(borderRadius: BorderRadius.circular(20), color: Theme.of(context).focusColor), borderRadius: BorderRadius.circular(20),
color: Theme.of(context).focusColor),
child: Padding( child: Padding(
padding: const EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Text( child: Text(
entries.length.toString(), entries.length.toString(),
style: TextStyle(fontSize: 12, color: Theme.of(context).textTheme.bodySmall!.color), style: TextStyle(
fontSize: 12,
color: Theme.of(context).textTheme.bodySmall!.color),
), ),
), ),
); );

View file

@ -37,7 +37,8 @@ Mode getSourceMode(Source? source) {
class _CodeEditorState extends ConsumerState<CodeEditor> { class _CodeEditorState extends ConsumerState<CodeEditor> {
dynamic result; dynamic result;
late final source = widget.sourceId == null ? null : isar.sources.getSync(widget.sourceId!); late final source =
widget.sourceId == null ? null : isar.sources.getSync(widget.sourceId!);
late final controller = CodeController( late final controller = CodeController(
text: source?.sourceCode ?? "", text: source?.sourceCode ?? "",
language: getSourceMode(source), language: getSourceMode(source),
@ -59,7 +60,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
bool _isLoading = false; bool _isLoading = false;
String _errorText = ""; String _errorText = "";
bool _error = false; bool _error = false;
final _logsNotifier = ValueNotifier<List<(LoggerLevel, String, DateTime)>>([]); final _logsNotifier =
ValueNotifier<List<(LoggerLevel, String, DateTime)>>([]);
late final _logStreamController = Logger.logStreamController; late final _logStreamController = Logger.logStreamController;
final _scrollController = ScrollController(); final _scrollController = ScrollController();
@override @override
@ -96,13 +98,15 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
), ),
const Spacer(), const Spacer(),
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: context.primaryColor), style: ElevatedButton.styleFrom(
backgroundColor: context.primaryColor),
onPressed: () { onPressed: () {
Navigator.pop(context, 'filter'); Navigator.pop(context, 'filter');
}, },
child: Text( child: Text(
context.l10n.filter, context.l10n.filter,
style: TextStyle(color: Theme.of(context).scaffoldBackgroundColor), style: TextStyle(
color: Theme.of(context).scaffoldBackgroundColor),
), ),
), ),
], ],
@ -156,7 +160,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
gutterStyle: const GutterStyle( gutterStyle: const GutterStyle(
textStyle: TextStyle( textStyle: TextStyle(
color: Colors.grey, color: Colors.grey,
height: 1.5, // Issue #307 fix, found in package: flutter-code-editor issue #270 height:
1.5, // Issue #307 fix, found in package: flutter-code-editor issue #270
), ),
showLineNumbers: true, showLineNumbers: true,
), ),
@ -165,7 +170,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
source?.sourceCode = a; source?.sourceCode = a;
}); });
if (source != null && mounted) { if (source != null && mounted) {
isar.writeTxnSync(() => isar.sources.putSync(source!)); isar.writeTxnSync(
() => isar.sources.putSync(source!));
} }
}, },
), ),
@ -182,11 +188,13 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
icon: const Icon(Icons.keyboard_arrow_down), icon: const Icon(Icons.keyboard_arrow_down),
isExpanded: true, isExpanded: true,
value: _serviceIndex, value: _serviceIndex,
hint: Text(_getServices(context)[_serviceIndex].$1, style: const TextStyle(fontSize: 13)), hint: Text(_getServices(context)[_serviceIndex].$1,
style: const TextStyle(fontSize: 13)),
items: _getServices(context) items: _getServices(context)
.map((e) => DropdownMenuItem( .map((e) => DropdownMenuItem(
value: e.$2, value: e.$2,
child: Text(e.$1, style: const TextStyle(fontSize: 13)), child: Text(e.$1,
style: const TextStyle(fontSize: 13)),
)) ))
.toList(), .toList(),
onChanged: (v) { onChanged: (v) {
@ -196,7 +204,9 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
}, },
), ),
), ),
if (_serviceIndex == 0 || _serviceIndex == 1 || _serviceIndex == 2) if (_serviceIndex == 0 ||
_serviceIndex == 1 ||
_serviceIndex == 2)
_textEditing("Page", context, "ex: 1", (v) { _textEditing("Page", context, "ex: 1", (v) {
_page = int.tryParse(v) ?? 1; _page = int.tryParse(v) ?? 1;
}), }),
@ -204,8 +214,11 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
_textEditing("Query", context, "ex: one piece", (v) { _textEditing("Query", context, "ex: one piece", (v) {
_query = v; _query = v;
}), }),
if (_serviceIndex == 3 || _serviceIndex == 4 || _serviceIndex == 5) if (_serviceIndex == 3 ||
_textEditing("Url", context, "ex: url of the entry", (v) { _serviceIndex == 4 ||
_serviceIndex == 5)
_textEditing("Url", context, "ex: url of the entry",
(v) {
_url = v; _url = v;
}), }),
Padding( Padding(
@ -219,7 +232,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
source?.sourceCode = controller.text; source?.sourceCode = controller.text;
}); });
if (source != null && mounted) { if (source != null && mounted) {
isar.writeTxnSync(() => isar.sources.putSync(source!)); isar.writeTxnSync(
() => isar.sources.putSync(source!));
} }
setState(() { setState(() {
result = null; result = null;
@ -228,36 +242,52 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
_errorText = ""; _errorText = "";
}); });
if (source != null) { if (source != null) {
final service = getExtensionService(source!); final service =
getExtensionService(source!);
try { try {
if (_serviceIndex == 0) { if (_serviceIndex == 0) {
final getManga = final getManga = await ref.watch(
await ref.watch(getPopularProvider(source: source!, page: _page).future); getPopularProvider(
source: source!,
page: _page)
.future);
result = getManga!.toJson(); result = getManga!.toJson();
} else if (_serviceIndex == 1) { } else if (_serviceIndex == 1) {
final getManga = await ref final getManga = await ref.watch(
.watch(getLatestUpdatesProvider(source: source!, page: _page).future); getLatestUpdatesProvider(
source: source!,
page: _page)
.future);
result = getManga!.toJson(); result = getManga!.toJson();
} else if (_serviceIndex == 2) { } else if (_serviceIndex == 2) {
final getManga = await ref.watch(searchProvider( final getManga = await ref.watch(
source: source!, query: _query, page: _page, filterList: filterList) searchProvider(
.future); source: source!,
query: _query,
page: _page,
filterList: filterList)
.future);
result = getManga!.toJson(); result = getManga!.toJson();
} else if (_serviceIndex == 3) { } else if (_serviceIndex == 3) {
final getManga = final getManga = await ref.watch(
await ref.watch(getDetailProvider(source: source!, url: _url).future); getDetailProvider(
source: source!,
url: _url)
.future);
result = getManga.toJson(); result = getManga.toJson();
} else if (_serviceIndex == 4) { } else if (_serviceIndex == 4) {
result = { result = {
"pages": (await service.getPageList(_url)) "pages": (await service
.getPageList(_url))
.map((e) => e.toJson()) .map((e) => e.toJson())
.toList(), .toList(),
}; };
} else { } else {
result = (await service.getVideoList(_url)) result =
.map((e) => e.toJson()) (await service.getVideoList(_url))
.toList(); .map((e) => e.toJson())
.toList();
} }
if (mounted) { if (mounted) {
setState(() { setState(() {
@ -298,7 +328,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
if (filters.isEmpty) { if (filters.isEmpty) {
filters = filterList; filters = filterList;
} }
final res = await filterDialog(context); final res =
await filterDialog(context);
if (res == 'filter' && mounted) { if (res == 'filter' && mounted) {
setState(() { setState(() {
result = null; result = null;
@ -306,9 +337,13 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
_error = false; _error = false;
_errorText = ""; _errorText = "";
}); });
final getManga = await ref.watch(searchProvider( final getManga = await ref.watch(
source: source!, query: _query, page: _page, filterList: filters) searchProvider(
.future); source: source!,
query: _query,
page: _page,
filterList: filters)
.future);
result = getManga!.toJson(); result = getManga!.toJson();
setState(() { setState(() {
_isLoading = false; _isLoading = false;
@ -331,22 +366,26 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
child: _error child: _error
? SingleChildScrollView( ? SingleChildScrollView(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Text(_errorText), Text(_errorText),
], ],
), ),
) )
: _isLoading : _isLoading
? const Center(child: CircularProgressIndicator()) ? const Center(
child: CircularProgressIndicator())
: result != null : result != null
? JsonConfig( ? JsonConfig(
data: JsonConfigData( data: JsonConfigData(
gap: 100, gap: 100,
style: const JsonStyleScheme( style: const JsonStyleScheme(
quotation: JsonQuotation.same('"'), quotation:
JsonQuotation.same('"'),
openAtStart: false, openAtStart: false,
arrow: Icon(Icons.arrow_forward), arrow:
Icon(Icons.arrow_forward),
depth: 4, depth: 4,
), ),
color: const JsonColorScheme(), color: const JsonColorScheme(),
@ -379,7 +418,10 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final value = logs[index]; final value = logs[index];
return SelectableText(value.$2, return SelectableText(value.$2,
style: TextStyle(color: value.$1 == LoggerLevel.info ? Colors.yellow : Colors.blueAccent)); style: TextStyle(
color: value.$1 == LoggerLevel.info
? Colors.yellow
: Colors.blueAccent));
}, },
), ),
), ),
@ -390,7 +432,8 @@ class _CodeEditorState extends ConsumerState<CodeEditor> {
} }
} }
Widget _textEditing(String label, BuildContext context, String hintText, void Function(String)? onChanged) { Widget _textEditing(String label, BuildContext context, String hintText,
void Function(String)? onChanged) {
return Padding( return Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: TextFormField( child: TextFormField(
@ -402,9 +445,12 @@ Widget _textEditing(String label, BuildContext context, String hintText, void Fu
isDense: true, isDense: true,
filled: true, filled: true,
fillColor: Colors.transparent, fillColor: Colors.transparent,
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor)), enabledBorder: OutlineInputBorder(
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor)), borderSide: BorderSide(color: context.dynamicThemeColor)),
border: OutlineInputBorder(borderSide: BorderSide(color: context.dynamicThemeColor))), focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: context.dynamicThemeColor)),
border: OutlineInputBorder(
borderSide: BorderSide(color: context.dynamicThemeColor))),
), ),
); );
} }

View file

@ -26,14 +26,17 @@ class ExtensionDetail extends ConsumerStatefulWidget {
class _ExtensionDetailState extends ConsumerState<ExtensionDetail> { class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
late Source source = widget.source; late Source source = widget.source;
late List<SourcePreference> sourcePreference = late List<SourcePreference> sourcePreference =
getSourcePreference(source: source).map((e) => getSourcePreferenceEntry(e.key!, source.id!)).toList(); getSourcePreference(source: source)
.map((e) => getSourcePreferenceEntry(e.key!, source.id!))
.toList();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(l10n.extension_detail), leading: BackButton(onPressed: () => Navigator.pop(context, source))), title: Text(l10n.extension_detail),
leading: BackButton(onPressed: () => Navigator.pop(context, source))),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
@ -41,7 +44,9 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.only(top: 20), padding: const EdgeInsets.only(top: 20),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5), color: Theme.of(context)
.secondaryHeaderColor
.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(10)), borderRadius: BorderRadius.circular(10)),
child: widget.source.iconUrl!.isEmpty child: widget.source.iconUrl!.isEmpty
? const Icon(Icons.source_outlined, size: 140) ? const Icon(Icons.source_outlined, size: 140)
@ -65,7 +70,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Text( child: Text(
widget.source.name!, widget.source.name!,
style: const TextStyle(fontSize: 23, fontWeight: FontWeight.bold), style:
const TextStyle(fontSize: 23, fontWeight: FontWeight.bold),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@ -73,7 +79,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.primaryColor.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(10)), color: context.primaryColor.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(10)),
child: Padding( child: Padding(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
child: Row( child: Row(
@ -83,7 +90,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
children: [ children: [
Text( Text(
widget.source.version!, widget.source.version!,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.bold),
), ),
Text( Text(
l10n.version, l10n.version,
@ -95,7 +103,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
children: [ children: [
Text( Text(
completeLanguageName(widget.source.lang!), completeLanguageName(widget.source.lang!),
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.bold),
), ),
Text( Text(
l10n.language, l10n.language,
@ -116,16 +125,19 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
elevation: 0, elevation: 0,
shadowColor: Colors.transparent), shadowColor: Colors.transparent),
onPressed: () async { onPressed: () async {
final res = await context.push('/codeEditor', extra: source.id); final res =
await context.push('/codeEditor', extra: source.id);
if (res != null && mounted) { if (res != null && mounted) {
setState(() { setState(() {
source = res as Source; source = res as Source;
sourcePreference = getSourcePreference(source: source) sourcePreference = getSourcePreference(source: source)
.map((e) => getSourcePreferenceEntry(e.key!, source.id!)) .map((e) =>
getSourcePreferenceEntry(e.key!, source.id!))
.toList(); .toList();
}); });
} }
@ -137,7 +149,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: const EdgeInsets.symmetric(horizontal: 10), padding: const EdgeInsets.symmetric(horizontal: 10),
child: Text( child: Text(
l10n.edit_code, l10n.edit_code,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
), ),
), ),
const Icon(Icons.code) const Icon(Icons.code)
@ -153,7 +166,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
elevation: 0, elevation: 0,
shadowColor: Colors.transparent), shadowColor: Colors.transparent),
onPressed: () async { onPressed: () async {
@ -164,7 +178,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 10),
child: Text( child: Text(
"Delete all cookies", "Delete all cookies",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
), ),
)), )),
), ),
@ -176,9 +191,11 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
side: BorderSide(color: context.primaryColor, width: 0.3), side:
BorderSide(color: context.primaryColor, width: 0.3),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
elevation: 0, elevation: 0,
shadowColor: Colors.transparent), shadowColor: Colors.transparent),
onPressed: () { onPressed: () {
@ -189,7 +206,8 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
title: Text( title: Text(
widget.source.name!, widget.source.name!,
), ),
content: Text(l10n.uninstall_extension(widget.source.name!)), content: Text(l10n
.uninstall_extension(widget.source.name!)),
actions: [ actions: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
@ -204,13 +222,15 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
final sourcePrefsIds = isar.sourcePreferences final sourcePrefsIds = isar
.sourcePreferences
.filter() .filter()
.sourceIdEqualTo(source.id!) .sourceIdEqualTo(source.id!)
.findAllSync() .findAllSync()
.map((e) => e.id!) .map((e) => e.id!)
.toList(); .toList();
final sourcePrefsStringIds = isar.sourcePreferenceStringValues final sourcePrefsStringIds = isar
.sourcePreferenceStringValues
.filter() .filter()
.sourceIdEqualTo(source.id!) .sourceIdEqualTo(source.id!)
.findAllSync() .findAllSync()
@ -218,15 +238,19 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
.toList(); .toList();
isar.writeTxnSync(() { isar.writeTxnSync(() {
if (source.isObsolete ?? false) { if (source.isObsolete ?? false) {
isar.sources.deleteSync(widget.source.id!); isar.sources.deleteSync(
widget.source.id!);
} else { } else {
isar.sources.putSync(widget.source isar.sources.putSync(widget.source
..sourceCode = "" ..sourceCode = ""
..isAdded = false ..isAdded = false
..isPinned = false); ..isPinned = false);
} }
isar.sourcePreferences.deleteAllSync(sourcePrefsIds); isar.sourcePreferences
isar.sourcePreferenceStringValues.deleteAllSync(sourcePrefsStringIds); .deleteAllSync(sourcePrefsIds);
isar.sourcePreferenceStringValues
.deleteAllSync(
sourcePrefsStringIds);
}); });
Navigator.pop(ctx); Navigator.pop(ctx);
@ -241,11 +265,13 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
}, },
child: Text( child: Text(
l10n.uninstall, l10n.uninstall,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
)), )),
), ),
), ),
SourcePreferenceWidget(sourcePreference: sourcePreference, source: source) SourcePreferenceWidget(
sourcePreference: sourcePreference, source: source)
], ],
), ),
), ),

View file

@ -39,7 +39,12 @@ class ExtensionsLang extends ConsumerWidget {
} else if (value == 1) { } else if (value == 1) {
enable = false; enable = false;
} }
final sources = isar.sources.filter().idIsNotNull().and().isMangaEqualTo(isManga).findAllSync(); final sources = isar.sources
.filter()
.idIsNotNull()
.and()
.isMangaEqualTo(isManga)
.findAllSync();
for (var source in sources) { for (var source in sources) {
isar.sources.putSync(source..isActive = enable); isar.sources.putSync(source..isActive = enable);
} }
@ -48,7 +53,12 @@ class ExtensionsLang extends ConsumerWidget {
], ],
), ),
body: StreamBuilder( body: StreamBuilder(
stream: isar.sources.filter().idIsNotNull().and().isMangaEqualTo(isManga).watch(fireImmediately: true), stream: isar.sources
.filter()
.idIsNotNull()
.and()
.isMangaEqualTo(isManga)
.watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
List<Source>? entries = snapshot.hasData ? snapshot.data : []; List<Source>? entries = snapshot.hasData ? snapshot.data : [];
final languages = entries!.map((e) => e.lang!).toSet().toList(); final languages = entries!.map((e) => e.lang!).toSet().toList();
@ -70,7 +80,9 @@ class ExtensionsLang extends ConsumerWidget {
}); });
}, },
value: entries value: entries
.where((element) => element.lang!.toLowerCase() == lang.toLowerCase() && element.isActive!) .where((element) =>
element.lang!.toLowerCase() == lang.toLowerCase() &&
element.isActive!)
.isNotEmpty, .isNotEmpty,
); );
}, },

View file

@ -14,7 +14,8 @@ import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_w
class ExtensionScreen extends ConsumerStatefulWidget { class ExtensionScreen extends ConsumerStatefulWidget {
final bool isManga; final bool isManga;
final String query; final String query;
const ExtensionScreen({required this.query, required this.isManga, super.key}); const ExtensionScreen(
{required this.query, required this.isManga, super.key});
@override @override
ConsumerState<ExtensionScreen> createState() => _ExtensionScreenState(); ConsumerState<ExtensionScreen> createState() => _ExtensionScreenState();
@ -24,7 +25,8 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
final controller = ScrollController(); final controller = ScrollController();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final streamExtensions = ref.watch(getExtensionsStreamProvider(widget.isManga)); final streamExtensions =
ref.watch(getExtensionsStreamProvider(widget.isManga));
if (widget.isManga) { if (widget.isManga) {
ref.watch(fetchMangaSourcesListProvider(id: null, reFresh: false)); ref.watch(fetchMangaSourcesListProvider(id: null, reFresh: false));
} else { } else {
@ -33,15 +35,21 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => widget.isManga onRefresh: () => widget.isManga
? ref.refresh(fetchMangaSourcesListProvider(id: null, reFresh: true).future) ? ref.refresh(
: ref.refresh(fetchAnimeSourcesListProvider(id: null, reFresh: true).future), fetchMangaSourcesListProvider(id: null, reFresh: true).future)
: ref.refresh(
fetchAnimeSourcesListProvider(id: null, reFresh: true).future),
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: streamExtensions.when( child: streamExtensions.when(
data: (data) { data: (data) {
data = widget.query.isEmpty data = widget.query.isEmpty
? data ? data
: data.where((element) => element.name!.toLowerCase().contains(widget.query.toLowerCase())).toList(); : data
.where((element) => element.name!
.toLowerCase()
.contains(widget.query.toLowerCase()))
.toList();
final notInstalledEntries = data final notInstalledEntries = data
.where((element) => element.version == element.versionLast!) .where((element) => element.version == element.versionLast!)
@ -51,8 +59,10 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
.where((element) => element.version == element.versionLast!) .where((element) => element.version == element.versionLast!)
.where((element) => element.isAdded!) .where((element) => element.isAdded!)
.toList(); .toList();
final updateEntries = final updateEntries = data
data.where((element) => compareVersions(element.version!, element.versionLast!) < 0).toList(); .where((element) =>
compareVersions(element.version!, element.versionLast!) < 0)
.toList();
return Scrollbar( return Scrollbar(
interactive: true, interactive: true,
controller: controller, controller: controller,
@ -71,16 +81,21 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
children: [ children: [
Text( Text(
l10n.update_pending, l10n.update_pending,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
), ),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
for (var source in updateEntries) { for (var source in updateEntries) {
source.isManga! source.isManga!
? await ref ? await ref.watch(
.watch(fetchMangaSourcesListProvider(id: source.id, reFresh: true).future) fetchMangaSourcesListProvider(
: await ref id: source.id, reFresh: true)
.watch(fetchAnimeSourcesListProvider(id: source.id, reFresh: true).future); .future)
: await ref.watch(
fetchAnimeSourcesListProvider(
id: source.id, reFresh: true)
.future);
} }
}, },
child: Text(l10n.update_all)) child: Text(l10n.update_all))
@ -92,8 +107,10 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
source: element, source: element,
); );
}, },
groupComparator: (group1, group2) => group1.compareTo(group2), groupComparator: (group1, group2) =>
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!), group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC, order: GroupedListOrder.ASC,
), ),
SliverGroupedListView<Source, String>( SliverGroupedListView<Source, String>(
@ -103,26 +120,31 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
padding: const EdgeInsets.symmetric(horizontal: 12), padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text( child: Text(
l10n.installed, l10n.installed,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
), ),
), ),
itemBuilder: (context, Source element) { itemBuilder: (context, Source element) {
return ExtensionListTileWidget(source: element); return ExtensionListTileWidget(source: element);
}, },
groupComparator: (group1, group2) => group1.compareTo(group2), groupComparator: (group1, group2) =>
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!), group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC, order: GroupedListOrder.ASC,
), ),
SliverGroupedListView<Source, String>( SliverGroupedListView<Source, String>(
elements: notInstalledEntries, elements: notInstalledEntries,
groupBy: (element) => completeLanguageName(element.lang!.toLowerCase()), groupBy: (element) =>
completeLanguageName(element.lang!.toLowerCase()),
groupSeparatorBuilder: (String groupByValue) => Padding( groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(left: 12), padding: const EdgeInsets.only(left: 12),
child: Row( child: Row(
children: [ children: [
Text( Text(
groupByValue, groupByValue,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
), ),
], ],
), ),
@ -132,8 +154,10 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
source: element, source: element,
); );
}, },
groupComparator: (group1, group2) => group1.compareTo(group2), groupComparator: (group1, group2) =>
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!), group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC, order: GroupedListOrder.ASC,
), ),
], ],
@ -144,9 +168,11 @@ class _ExtensionScreenState extends ConsumerState<ExtensionScreen> {
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
if (widget.isManga) { if (widget.isManga) {
ref.invalidate(fetchMangaSourcesListProvider(id: null, reFresh: true)); ref.invalidate(
fetchMangaSourcesListProvider(id: null, reFresh: true));
} else { } else {
ref.invalidate(fetchAnimeSourcesListProvider(id: null, reFresh: true)); ref.invalidate(
fetchAnimeSourcesListProvider(id: null, reFresh: true));
} }
}, },
child: Text(context.l10n.refresh)), child: Text(context.l10n.refresh)),

View file

@ -5,8 +5,11 @@ import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/services/get_source_preference.dart'; import 'package:mangayomi/services/get_source_preference.dart';
void setPreferenceSetting(SourcePreference sourcePreference, Source source) { void setPreferenceSetting(SourcePreference sourcePreference, Source source) {
final sourcePref = final sourcePref = isar.sourcePreferences
isar.sourcePreferences.filter().sourceIdEqualTo(source.id).keyEqualTo(sourcePreference.key).findFirstSync(); .filter()
.sourceIdEqualTo(source.id)
.keyEqualTo(sourcePreference.key)
.findFirstSync();
isar.writeTxnSync(() { isar.writeTxnSync(() {
if (sourcePref != null) { if (sourcePref != null) {
isar.sourcePreferences.putSync(sourcePreference); isar.sourcePreferences.putSync(sourcePreference);
@ -33,21 +36,30 @@ getPreferenceValue(int sourceId, String key) {
} }
SourcePreference getSourcePreferenceEntry(String key, int sourceId) { SourcePreference getSourcePreferenceEntry(String key, int sourceId) {
SourcePreference? sourcePreference = SourcePreference? sourcePreference = isar.sourcePreferences
isar.sourcePreferences.filter().sourceIdEqualTo(sourceId).keyEqualTo(key).findFirstSync(); .filter()
.sourceIdEqualTo(sourceId)
.keyEqualTo(key)
.findFirstSync();
if (sourcePreference == null) { if (sourcePreference == null) {
final source = isar.sources.getSync(sourceId)!; final source = isar.sources.getSync(sourceId)!;
sourcePreference = getSourcePreference(source: source) sourcePreference = getSourcePreference(source: source).firstWhere(
.firstWhere((element) => element.key == key, orElse: () => throw "Error when getting source preference"); (element) => element.key == key,
orElse: () => throw "Error when getting source preference");
setPreferenceSetting(sourcePreference, source); setPreferenceSetting(sourcePreference, source);
} }
return sourcePreference; return sourcePreference;
} }
String getSourcePreferenceStringValue(int sourceId, String key, String defaultValue) { String getSourcePreferenceStringValue(
SourcePreferenceStringValue? sourcePreferenceStringValue = int sourceId, String key, String defaultValue) {
isar.sourcePreferenceStringValues.filter().sourceIdEqualTo(sourceId).keyEqualTo(key).findFirstSync(); SourcePreferenceStringValue? sourcePreferenceStringValue = isar
.sourcePreferenceStringValues
.filter()
.sourceIdEqualTo(sourceId)
.keyEqualTo(key)
.findFirstSync();
if (sourcePreferenceStringValue == null) { if (sourcePreferenceStringValue == null) {
setSourcePreferenceStringValue(sourceId, key, defaultValue); setSourcePreferenceStringValue(sourceId, key, defaultValue);
return defaultValue; return defaultValue;
@ -57,8 +69,11 @@ String getSourcePreferenceStringValue(int sourceId, String key, String defaultVa
} }
void setSourcePreferenceStringValue(int sourceId, String key, String value) { void setSourcePreferenceStringValue(int sourceId, String key, String value) {
final sourcePref = final sourcePref = isar.sourcePreferenceStringValues
isar.sourcePreferenceStringValues.filter().sourceIdEqualTo(sourceId).keyEqualTo(key).findFirstSync(); .filter()
.sourceIdEqualTo(sourceId)
.keyEqualTo(key)
.findFirstSync();
isar.writeTxnSync(() { isar.writeTxnSync(() {
if (sourcePref != null) { if (sourcePref != null) {
isar.sourcePreferenceStringValues.putSync(sourcePref..value = value); isar.sourcePreferenceStringValues.putSync(sourcePref..value = value);

View file

@ -46,11 +46,13 @@ class _CreateExtensionState extends State<CreateExtension> {
icon: const Icon(Icons.keyboard_arrow_down), icon: const Icon(Icons.keyboard_arrow_down),
isExpanded: true, isExpanded: true,
value: _languageIndex, value: _languageIndex,
hint: Text(_languages[_languageIndex], style: const TextStyle(fontSize: 13)), hint: Text(_languages[_languageIndex],
style: const TextStyle(fontSize: 13)),
items: _languages items: _languages
.map((e) => DropdownMenuItem( .map((e) => DropdownMenuItem(
value: _languages.indexOf(e), value: _languages.indexOf(e),
child: Text(e, style: const TextStyle(fontSize: 13)), child: Text(e,
style: const TextStyle(fontSize: 13)),
)) ))
.toList(), .toList(),
onChanged: (v) { onChanged: (v) {
@ -58,7 +60,8 @@ class _CreateExtensionState extends State<CreateExtension> {
if (v == 0) { if (v == 0) {
_sourceCodeLanguage = SourceCodeLanguage.dart; _sourceCodeLanguage = SourceCodeLanguage.dart;
} else { } else {
_sourceCodeLanguage = SourceCodeLanguage.javascript; _sourceCodeLanguage =
SourceCodeLanguage.javascript;
} }
_languageIndex = v!; _languageIndex = v!;
}); });
@ -78,12 +81,15 @@ class _CreateExtensionState extends State<CreateExtension> {
_lang = v; _lang = v;
}); });
}), }),
_textEditing("BaseUrl", context, "ex: https://example.com", (v) { _textEditing("BaseUrl", context, "ex: https://example.com",
(v) {
setState(() { setState(() {
_baseUrl = v; _baseUrl = v;
}); });
}), }),
_textEditing("ApiUrl (optional)", context, "ex: https://api.example.com", (v) { _textEditing(
"ApiUrl (optional)", context, "ex: https://api.example.com",
(v) {
setState(() { setState(() {
_apiUrl = v; _apiUrl = v;
}); });
@ -104,11 +110,13 @@ class _CreateExtensionState extends State<CreateExtension> {
icon: const Icon(Icons.keyboard_arrow_down), icon: const Icon(Icons.keyboard_arrow_down),
isExpanded: true, isExpanded: true,
value: _sourceTypeIndex, value: _sourceTypeIndex,
hint: Text(_sourceTypes[_sourceTypeIndex], style: const TextStyle(fontSize: 13)), hint: Text(_sourceTypes[_sourceTypeIndex],
style: const TextStyle(fontSize: 13)),
items: _sourceTypes items: _sourceTypes
.map((e) => DropdownMenuItem( .map((e) => DropdownMenuItem(
value: _sourceTypes.indexOf(e), value: _sourceTypes.indexOf(e),
child: Text(e, style: const TextStyle(fontSize: 13)), child: Text(e,
style: const TextStyle(fontSize: 13)),
)) ))
.toList(), .toList(),
onChanged: (v) { onChanged: (v) {
@ -132,11 +140,15 @@ class _CreateExtensionState extends State<CreateExtension> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
if (_name.isNotEmpty && _lang.isNotEmpty && _baseUrl.isNotEmpty && _iconUrl.isNotEmpty) { if (_name.isNotEmpty &&
_lang.isNotEmpty &&
_baseUrl.isNotEmpty &&
_iconUrl.isNotEmpty) {
try { try {
final id = _sourceCodeLanguage == SourceCodeLanguage.dart final id =
? 'mangayomi-$_lang.$_name'.hashCode _sourceCodeLanguage == SourceCodeLanguage.dart
: 'mangayomi-js-$_lang.$_name'.hashCode; ? 'mangayomi-$_lang.$_name'.hashCode
: 'mangayomi-js-$_lang.$_name'.hashCode;
final checkIfExist = isar.sources.getSync(id); final checkIfExist = isar.sources.getSync(id);
if (checkIfExist == null) { if (checkIfExist == null) {
Source source = Source( Source source = Source(
@ -155,9 +167,12 @@ class _CreateExtensionState extends State<CreateExtension> {
..sourceCodeLanguage = _sourceCodeLanguage; ..sourceCodeLanguage = _sourceCodeLanguage;
source = source source = source
..isLocal = true ..isLocal = true
..sourceCode = ..sourceCode = _sourceCodeLanguage ==
_sourceCodeLanguage == SourceCodeLanguage.dart ? _dartTemplate : _jsSample(source); SourceCodeLanguage.dart
isar.writeTxnSync(() => isar.sources.putSync(source)); ? _dartTemplate
: _jsSample(source);
isar.writeTxnSync(
() => isar.sources.putSync(source));
Navigator.pop(context); Navigator.pop(context);
botToast("Source created successfully"); botToast("Source created successfully");
} else { } else {
@ -177,7 +192,8 @@ class _CreateExtensionState extends State<CreateExtension> {
} }
} }
Widget _textEditing(String label, BuildContext context, String hintText, void Function(String)? onChanged) { Widget _textEditing(String label, BuildContext context, String hintText,
void Function(String)? onChanged) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 5),
child: TextFormField( child: TextFormField(
@ -189,9 +205,12 @@ Widget _textEditing(String label, BuildContext context, String hintText, void Fu
isDense: true, isDense: true,
filled: true, filled: true,
fillColor: Colors.transparent, fillColor: Colors.transparent,
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: context.secondaryColor)), enabledBorder: OutlineInputBorder(
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: context.secondaryColor)), borderSide: BorderSide(color: context.secondaryColor)),
border: OutlineInputBorder(borderSide: BorderSide(color: context.secondaryColor))), focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: context.secondaryColor)),
border: OutlineInputBorder(
borderSide: BorderSide(color: context.secondaryColor))),
), ),
); );
} }

View file

@ -5,7 +5,11 @@ class ExtensionLangListTileWidget extends StatelessWidget {
final String lang; final String lang;
final bool value; final bool value;
final Function(bool) onChanged; final Function(bool) onChanged;
const ExtensionLangListTileWidget({super.key, required this.lang, required this.value, required this.onChanged}); const ExtensionLangListTileWidget(
{super.key,
required this.lang,
required this.value,
required this.onChanged});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -14,22 +14,28 @@ import 'package:mangayomi/utils/language.dart';
class ExtensionListTileWidget extends ConsumerStatefulWidget { class ExtensionListTileWidget extends ConsumerStatefulWidget {
final Source source; final Source source;
final bool isTestSource; final bool isTestSource;
const ExtensionListTileWidget({super.key, required this.source, this.isTestSource = false}); const ExtensionListTileWidget(
{super.key, required this.source, this.isTestSource = false});
@override @override
ConsumerState<ExtensionListTileWidget> createState() => _ExtensionListTileWidgetState(); ConsumerState<ExtensionListTileWidget> createState() =>
_ExtensionListTileWidgetState();
} }
class _ExtensionListTileWidgetState extends ConsumerState<ExtensionListTileWidget> { class _ExtensionListTileWidgetState
extends ConsumerState<ExtensionListTileWidget> {
bool _isLoading = false; bool _isLoading = false;
@override @override
Widget build( Widget build(
BuildContext context, BuildContext context,
) { ) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final updateAivalable = final updateAivalable = widget.isTestSource
widget.isTestSource ? false : compareVersions(widget.source.version!, widget.source.versionLast!) < 0; ? false
final sourceNotEmpty = widget.source.sourceCode != null && widget.source.sourceCode!.isNotEmpty; : compareVersions(widget.source.version!, widget.source.versionLast!) <
0;
final sourceNotEmpty = widget.source.sourceCode != null &&
widget.source.sourceCode!.isNotEmpty;
return ListTile( return ListTile(
onTap: () async { onTap: () async {
@ -43,8 +49,12 @@ class _ExtensionListTileWidgetState extends ConsumerState<ExtensionListTileWidge
_isLoading = true; _isLoading = true;
}); });
widget.source.isManga! widget.source.isManga!
? await ref.watch(fetchMangaSourcesListProvider(id: widget.source.id, reFresh: true).future) ? await ref.watch(fetchMangaSourcesListProvider(
: await ref.watch(fetchAnimeSourcesListProvider(id: widget.source.id, reFresh: true).future); id: widget.source.id, reFresh: true)
.future)
: await ref.watch(fetchAnimeSourcesListProvider(
id: widget.source.id, reFresh: true)
.future);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
@ -56,7 +66,8 @@ class _ExtensionListTileWidgetState extends ConsumerState<ExtensionListTileWidge
height: 37, height: 37,
width: 37, width: 37,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5), color:
Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(5)), borderRadius: BorderRadius.circular(5)),
child: widget.source.iconUrl!.isEmpty child: widget.source.iconUrl!.isEmpty
? const Icon(Icons.extension_rounded) ? const Icon(Icons.extension_rounded)
@ -79,14 +90,20 @@ class _ExtensionListTileWidgetState extends ConsumerState<ExtensionListTileWidge
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text(completeLanguageName(widget.source.lang!.toLowerCase()), Text(completeLanguageName(widget.source.lang!.toLowerCase()),
style: const TextStyle(fontWeight: FontWeight.w300, fontSize: 12)), style:
const TextStyle(fontWeight: FontWeight.w300, fontSize: 12)),
const SizedBox(width: 4), const SizedBox(width: 4),
Text(widget.source.version!, style: const TextStyle(fontWeight: FontWeight.w300, fontSize: 12)), Text(widget.source.version!,
style:
const TextStyle(fontWeight: FontWeight.w300, fontSize: 12)),
if (widget.source.isObsolete ?? false) if (widget.source.isObsolete ?? false)
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(horizontal: 4),
child: Text("OBSOLETE", child: Text("OBSOLETE",
style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 12)), style: TextStyle(
color: context.primaryColor,
fontWeight: FontWeight.bold,
fontSize: 12)),
) )
], ],
), ),
@ -100,8 +117,12 @@ class _ExtensionListTileWidgetState extends ConsumerState<ExtensionListTileWidge
_isLoading = true; _isLoading = true;
}); });
widget.source.isManga! widget.source.isManga!
? await ref.watch(fetchMangaSourcesListProvider(id: widget.source.id, reFresh: true).future) ? await ref.watch(fetchMangaSourcesListProvider(
: await ref.watch(fetchAnimeSourcesListProvider(id: widget.source.id, reFresh: true).future); id: widget.source.id, reFresh: true)
.future)
: await ref.watch(fetchAnimeSourcesListProvider(
id: widget.source.id, reFresh: true)
.future);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;

View file

@ -9,7 +9,8 @@ import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
class SourcePreferenceWidget extends StatefulWidget { class SourcePreferenceWidget extends StatefulWidget {
final List<SourcePreference> sourcePreference; final List<SourcePreference> sourcePreference;
final Source source; final Source source;
const SourcePreferenceWidget({super.key, required this.sourcePreference, required this.source}); const SourcePreferenceWidget(
{super.key, required this.sourcePreference, required this.source});
@override @override
State<SourcePreferenceWidget> createState() => _SourcePreferenceWidgetState(); State<SourcePreferenceWidget> createState() => _SourcePreferenceWidgetState();
@ -29,7 +30,9 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
final pref = preference.editTextPreference!; final pref = preference.editTextPreference!;
w = ListTile( w = ListTile(
title: Text(pref.title!), title: Text(pref.title!),
subtitle: Text(pref.summary!, style: TextStyle(fontSize: 11, color: context.secondaryColor)), subtitle: Text(pref.summary!,
style: TextStyle(
fontSize: 11, color: context.secondaryColor)),
onTap: () { onTap: () {
showDialog( showDialog(
context: context, context: context,
@ -49,7 +52,9 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
final pref = preference.checkBoxPreference!; final pref = preference.checkBoxPreference!;
w = CheckboxListTile( w = CheckboxListTile(
title: Text(pref.title!), title: Text(pref.title!),
subtitle: Text(pref.summary!, style: TextStyle(fontSize: 11, color: context.secondaryColor)), subtitle: Text(pref.summary!,
style: TextStyle(
fontSize: 11, color: context.secondaryColor)),
value: pref.value, value: pref.value,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
@ -63,7 +68,9 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
final pref = preference.switchPreferenceCompat!; final pref = preference.switchPreferenceCompat!;
w = SwitchListTile( w = SwitchListTile(
title: Text(pref.title!), title: Text(pref.title!),
subtitle: Text(pref.summary!, style: TextStyle(fontSize: 11, color: context.secondaryColor)), subtitle: Text(pref.summary!,
style: TextStyle(
fontSize: 11, color: context.secondaryColor)),
value: pref.value!, value: pref.value!,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
@ -78,7 +85,8 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
w = ListTile( w = ListTile(
title: Text(pref.title!), title: Text(pref.title!),
subtitle: Text(pref.entries![pref.valueIndex!], subtitle: Text(pref.entries![pref.valueIndex!],
style: TextStyle(fontSize: 11, color: context.secondaryColor)), style: TextStyle(
fontSize: 11, color: context.secondaryColor)),
onTap: () async { onTap: () async {
final res = await showDialog( final res = await showDialog(
context: context, context: context,
@ -114,7 +122,8 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
}, },
child: Text( child: Text(
context.l10n.cancel, context.l10n.cancel,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
], ],
) )
@ -132,7 +141,9 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
final pref = preference.multiSelectListPreference!; final pref = preference.multiSelectListPreference!;
w = ListTile( w = ListTile(
title: Text(pref.title!), title: Text(pref.title!),
subtitle: Text(pref.summary!, style: TextStyle(fontSize: 11, color: context.secondaryColor)), subtitle: Text(pref.summary!,
style: TextStyle(
fontSize: 11, color: context.secondaryColor)),
onTap: () { onTap: () {
List<String> indexList = []; List<String> indexList = [];
indexList.addAll(pref.values!); indexList.addAll(pref.values!);
@ -151,20 +162,27 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ListTileChapterFilter( return ListTileChapterFilter(
label: pref.entries![index], label: pref.entries![index],
type: indexList.contains(pref.entryValues![index]) ? 1 : 0, type: indexList.contains(
pref.entryValues![index])
? 1
: 0,
onTap: () { onTap: () {
if (indexList.contains(pref.entryValues![index])) { if (indexList.contains(
pref.entryValues![index])) {
setState(() { setState(() {
indexList.remove(pref.entryValues![index]); indexList.remove(pref
.entryValues![index]);
pref.values = indexList; pref.values = indexList;
}); });
} else { } else {
setState(() { setState(() {
indexList.add(pref.entryValues![index]); indexList.add(pref
.entryValues![index]);
pref.values = indexList; pref.values = indexList;
}); });
} }
setPreferenceSetting(preference, widget.source); setPreferenceSetting(
preference, widget.source);
}); });
}, },
)), )),
@ -178,7 +196,8 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
}, },
child: Text( child: Text(
context.l10n.cancel, context.l10n.cancel,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@ -186,7 +205,8 @@ class _SourcePreferenceWidgetState extends State<SourcePreferenceWidget> {
}, },
child: Text( child: Text(
context.l10n.ok, context.l10n.ok,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
], ],
) )
@ -211,7 +231,11 @@ class EditTextDialogWidget extends StatefulWidget {
final String dialogMessage; final String dialogMessage;
final Function(String) onChanged; final Function(String) onChanged;
const EditTextDialogWidget( const EditTextDialogWidget(
{super.key, required this.text, required this.onChanged, required this.dialogTitle, required this.dialogMessage}); {super.key,
required this.text,
required this.onChanged,
required this.dialogTitle,
required this.dialogMessage});
@override @override
State<EditTextDialogWidget> createState() => _EditTextDialogWidgetState(); State<EditTextDialogWidget> createState() => _EditTextDialogWidgetState();
@ -224,7 +248,10 @@ class _EditTextDialogWidgetState extends State<EditTextDialogWidget> {
return AlertDialog( return AlertDialog(
title: Column( title: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [Text(widget.dialogTitle), Text(widget.dialogMessage, style: const TextStyle(fontSize: 13))], children: [
Text(widget.dialogTitle),
Text(widget.dialogMessage, style: const TextStyle(fontSize: 13))
],
), ),
content: Padding( content: Padding(
padding: const EdgeInsets.only(top: 20), padding: const EdgeInsets.only(top: 20),

View file

@ -38,7 +38,12 @@ class _GlobalSearchScreenState extends ConsumerState<GlobalSearchScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Source> sourceList = ref.watch(onlyIncludePinnedSourceStateProvider) List<Source> sourceList = ref.watch(onlyIncludePinnedSourceStateProvider)
? isar.sources.filter().isPinnedEqualTo(true).and().isMangaEqualTo(widget.isManga).findAllSync() ? isar.sources
.filter()
.isPinnedEqualTo(true)
.and()
.isMangaEqualTo(widget.isManga)
.findAllSync()
: isar.sources : isar.sources
.filter() .filter()
.idIsNotNull() .idIsNotNull()
@ -123,7 +128,8 @@ class _SourceSearchScreenState extends State<SourceSearchScreen> {
_init() async { _init() async {
try { try {
_errorMessage = ""; _errorMessage = "";
pages = await search(source: widget.source, page: 1, query: widget.query, filterList: []); pages = await search(
source: widget.source, page: 1, query: widget.query, filterList: []);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
@ -214,7 +220,8 @@ class MangaGlobalImageCard extends ConsumerStatefulWidget {
}); });
@override @override
ConsumerState<MangaGlobalImageCard> createState() => _MangaGlobalImageCardState(); ConsumerState<MangaGlobalImageCard> createState() =>
_MangaGlobalImageCardState();
} }
class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard> class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
@ -251,16 +258,20 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
child: Column(children: [ child: Column(children: [
Builder( Builder(
builder: (context) { builder: (context) {
if (hasData && snapshot.data!.first.customCoverImage != null) { if (hasData &&
return Image.memory(snapshot.data!.first.customCoverImage as Uint8List); snapshot.data!.first.customCoverImage != null) {
return Image.memory(snapshot
.data!.first.customCoverImage as Uint8List);
} }
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
child: cachedNetworkImage( child: cachedNetworkImage(
headers: ref headers: ref.watch(headersProvider(
.watch(headersProvider(source: widget.source.name!, lang: widget.source.lang!)), source: widget.source.name!,
lang: widget.source.lang!)),
imageUrl: toImgUrl(hasData imageUrl: toImgUrl(hasData
? snapshot.data!.first.customCoverFromTracker ?? ? snapshot.data!.first
.customCoverFromTracker ??
snapshot.data!.first.imageUrl ?? snapshot.data!.first.imageUrl ??
"" ""
: getMangaDetail.imageUrl ?? ""), : getMangaDetail.imageUrl ?? ""),
@ -281,7 +292,9 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
Container( Container(
width: 110, width: 110,
height: 150, height: 150,
color: hasData && snapshot.data!.first.favorite! ? Colors.black.withValues(alpha: 0.7) : null, color: hasData && snapshot.data!.first.favorite!
? Colors.black.withValues(alpha: 0.7)
: null,
), ),
if (hasData && snapshot.data!.first.favorite!) if (hasData && snapshot.data!.first.favorite!)
Positioned( Positioned(
@ -289,7 +302,8 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
left: 0, left: 0,
child: Padding( child: Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: Icon(Icons.collections_bookmark, color: context.primaryColor), child: Icon(Icons.collections_bookmark,
color: context.primaryColor),
)) ))
], ],
), ),

View file

@ -38,7 +38,8 @@ class SourcesFilterScreen extends ConsumerWidget {
SliverGroupedListView<Source, String>( SliverGroupedListView<Source, String>(
elements: entries, elements: entries,
groupBy: (element) => element.lang!, groupBy: (element) => element.lang!,
groupSeparatorBuilder: (String groupByValue) => SwitchListTile( groupSeparatorBuilder: (String groupByValue) =>
SwitchListTile(
value: entries value: entries
.where((element) => .where((element) =>
element.lang!.toLowerCase() == groupByValue && element.lang!.toLowerCase() == groupByValue &&
@ -49,19 +50,24 @@ class SourcesFilterScreen extends ConsumerWidget {
isar.writeTxnSync(() { isar.writeTxnSync(() {
for (var source in entries) { for (var source in entries) {
if (source.lang!.toLowerCase() == groupByValue) { if (source.lang!.toLowerCase() == groupByValue) {
isar.sources.putSync(source..isActive = val == true); isar.sources
.putSync(source..isActive = val == true);
} }
} }
}); });
}, },
title: Text( title: Text(
completeLanguageName(groupByValue), completeLanguageName(groupByValue),
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
), ),
), ),
itemBuilder: (context, Source element) { itemBuilder: (context, Source element) {
if (entries if (entries
.where((s) => s.lang!.toLowerCase() == element.lang && s.isActive! && s.isManga == isManga) .where((s) =>
s.lang!.toLowerCase() == element.lang &&
s.isActive! &&
s.isManga == isManga)
.isEmpty) { .isEmpty) {
return Container(); return Container();
} }
@ -70,7 +76,9 @@ class SourcesFilterScreen extends ConsumerWidget {
height: 37, height: 37,
width: 37, width: 37,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5), color: Theme.of(context)
.secondaryHeaderColor
.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(5)), borderRadius: BorderRadius.circular(5)),
child: element.iconUrl!.isEmpty child: element.iconUrl!.isEmpty
? const Icon(Icons.source_outlined) ? const Icon(Icons.source_outlined)
@ -97,8 +105,10 @@ class SourcesFilterScreen extends ConsumerWidget {
title: Text(element.name!), title: Text(element.name!),
); );
}, },
groupComparator: (group1, group2) => group1.compareTo(group2), groupComparator: (group1, group2) =>
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!), group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC, order: GroupedListOrder.ASC,
), ),
], ],

View file

@ -11,7 +11,8 @@ import 'package:mangayomi/utils/language.dart';
class SourcesScreen extends ConsumerStatefulWidget { class SourcesScreen extends ConsumerStatefulWidget {
final Function(int) tabIndex; final Function(int) tabIndex;
final bool isManga; final bool isManga;
const SourcesScreen({required this.tabIndex, required this.isManga, super.key}); const SourcesScreen(
{required this.tabIndex, required this.isManga, super.key});
@override @override
ConsumerState<SourcesScreen> createState() => _SourcesScreenState(); ConsumerState<SourcesScreen> createState() => _SourcesScreenState();
@ -50,16 +51,20 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: () => widget.tabIndex(widget.isManga ? 2 : 3), onPressed: () =>
widget.tabIndex(widget.isManga ? 2 : 3),
icon: const Icon(Icons.extension_rounded), icon: const Icon(Icons.extension_rounded),
label: Text(context.l10n.show_extensions)), label: Text(context.l10n.show_extensions)),
) )
], ],
); );
} }
final lastUsedEntries = sources.where((element) => element.lastUsed!).toList(); final lastUsedEntries =
final isPinnedEntries = sources.where((element) => element.isPinned!).toList(); sources.where((element) => element.lastUsed!).toList();
final allEntriesWithoutIspinned = sources.where((element) => !element.isPinned!).toList(); final isPinnedEntries =
sources.where((element) => element.isPinned!).toList();
final allEntriesWithoutIspinned =
sources.where((element) => !element.isPinned!).toList();
return Scrollbar( return Scrollbar(
interactive: true, interactive: true,
controller: controller, controller: controller,
@ -77,7 +82,8 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
children: [ children: [
Text( Text(
l10n.last_used, l10n.last_used,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
), ),
], ],
), ),
@ -88,8 +94,10 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
isManga: widget.isManga, isManga: widget.isManga,
); );
}, },
groupComparator: (group1, group2) => group1.compareTo(group2), groupComparator: (group1, group2) =>
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!), group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC, order: GroupedListOrder.ASC,
), ),
SliverGroupedListView<Source, String>( SliverGroupedListView<Source, String>(
@ -101,7 +109,8 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
children: [ children: [
Text( Text(
l10n.pinned, l10n.pinned,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
), ),
], ],
), ),
@ -112,20 +121,24 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
isManga: widget.isManga, isManga: widget.isManga,
); );
}, },
groupComparator: (group1, group2) => group1.compareTo(group2), groupComparator: (group1, group2) =>
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!), group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC, order: GroupedListOrder.ASC,
), ),
SliverGroupedListView<Source, String>( SliverGroupedListView<Source, String>(
elements: allEntriesWithoutIspinned, elements: allEntriesWithoutIspinned,
groupBy: (element) => completeLanguageName(element.lang!.toLowerCase()), groupBy: (element) =>
completeLanguageName(element.lang!.toLowerCase()),
groupSeparatorBuilder: (String groupByValue) => Padding( groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(left: 12), padding: const EdgeInsets.only(left: 12),
child: Row( child: Row(
children: [ children: [
Text( Text(
groupByValue, groupByValue,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
), ),
], ],
), ),
@ -136,8 +149,10 @@ class _SourcesScreenState extends ConsumerState<SourcesScreen> {
isManga: widget.isManga, isManga: widget.isManga,
); );
}, },
groupComparator: (group1, group2) => group1.compareTo(group2), groupComparator: (group1, group2) =>
itemComparator: (item1, item2) => item1.name!.compareTo(item2.name!), group1.compareTo(group2),
itemComparator: (item1, item2) =>
item1.name!.compareTo(item2.name!),
order: GroupedListOrder.ASC, order: GroupedListOrder.ASC,
), ),
], ],

View file

@ -12,16 +12,23 @@ import 'package:mangayomi/utils/language.dart';
class SourceListTile extends StatelessWidget { class SourceListTile extends StatelessWidget {
final bool isManga; final bool isManga;
final Source source; final Source source;
const SourceListTile({super.key, required this.source, required this.isManga}); const SourceListTile(
{super.key, required this.source, required this.isManga});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListTile( return ListTile(
onTap: () { onTap: () {
final sources = isar.sources.filter().idIsNotNull().and().isMangaEqualTo(isManga).findAllSync(); final sources = isar.sources
.filter()
.idIsNotNull()
.and()
.isMangaEqualTo(isManga)
.findAllSync();
isar.writeTxnSync(() { isar.writeTxnSync(() {
for (var src in sources) { for (var src in sources) {
isar.sources.putSync(src..lastUsed = src.id == source.id ? true : false); isar.sources
.putSync(src..lastUsed = src.id == source.id ? true : false);
} }
}); });
@ -31,7 +38,8 @@ class SourceListTile extends StatelessWidget {
height: 37, height: 37,
width: 37, width: 37,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5), color:
Theme.of(context).secondaryHeaderColor.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(5)), borderRadius: BorderRadius.circular(5)),
child: source.iconUrl!.isEmpty child: source.iconUrl!.isEmpty
? const Icon(Icons.extension_rounded) ? const Icon(Icons.extension_rounded)
@ -68,8 +76,10 @@ class SourceListTile extends StatelessWidget {
// final supportsLatest = ref.watch(supportsLatestProvider(source: source)); // final supportsLatest = ref.watch(supportsLatestProvider(source: source));
// if (supportsLatest) { // if (supportsLatest) {
return TextButton( return TextButton(
style: const ButtonStyle(padding: WidgetStatePropertyAll(EdgeInsets.all(10))), style: const ButtonStyle(
onPressed: () => context.push('/mangaHome', extra: (source, true)), padding: WidgetStatePropertyAll(EdgeInsets.all(10))),
onPressed: () =>
context.push('/mangaHome', extra: (source, true)),
child: Text(context.l10n.latest)); child: Text(context.l10n.latest));
// } // }
// return const SizedBox.shrink(); // return const SizedBox.shrink();
@ -79,7 +89,8 @@ class SourceListTile extends StatelessWidget {
IconButton( IconButton(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
onPressed: () { onPressed: () {
isar.writeTxnSync(() => isar.sources.putSync(source..isPinned = !source.isPinned!)); isar.writeTxnSync(() => isar.sources
.putSync(source..isPinned = !source.isPinned!));
}, },
icon: Icon( icon: Icon(
Icons.push_pin_outlined, Icons.push_pin_outlined,

View file

@ -28,7 +28,8 @@ class HistoryScreen extends ConsumerStatefulWidget {
ConsumerState<HistoryScreen> createState() => _HistoryScreenState(); ConsumerState<HistoryScreen> createState() => _HistoryScreenState();
} }
class _HistoryScreenState extends ConsumerState<HistoryScreen> with TickerProviderStateMixin { class _HistoryScreenState extends ConsumerState<HistoryScreen>
with TickerProviderStateMixin {
late TabController _tabBarController; late TabController _tabBarController;
@override @override
@ -88,7 +89,8 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> with TickerProvid
_isSearch = true; _isSearch = true;
}); });
}, },
icon: Icon(Icons.search, color: Theme.of(context).hintColor)), icon:
Icon(Icons.search, color: Theme.of(context).hintColor)),
IconButton( IconButton(
splashRadius: 20, splashRadius: 20,
onPressed: () { onPressed: () {
@ -117,8 +119,10 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> with TickerProvid
List<History> histories = isar.historys List<History> histories = isar.historys
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.chapter( .chapter((q) => q.manga((q) =>
(q) => q.manga((q) => q.isMangaEqualTo(_tabBarController.index == 0))) q.isMangaEqualTo(
_tabBarController.index ==
0)))
.findAllSync() .findAllSync()
.toList(); .toList();
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -137,7 +141,8 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> with TickerProvid
); );
}); });
}, },
icon: Icon(Icons.delete_sweep_outlined, color: Theme.of(context).hintColor)), icon: Icon(Icons.delete_sweep_outlined,
color: Theme.of(context).hintColor)),
], ],
bottom: TabBar( bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab, indicatorSize: TabBarIndicatorSize.tab,
@ -179,13 +184,16 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
final history = ref.watch(getAllHistoryStreamProvider(isManga: widget.isManga)); final history =
ref.watch(getAllHistoryStreamProvider(isManga: widget.isManga));
return Scaffold( return Scaffold(
body: history.when( body: history.when(
data: (data) { data: (data) {
final entries = data final entries = data
.where((element) => widget.query.isNotEmpty .where((element) => widget.query.isNotEmpty
? element.chapter.value!.manga.value!.name!.toLowerCase().contains(widget.query.toLowerCase()) ? element.chapter.value!.manga.value!.name!
.toLowerCase()
.contains(widget.query.toLowerCase())
: true) : true)
.toList(); .toList();
@ -195,7 +203,10 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
SliverGroupedListView<History, String>( SliverGroupedListView<History, String>(
elements: entries, elements: entries,
groupBy: (element) => dateFormat(element.date!, groupBy: (element) => dateFormat(element.date!,
context: context, ref: ref, forHistoryValue: true, useRelativeTimesTamps: false), context: context,
ref: ref,
forHistoryValue: true,
useRelativeTimesTamps: false),
groupSeparatorBuilder: (String groupByValue) => Padding( groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(bottom: 8, left: 12), padding: const EdgeInsets.only(bottom: 8, left: 12),
child: Row( child: Row(
@ -216,7 +227,8 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0)),
elevation: 0, elevation: 0,
shadowColor: Colors.transparent), shadowColor: Colors.transparent),
onPressed: () { onPressed: () {
@ -235,18 +247,26 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7)),
), ),
onPressed: () { onPressed: () {
context.push('/manga-reader/detail', extra: manga.id); context.push('/manga-reader/detail',
extra: manga.id);
}, },
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(7), borderRadius: BorderRadius.circular(7),
child: manga.customCoverImage != null child: manga.customCoverImage != null
? Image.memory(manga.customCoverImage as Uint8List) ? Image.memory(
manga.customCoverImage as Uint8List)
: cachedNetworkImage( : cachedNetworkImage(
headers: ref.watch(headersProvider(source: manga.source!, lang: manga.lang!)), headers: ref.watch(headersProvider(
imageUrl: toImgUrl(manga.customCoverFromTracker ?? manga.imageUrl ?? ""), source: manga.source!,
lang: manga.lang!)),
imageUrl: toImgUrl(
manga.customCoverFromTracker ??
manga.imageUrl ??
""),
width: 60, width: 60,
height: 90, height: 90,
fit: BoxFit.cover), fit: BoxFit.cover),
@ -262,33 +282,46 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment:
crossAxisAlignment: CrossAxisAlignment.start, MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Text( Text(
manga.name!, manga.name!,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
color: Theme.of(context).textTheme.bodyLarge!.color, color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
textAlign: TextAlign.start, textAlign: TextAlign.start,
), ),
Wrap( Wrap(
crossAxisAlignment: WrapCrossAlignment.end, crossAxisAlignment:
WrapCrossAlignment.end,
children: [ children: [
Text( Text(
chapter.name!, chapter.name!,
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
color: Theme.of(context).textTheme.bodyLarge!.color, color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
), ),
), ),
Text( Text(
" - ${dateFormatHour(element.date!, context)}", " - ${dateFormatHour(element.date!, context)}",
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
color: Theme.of(context).textTheme.bodyLarge!.color, color: Theme.of(context)
fontWeight: FontWeight.w400), .textTheme
.bodyLarge!
.color,
fontWeight:
FontWeight.w400),
), ),
], ],
), ),
@ -306,43 +339,73 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
title: Text( title: Text(
l10n.remove, l10n.remove,
), ),
content: Text(l10n.remove_history_msg), content: Text(
l10n.remove_history_msg),
actions: [ actions: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment:
MainAxisAlignment.end,
children: [ children: [
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(
context);
}, },
child: Text(l10n.cancel)), child: Text(
l10n.cancel)),
const SizedBox( const SizedBox(
width: 15, width: 15,
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
await manga.chapters.load(); await manga.chapters
final chapters = manga.chapters; .load();
await isar.writeTxn(() async { final chapters =
await isar.historys.delete(element.id!); manga.chapters;
for (var chapter in chapters) { await isar.writeTxn(
() async {
await isar
.historys
.delete(
element
.id!);
for (var chapter
in chapters) {
await ref await ref
.read(changedItemsManagerProvider(managerId: 1) .read(changedItemsManagerProvider(
managerId:
1)
.notifier) .notifier)
.addUpdatedChapterAsync(chapter, true, false); .addUpdatedChapterAsync(
await isar.chapters.delete(chapter.id!); chapter,
true,
false);
await isar
.chapters
.delete(
chapter
.id!);
} }
await ref await ref
.read(changedItemsManagerProvider(managerId: 1) .read(changedItemsManagerProvider(
managerId:
1)
.notifier) .notifier)
.addDeletedMangaAsync(manga, false); .addDeletedMangaAsync(
await isar.mangas.delete(manga.id!); manga,
false);
await isar.mangas
.delete(manga
.id!);
}); });
if (context.mounted) { if (context
Navigator.pop(context); .mounted) {
Navigator.pop(
context);
} }
}, },
child: Text(l10n.remove)), child: Text(
l10n.remove)),
], ],
) )
], ],
@ -352,7 +415,10 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
icon: Icon( icon: Icon(
Icons.delete_outline, Icons.delete_outline,
size: 25, size: 25,
color: Theme.of(context).textTheme.bodyLarge!.color, color: Theme.of(context)
.textTheme
.bodyLarge!
.color,
)), )),
], ],
), ),
@ -363,7 +429,8 @@ class _HistoryTabState extends ConsumerState<HistoryTab> {
), ),
); );
}, },
itemComparator: (item1, item2) => item1.date!.compareTo(item2.date!), itemComparator: (item1, item2) =>
item1.date!.compareTo(item2.date!),
order: GroupedListOrder.DESC, order: GroupedListOrder.DESC,
), ),
], ],

View file

@ -9,7 +9,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'isar_providers.g.dart'; part 'isar_providers.g.dart';
@riverpod @riverpod
Stream<List<History>> getAllHistoryStream(Ref ref, {required bool isManga}) async* { Stream<List<History>> getAllHistoryStream(Ref ref,
{required bool isManga}) async* {
yield* isar.historys yield* isar.historys
.filter() .filter()
.idIsNotNull() .idIsNotNull()
@ -19,7 +20,8 @@ Stream<List<History>> getAllHistoryStream(Ref ref, {required bool isManga}) asyn
} }
@riverpod @riverpod
Stream<List<Update>> getAllUpdateStream(Ref ref, {required bool isManga}) async* { Stream<List<Update>> getAllUpdateStream(Ref ref,
{required bool isManga}) async* {
yield* isar.updates yield* isar.updates
.filter() .filter()
.idIsNotNull() .idIsNotNull()

View file

@ -8,7 +8,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/eval/dart/model/m_bridge.dart'; import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/category.dart'; import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
@ -1115,7 +1115,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
type: fromLibList.isNotEmpty ? 1 : 0, type: fromLibList.isNotEmpty ? 1 : 0,
), ),
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga ? l10n.downloaded_chapters : l10n.downloaded_episodes, label: widget.isManga
? l10n.downloaded_chapters
: l10n.downloaded_episodes,
onTap: () { onTap: () {
setState(() { setState(() {
if (downloadedChapsList == mangaIdsList) { if (downloadedChapsList == mangaIdsList) {
@ -1516,7 +1518,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
child: Column( child: Column(
children: [ children: [
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga ? l10n.downloaded_chapters : l10n.downloaded_episodes, label: widget.isManga
? l10n.downloaded_chapters
: l10n.downloaded_episodes,
type: downloadedChapter ? 1 : 0, type: downloadedChapter ? 1 : 0,
onTap: () { onTap: () {
ref ref
@ -1549,7 +1553,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.set(!localSource); .set(!localSource);
}), }),
ListTileChapterFilter( ListTileChapterFilter(
label: widget.isManga ? l10n.show_continue_reading_buttons : l10n.show_continue_watching_buttons, label: widget.isManga
? l10n.show_continue_reading_buttons
: l10n.show_continue_watching_buttons,
type: continueReaderBtn ? 1 : 0, type: continueReaderBtn ? 1 : 0,
onTap: () { onTap: () {
ref ref
@ -1648,7 +1654,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
child: AppBar( child: AppBar(
title: Text(mangaIdsList.length.toString()), title: Text(mangaIdsList.length.toString()),
backgroundColor: context.primaryColor.withValues(alpha: 0.2), backgroundColor:
context.primaryColor.withValues(alpha: 0.2),
leading: IconButton( leading: IconButton(
onPressed: () { onPressed: () {
ref.read(mangasListStateProvider.notifier).clear(); ref.read(mangasListStateProvider.notifier).clear();

View file

@ -8,17 +8,23 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'add_torrent.g.dart'; part 'add_torrent.g.dart';
@riverpod @riverpod
Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga, {required bool init, String? url}) async { Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga,
{required bool init, String? url}) async {
FilePickerResult? result; FilePickerResult? result;
if (url == null) { if (url == null) {
result = result = await FilePicker.platform.pickFiles(
await FilePicker.platform.pickFiles(allowMultiple: true, type: FileType.custom, allowedExtensions: ['torrent']); allowMultiple: true,
type: FileType.custom,
allowedExtensions: ['torrent']);
} }
if (result != null || url != null) { if (result != null || url != null) {
String torrentName = ""; String torrentName = "";
if (url != null) { if (url != null) {
torrentName = (await MTorrentServer().getTorrentPlaylist(url, null)).$1.first.quality; torrentName = (await MTorrentServer().getTorrentPlaylist(url, null))
.$1
.first
.quality;
} }
final dateNow = DateTime.now().millisecondsSinceEpoch; final dateNow = DateTime.now().millisecondsSinceEpoch;
final manga = mManga ?? final manga = mManga ??
@ -43,7 +49,8 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga, {required bool init,
manga.customCoverImage = null; manga.customCoverImage = null;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.mangas.putSync(manga); isar.mangas.putSync(manga);
final chapters = Chapter(name: torrentName, url: url, mangaId: manga.id)..manga.value = manga; final chapters = Chapter(name: torrentName, url: url, mangaId: manga.id)
..manga.value = manga;
isar.chapters.putSync(chapters); isar.chapters.putSync(chapters);
chapters.manga.saveSync(); chapters.manga.saveSync();
}); });
@ -57,7 +64,9 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga, {required bool init,
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.mangas.putSync(manga); isar.mangas.putSync(manga);
final chapters = Chapter(name: name, archivePath: file.path, mangaId: manga.id)..manga.value = manga; final chapters =
Chapter(name: name, archivePath: file.path, mangaId: manga.id)
..manga.value = manga;
isar.chapters.putSync(chapters); isar.chapters.putSync(chapters);
chapters.manga.saveSync(); chapters.manga.saveSync();
}); });
@ -68,10 +77,6 @@ Future addTorrentFromUrlOrFromFile(Ref ref, Manga? mManga, {required bool init,
} }
String _getName(String path) { String _getName(String path) {
return path return path.split('/').last.split("\\").last.replaceAll(
.split('/') RegExp(r'\.(mp4|mov|avi|flv|wmv|mpeg|mkv|cbz|zip|cbt|tar|torrent)'), '');
.last
.split("\\")
.last
.replaceAll(RegExp(r'\.(mp4|mov|avi|flv|wmv|mpeg|mkv|cbz|zip|cbt|tar|torrent)'), '');
} }

View file

@ -7,7 +7,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'isar_providers.g.dart'; part 'isar_providers.g.dart';
@riverpod @riverpod
Stream<List<Manga>> getAllMangaStream(Ref ref, {required int? categoryId, required bool? isManga}) async* { Stream<List<Manga>> getAllMangaStream(Ref ref,
{required int? categoryId, required bool? isManga}) async* {
yield* categoryId == null yield* categoryId == null
? isar.mangas ? isar.mangas
.filter() .filter()
@ -28,7 +29,8 @@ Stream<List<Manga>> getAllMangaStream(Ref ref, {required int? categoryId, requir
} }
@riverpod @riverpod
Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref, {required bool? isManga}) async* { Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref,
{required bool? isManga}) async* {
yield* isar.mangas yield* isar.mangas
.filter() .filter()
.idIsNotNull() .idIsNotNull()
@ -47,5 +49,10 @@ Stream<List<Manga>> getAllMangaWithoutCategoriesStream(Ref ref, {required bool?
@riverpod @riverpod
Stream<List<Settings>> getSettingsStream(Ref ref) async* { Stream<List<Settings>> getSettingsStream(Ref ref) async* {
yield* isar.settings.filter().idIsNotNull().and().idEqualTo(227).watch(fireImmediately: true); yield* isar.settings
.filter()
.idIsNotNull()
.and()
.idEqualTo(227)
.watch(fireImmediately: true);
} }

View file

@ -16,7 +16,8 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
return isManga ? settings.displayType : settings.animeDisplayType; return isManga ? settings.displayType : settings.animeDisplayType;
} }
String getLibraryDisplayTypeName(DisplayType displayType, BuildContext context) { String getLibraryDisplayTypeName(
DisplayType displayType, BuildContext context) {
final l10n = context.l10n; final l10n = context.l10n;
return switch (displayType) { return switch (displayType) {
DisplayType.compactGrid => l10n.compact_grid, DisplayType.compactGrid => l10n.compact_grid,
@ -74,13 +75,18 @@ class LibraryGridSizeState extends _$LibraryGridSizeState {
@riverpod @riverpod
class MangaFilterDownloadedState extends _$MangaFilterDownloadedState { class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@override @override
int build({required List<Manga> mangaList, required bool isManga, required Settings settings}) { int build(
{required List<Manga> mangaList,
required bool isManga,
required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga ? settings.libraryFilterMangasDownloadType! : settings.libraryFilterAnimeDownloadType ?? 0; return isManga
? settings.libraryFilterMangasDownloadType!
: settings.libraryFilterAnimeDownloadType ?? 0;
} }
void setType(int type) { void setType(int type) {
@ -110,13 +116,18 @@ class MangaFilterDownloadedState extends _$MangaFilterDownloadedState {
@riverpod @riverpod
class MangaFilterUnreadState extends _$MangaFilterUnreadState { class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@override @override
int build({required List<Manga> mangaList, required bool isManga, required Settings settings}) { int build(
{required List<Manga> mangaList,
required bool isManga,
required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga ? settings.libraryFilterMangasUnreadType! : settings.libraryFilterAnimeUnreadType ?? 0; return isManga
? settings.libraryFilterMangasUnreadType!
: settings.libraryFilterAnimeUnreadType ?? 0;
} }
void setType(int type) { void setType(int type) {
@ -195,13 +206,18 @@ class MangaFilterUnreadState extends _$MangaFilterUnreadState {
@riverpod @riverpod
class MangaFilterStartedState extends _$MangaFilterStartedState { class MangaFilterStartedState extends _$MangaFilterStartedState {
@override @override
int build({required List<Manga> mangaList, required bool isManga, required Settings settings}) { int build(
{required List<Manga> mangaList,
required bool isManga,
required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga ? settings.libraryFilterMangasStartedType! : settings.libraryFilterAnimeStartedType ?? 0; return isManga
? settings.libraryFilterMangasStartedType!
: settings.libraryFilterAnimeStartedType ?? 0;
} }
void setType(int type) { void setType(int type) {
@ -280,13 +296,18 @@ class MangaFilterStartedState extends _$MangaFilterStartedState {
@riverpod @riverpod
class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState { class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@override @override
int build({required List<Manga> mangaList, required bool isManga, required Settings settings}) { int build(
{required List<Manga> mangaList,
required bool isManga,
required Settings settings}) {
state = getType(); state = getType();
return getType(); return getType();
} }
int getType() { int getType() {
return isManga ? settings.libraryFilterMangasBookMarkedType! : settings.libraryFilterAnimeBookMarkedType ?? 0; return isManga
? settings.libraryFilterMangasBookMarkedType!
: settings.libraryFilterAnimeBookMarkedType ?? 0;
} }
void setType(int type) { void setType(int type) {
@ -365,16 +386,22 @@ class MangaFilterBookmarkedState extends _$MangaFilterBookmarkedState {
@riverpod @riverpod
class MangasFilterResultState extends _$MangasFilterResultState { class MangasFilterResultState extends _$MangasFilterResultState {
@override @override
bool build({required List<Manga> mangaList, required bool isManga, required Settings settings}) { bool build(
final downloadFilterType = {required List<Manga> mangaList,
ref.watch(mangaFilterDownloadedStateProvider(mangaList: mangaList, isManga: isManga, settings: settings)); required bool isManga,
final unreadFilterType = required Settings settings}) {
ref.watch(mangaFilterUnreadStateProvider(mangaList: mangaList, isManga: isManga, settings: settings)); final downloadFilterType = ref.watch(mangaFilterDownloadedStateProvider(
final startedFilterType = mangaList: mangaList, isManga: isManga, settings: settings));
ref.watch(mangaFilterStartedStateProvider(mangaList: mangaList, isManga: isManga, settings: settings)); final unreadFilterType = ref.watch(mangaFilterUnreadStateProvider(
final bookmarkedFilterType = mangaList: mangaList, isManga: isManga, settings: settings));
ref.watch(mangaFilterBookmarkedStateProvider(mangaList: mangaList, isManga: isManga, settings: settings)); final startedFilterType = ref.watch(mangaFilterStartedStateProvider(
return downloadFilterType == 0 && unreadFilterType == 0 && startedFilterType == 0 && bookmarkedFilterType == 0; mangaList: mangaList, isManga: isManga, settings: settings));
final bookmarkedFilterType = ref.watch(mangaFilterBookmarkedStateProvider(
mangaList: mangaList, isManga: isManga, settings: settings));
return downloadFilterType == 0 &&
unreadFilterType == 0 &&
startedFilterType == 0 &&
bookmarkedFilterType == 0;
} }
} }
@ -382,7 +409,9 @@ class MangasFilterResultState extends _$MangasFilterResultState {
class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState { class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required bool isManga, required Settings settings}) {
return isManga ? settings.libraryShowCategoryTabs! : settings.animeLibraryShowCategoryTabs ?? false; return isManga
? settings.libraryShowCategoryTabs!
: settings.animeLibraryShowCategoryTabs ?? false;
} }
void set(bool value) { void set(bool value) {
@ -403,7 +432,9 @@ class LibraryShowCategoryTabsState extends _$LibraryShowCategoryTabsState {
class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState { class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required bool isManga, required Settings settings}) {
return isManga ? settings.libraryDownloadedChapters! : settings.animeLibraryDownloadedChapters ?? false; return isManga
? settings.libraryDownloadedChapters!
: settings.animeLibraryDownloadedChapters ?? false;
} }
void set(bool value) { void set(bool value) {
@ -424,7 +455,9 @@ class LibraryDownloadedChaptersState extends _$LibraryDownloadedChaptersState {
class LibraryLanguageState extends _$LibraryLanguageState { class LibraryLanguageState extends _$LibraryLanguageState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required bool isManga, required Settings settings}) {
return isManga ? settings.libraryShowLanguage! : settings.animeLibraryShowLanguage ?? false; return isManga
? settings.libraryShowLanguage!
: settings.animeLibraryShowLanguage ?? false;
} }
void set(bool value) { void set(bool value) {
@ -445,7 +478,9 @@ class LibraryLanguageState extends _$LibraryLanguageState {
class LibraryLocalSourceState extends _$LibraryLocalSourceState { class LibraryLocalSourceState extends _$LibraryLocalSourceState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required bool isManga, required Settings settings}) {
return isManga ? settings.libraryLocalSource ?? false : settings.animeLibraryLocalSource ?? false; return isManga
? settings.libraryLocalSource ?? false
: settings.animeLibraryLocalSource ?? false;
} }
void set(bool value) { void set(bool value) {
@ -466,7 +501,9 @@ class LibraryLocalSourceState extends _$LibraryLocalSourceState {
class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState { class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required bool isManga, required Settings settings}) {
return isManga ? settings.libraryShowNumbersOfItems! : settings.animeLibraryShowNumbersOfItems ?? false; return isManga
? settings.libraryShowNumbersOfItems!
: settings.animeLibraryShowNumbersOfItems ?? false;
} }
void set(bool value) { void set(bool value) {
@ -484,7 +521,8 @@ class LibraryShowNumbersOfItemsState extends _$LibraryShowNumbersOfItemsState {
} }
@riverpod @riverpod
class LibraryShowContinueReadingButtonState extends _$LibraryShowContinueReadingButtonState { class LibraryShowContinueReadingButtonState
extends _$LibraryShowContinueReadingButtonState {
@override @override
bool build({required bool isManga, required Settings settings}) { bool build({required bool isManga, required Settings settings}) {
return isManga return isManga
@ -510,7 +548,9 @@ class LibraryShowContinueReadingButtonState extends _$LibraryShowContinueReading
class SortLibraryMangaState extends _$SortLibraryMangaState { class SortLibraryMangaState extends _$SortLibraryMangaState {
@override @override
SortLibraryManga build({required bool isManga, required Settings settings}) { SortLibraryManga build({required bool isManga, required Settings settings}) {
return isManga ? settings.sortLibraryManga ?? SortLibraryManga() : settings.sortLibraryAnime ?? SortLibraryManga(); return isManga
? settings.sortLibraryManga ?? SortLibraryManga()
: settings.sortLibraryAnime ?? SortLibraryManga();
} }
void update(bool reverse, int index) { void update(bool reverse, int index) {
@ -611,7 +651,9 @@ class MangasSetIsReadState extends _$MangasSetIsReadState {
for (var chapter in chapters) { for (var chapter in chapters) {
chapter.isRead = true; chapter.isRead = true;
chapter.lastPageRead = "1"; chapter.lastPageRead = "1";
ref.read(changedItemsManagerProvider(managerId: 1).notifier).addUpdatedChapter(chapter, false, false); ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(chapter, false, false);
isar.chapters.putSync(chapter..manga.value = manga); isar.chapters.putSync(chapter..manga.value = manga);
chapter.manga.saveSync(); chapter.manga.saveSync();
} }
@ -636,7 +678,9 @@ class MangasSetUnReadState extends _$MangasSetUnReadState {
isar.writeTxnSync(() { isar.writeTxnSync(() {
for (var chapter in chapters) { for (var chapter in chapters) {
chapter.isRead = false; chapter.isRead = false;
ref.read(changedItemsManagerProvider(managerId: 1).notifier).addUpdatedChapter(chapter, false, false); ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(chapter, false, false);
isar.chapters.putSync(chapter..manga.value = manga); isar.chapters.putSync(chapter..manga.value = manga);
chapter.manga.saveSync(); chapter.manga.saveSync();
} }

View file

@ -10,11 +10,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'local_archive.g.dart'; part 'local_archive.g.dart';
@riverpod @riverpod
Future importArchivesFromFile(Ref ref, Manga? mManga, {required bool isManga, required bool init}) async { Future importArchivesFromFile(Ref ref, Manga? mManga,
{required bool isManga, required bool init}) async {
FilePickerResult? result = await FilePicker.platform.pickFiles( FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true, allowMultiple: true,
type: FileType.custom, type: FileType.custom,
allowedExtensions: isManga ? ['cbz', 'zip'] : ['mp4', 'mov', 'avi', 'flv', 'wmv', 'mpeg', 'mkv']); allowedExtensions: isManga
? ['cbz', 'zip']
: ['mp4', 'mov', 'avi', 'flv', 'wmv', 'mpeg', 'mkv']);
if (result != null) { if (result != null) {
final dateNow = DateTime.now().millisecondsSinceEpoch; final dateNow = DateTime.now().millisecondsSinceEpoch;
final manga = mManga ?? final manga = mManga ??
@ -36,8 +39,9 @@ Future importArchivesFromFile(Ref ref, Manga? mManga, {required bool isManga, re
artist: '', artist: '',
); );
for (var file in result.files.reversed.toList()) { for (var file in result.files.reversed.toList()) {
(String, LocalExtensionType, Uint8List, String)? data = (String, LocalExtensionType, Uint8List, String)? data = isManga
isManga ? await ref.watch(getArchivesDataFromFileProvider(file.path!).future) : null; ? await ref.watch(getArchivesDataFromFileProvider(file.path!).future)
: null;
String name = _getName(file.path!); String name = _getName(file.path!);
if (init) { if (init) {
@ -46,9 +50,11 @@ Future importArchivesFromFile(Ref ref, Manga? mManga, {required bool isManga, re
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.mangas.putSync(manga); isar.mangas.putSync(manga);
final chapters = final chapters = Chapter(
Chapter(name: isManga ? data!.$1 : name, archivePath: isManga ? data!.$4 : file.path, mangaId: manga.id) name: isManga ? data!.$1 : name,
..manga.value = manga; archivePath: isManga ? data!.$4 : file.path,
mangaId: manga.id)
..manga.value = manga;
isar.chapters.putSync(chapters); isar.chapters.putSync(chapters);
chapters.manga.saveSync(); chapters.manga.saveSync();
}); });
@ -58,10 +64,6 @@ Future importArchivesFromFile(Ref ref, Manga? mManga, {required bool isManga, re
} }
String _getName(String path) { String _getName(String path) {
return path return path.split('/').last.split("\\").last.replaceAll(
.split('/') RegExp(r'\.(mp4|mov|avi|flv|wmv|mpeg|mkv|cbz|zip|cbt|tar)'), '');
.last
.split("\\")
.last
.replaceAll(RegExp(r'\.(mp4|mov|avi|flv|wmv|mpeg|mkv|cbz|zip|cbt|tar)'), '');
} }

View file

@ -53,7 +53,8 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
final isLongPressed = ref.watch(isLongPressedMangaStateProvider); final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
final isManga = widget.isManga; final isManga = widget.isManga;
final gridSize = ref.watch(libraryGridSizeStateProvider(isManga: isManga)); final gridSize =
ref.watch(libraryGridSizeStateProvider(isManga: isManga));
return GridViewWidget( return GridViewWidget(
gridSize: gridSize, gridSize: gridSize,
childAspectRatio: widget.isComfortableGrid ? 0.642 : 0.69, childAspectRatio: widget.isComfortableGrid ? 0.642 : 0.69,
@ -74,12 +75,16 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
), ),
isComfortableGrid: widget.isComfortableGrid, isComfortableGrid: widget.isComfortableGrid,
image: entry.customCoverImage != null image: entry.customCoverImage != null
? MemoryImage(entry.customCoverImage as Uint8List) as ImageProvider ? MemoryImage(entry.customCoverImage as Uint8List)
as ImageProvider
: CustomExtendedNetworkImageProvider( : CustomExtendedNetworkImageProvider(
toImgUrl(entry.customCoverFromTracker ?? entry.imageUrl ?? ""), toImgUrl(entry.customCoverFromTracker ??
entry.imageUrl ??
""),
headers: entry.isLocalArchive! headers: entry.isLocalArchive!
? null ? null
: ref.watch(headersProvider(source: entry.source!, lang: entry.lang!)), : ref.watch(headersProvider(
source: entry.source!, lang: entry.lang!)),
), ),
onTap: () async { onTap: () async {
if (isLongPressed) { if (isLongPressed) {
@ -91,15 +96,19 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
lang: entry.lang!, lang: entry.lang!,
mangaM: entry, mangaM: entry,
source: entry.source!); source: entry.source!);
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(isManga: widget.isManga)); ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(
ref.invalidate(getAllMangaStreamProvider(categoryId: null, isManga: widget.isManga)); isManga: widget.isManga));
ref.invalidate(getAllMangaStreamProvider(
categoryId: null, isManga: widget.isManga));
} }
}, },
onLongPress: () { onLongPress: () {
if (!isLongPressed) { if (!isLongPressed) {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
ref.read(isLongPressedMangaStateProvider.notifier).update(!isLongPressed); ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else { } else {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
} }
@ -108,7 +117,9 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
if (!isLongPressed) { if (!isLongPressed) {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
ref.read(isLongPressedMangaStateProvider.notifier).update(!isLongPressed); ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else { } else {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
} }
@ -132,14 +143,18 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(3), bottomLeft: Radius.circular(3)), topLeft: Radius.circular(3),
bottomLeft: Radius.circular(3)),
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3), padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text( child: Text(
"Local", "Local",
style: TextStyle(color: context.dynamicBlackWhiteColor), style: TextStyle(
color: context
.dynamicBlackWhiteColor),
), ),
), ),
), ),
@ -150,14 +165,20 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
List nbrDown = []; List nbrDown = [];
if (widget.downloadedChapter) { if (widget.downloadedChapter) {
isar.txnSync(() { isar.txnSync(() {
for (var i = 0; i < entry.chapters.length; i++) { for (var i = 0;
i < entry.chapters.length;
i++) {
final entries = isar.downloads final entries = isar.downloads
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.chapterIdEqualTo(entry.chapters.toList()[i].id) .chapterIdEqualTo(entry
.chapters
.toList()[i]
.id)
.findAllSync(); .findAllSync();
if (entries.isNotEmpty && entries.first.isDownload!) { if (entries.isNotEmpty &&
entries.first.isDownload!) {
nbrDown.add(1); nbrDown.add(1);
} }
} }
@ -166,25 +187,42 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
return Row( return Row(
children: [ children: [
if (nbrDown.isNotEmpty && widget.downloadedChapter) if (nbrDown.isNotEmpty &&
widget.downloadedChapter)
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius:
topLeft: Radius.circular(3), bottomLeft: Radius.circular(3)), const BorderRadius.only(
color: Theme.of(context).secondaryHeaderColor, topLeft:
Radius.circular(
3),
bottomLeft:
Radius.circular(
3)),
color: Theme.of(context)
.secondaryHeaderColor,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3), padding:
const EdgeInsets.only(
left: 3, right: 3),
child: Text( child: Text(
nbrDown.length.toString(), nbrDown.length.toString(),
), ),
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 3), padding: const EdgeInsets.only(
left: 3),
child: Text( child: Text(
entry.chapters.where((element) => !element.isRead!).length.toString(), entry.chapters
style: TextStyle(color: context.dynamicBlackWhiteColor), .where((element) =>
!element.isRead!)
.length
.toString(),
style: TextStyle(
color: context
.dynamicBlackWhiteColor),
), ),
), ),
], ],
@ -207,14 +245,17 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(3), bottomLeft: Radius.circular(3)), topLeft: Radius.circular(3),
bottomLeft: Radius.circular(3)),
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3), padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text( child: Text(
entry.lang!.toUpperCase(), entry.lang!.toUpperCase(),
style: const TextStyle(color: Colors.white), style:
const TextStyle(color: Colors.white),
), ),
), ),
), ),
@ -222,7 +263,8 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
)), )),
], ],
), ),
if (!widget.isComfortableGrid && !widget.isCoverOnlyGrid) BottomTextWidget(text: entry.name!), if (!widget.isComfortableGrid && !widget.isCoverOnlyGrid)
BottomTextWidget(text: entry.name!),
if (widget.continueReaderBtn) if (widget.continueReaderBtn)
Positioned( Positioned(
bottom: 0, bottom: 0,
@ -236,22 +278,31 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga((q) => q.isMangaEqualTo(entry.isManga!))) .chapter((q) => q.manga((q) =>
q.isMangaEqualTo(entry.isManga!)))
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData &&
final incognitoMode = ref.watch(incognitoModeStateProvider); snapshot.data!.isNotEmpty) {
final entries = final incognitoMode =
snapshot.data!.where((element) => element.mangaId == entry.id).toList(); ref.watch(incognitoModeStateProvider);
if (entries.isNotEmpty && !incognitoMode) { final entries = snapshot.data!
.where((element) =>
element.mangaId == entry.id)
.toList();
if (entries.isNotEmpty &&
!incognitoMode) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
entries.first.chapter.value!.pushToReaderView(context); entries.first.chapter.value!
.pushToReaderView(context);
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius:
color: context.primaryColor.withValues(alpha: 0.9), BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(7), padding: EdgeInsets.all(7),
@ -265,12 +316,19 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
} }
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
entry.chapters.toList().reversed.toList().last.pushToReaderView(context); entry.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius:
color: context.primaryColor.withValues(alpha: 0.9), BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(7), padding: EdgeInsets.all(7),
@ -284,12 +342,19 @@ class _LibraryGridViewWidgetState extends State<LibraryGridViewWidget> {
} }
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
entry.chapters.toList().reversed.toList().last.pushToReaderView(context); entry.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius:
color: context.primaryColor.withValues(alpha: 0.9), BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(7), padding: EdgeInsets.all(7),

View file

@ -58,15 +58,19 @@ class LibraryListViewWidget extends StatelessWidget {
lang: entry.lang!, lang: entry.lang!,
mangaM: entry, mangaM: entry,
source: entry.source!); source: entry.source!);
ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(isManga: entry.isManga)); ref.invalidate(getAllMangaWithoutCategoriesStreamProvider(
ref.invalidate(getAllMangaStreamProvider(categoryId: null, isManga: entry.isManga)); isManga: entry.isManga));
ref.invalidate(getAllMangaStreamProvider(
categoryId: null, isManga: entry.isManga));
} }
}, },
onLongPress: () { onLongPress: () {
if (!isLongPressed) { if (!isLongPressed) {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
ref.read(isLongPressedMangaStateProvider.notifier).update(!isLongPressed); ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else { } else {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
} }
@ -75,19 +79,24 @@ class LibraryListViewWidget extends StatelessWidget {
if (!isLongPressed) { if (!isLongPressed) {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
ref.read(isLongPressedMangaStateProvider.notifier).update(!isLongPressed); ref
.read(isLongPressedMangaStateProvider.notifier)
.update(!isLongPressed);
} else { } else {
ref.read(mangasListStateProvider.notifier).update(entry); ref.read(mangasListStateProvider.notifier).update(entry);
} }
}, },
child: Container( child: Container(
color: color: mangaIdsList.contains(entry.id)
mangaIdsList.contains(entry.id) ? context.primaryColor.withValues(alpha: 0.4) : Colors.transparent, ? context.primaryColor.withValues(alpha: 0.4)
: Colors.transparent,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
child: Container( child: Container(
height: 45, height: 45,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5)), decoration:
BoxDecoration(borderRadius: BorderRadius.circular(5)),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -102,16 +111,21 @@ class LibraryListViewWidget extends StatelessWidget {
width: 40, width: 40,
height: 45, height: 45,
image: entry.customCoverImage != null image: entry.customCoverImage != null
? MemoryImage(entry.customCoverImage as Uint8List) as ImageProvider ? MemoryImage(entry.customCoverImage
as Uint8List) as ImageProvider
: CustomExtendedNetworkImageProvider( : CustomExtendedNetworkImageProvider(
toImgUrl(entry.customCoverFromTracker ?? entry.imageUrl!), toImgUrl(
headers: entry.customCoverFromTracker ??
ref.watch(headersProvider(source: entry.source!, lang: entry.lang!)), entry.imageUrl!),
headers: ref.watch(headersProvider(
source: entry.source!,
lang: entry.lang!)),
), ),
child: InkWell( child: InkWell(
child: Container( child: Container(
color: mangaIdsList.contains(entry.id) color: mangaIdsList.contains(entry.id)
? context.primaryColor.withValues(alpha: 0.4) ? context.primaryColor
.withValues(alpha: 0.4)
: Colors.transparent, : Colors.transparent,
)), )),
), ),
@ -119,7 +133,8 @@ class LibraryListViewWidget extends StatelessWidget {
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10), padding: const EdgeInsets.symmetric(
horizontal: 10),
child: Text(entry.name!), child: Text(entry.name!),
), ),
) )
@ -129,8 +144,9 @@ class LibraryListViewWidget extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Container( child: Container(
decoration: decoration: BoxDecoration(
BoxDecoration(borderRadius: BorderRadius.circular(3), color: context.primaryColor), borderRadius: BorderRadius.circular(3),
color: context.primaryColor),
child: SizedBox( child: SizedBox(
height: 22, height: 22,
child: Row( child: Row(
@ -139,11 +155,13 @@ class LibraryListViewWidget extends StatelessWidget {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(3), bottomLeft: Radius.circular(3)), topLeft: Radius.circular(3),
bottomLeft: Radius.circular(3)),
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.only(left: 3, right: 3), padding:
EdgeInsets.only(left: 3, right: 3),
child: Text( child: Text(
"Local", "Local",
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
@ -157,14 +175,20 @@ class LibraryListViewWidget extends StatelessWidget {
builder: (context, ref, child) { builder: (context, ref, child) {
List nbrDown = []; List nbrDown = [];
isar.txnSync(() { isar.txnSync(() {
for (var i = 0; i < entry.chapters.length; i++) { for (var i = 0;
i < entry.chapters.length;
i++) {
final entries = isar.downloads final entries = isar.downloads
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.chapterIdEqualTo(entry.chapters.toList()[i].id) .chapterIdEqualTo(entry
.chapters
.toList()[i]
.id)
.findAllSync(); .findAllSync();
if (entries.isNotEmpty && entries.first.isDownload!) { if (entries.isNotEmpty &&
entries.first.isDownload!) {
nbrDown.add(entries.first); nbrDown.add(entries.first);
} }
} }
@ -172,15 +196,22 @@ class LibraryListViewWidget extends StatelessWidget {
if (nbrDown.isNotEmpty) { if (nbrDown.isNotEmpty) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius:
topLeft: Radius.circular(3), bottomLeft: Radius.circular(3)), const BorderRadius.only(
color: Theme.of(context).hintColor, topLeft:
Radius.circular(3),
bottomLeft:
Radius.circular(3)),
color:
Theme.of(context).hintColor,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3), padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text( child: Text(
nbrDown.length.toString(), nbrDown.length.toString(),
style: const TextStyle(color: Colors.white), style: const TextStyle(
color: Colors.white),
), ),
), ),
); );
@ -194,7 +225,8 @@ class LibraryListViewWidget extends StatelessWidget {
padding: const EdgeInsets.only(right: 3), padding: const EdgeInsets.only(right: 3),
child: Text( child: Text(
entry.chapters.length.toString(), entry.chapters.length.toString(),
style: const TextStyle(color: Colors.white), style:
const TextStyle(color: Colors.white),
), ),
), ),
if (language && entry.lang!.isNotEmpty) if (language && entry.lang!.isNotEmpty)
@ -203,14 +235,17 @@ class LibraryListViewWidget extends StatelessWidget {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topRight: Radius.circular(3), bottomRight: Radius.circular(3)), topRight: Radius.circular(3),
bottomRight: Radius.circular(3)),
color: Theme.of(context).hintColor, color: Theme.of(context).hintColor,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 3, right: 3), padding: const EdgeInsets.only(
left: 3, right: 3),
child: Text( child: Text(
entry.lang!.toUpperCase(), entry.lang!.toUpperCase(),
style: const TextStyle(color: Colors.white), style: const TextStyle(
color: Colors.white),
), ),
), ),
), ),
@ -228,13 +263,18 @@ class LibraryListViewWidget extends StatelessWidget {
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga((q) => q.isMangaEqualTo(entry.isManga!))) .chapter((q) => q.manga((q) =>
q.isMangaEqualTo(entry.isManga!)))
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData &&
final incognitoMode = ref.watch(incognitoModeStateProvider); snapshot.data!.isNotEmpty) {
final entries = final incognitoMode =
snapshot.data!.where((element) => element.mangaId == entry.id).toList(); ref.watch(incognitoModeStateProvider);
final entries = snapshot.data!
.where((element) =>
element.mangaId == entry.id)
.toList();
if (entries.isNotEmpty && !incognitoMode) { if (entries.isNotEmpty && !incognitoMode) {
final chap = entries.first.chapter.value!; final chap = entries.first.chapter.value!;
return GestureDetector( return GestureDetector(
@ -243,8 +283,10 @@ class LibraryListViewWidget extends StatelessWidget {
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius:
color: context.primaryColor.withValues(alpha: 0.9), BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(7), padding: EdgeInsets.all(7),
@ -258,12 +300,19 @@ class LibraryListViewWidget extends StatelessWidget {
} }
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
entry.chapters.toList().reversed.toList().last.pushToReaderView(context); entry.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius:
color: context.primaryColor.withValues(alpha: 0.9), BorderRadius.circular(5),
color: context.primaryColor
.withValues(alpha: 0.9),
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(7), padding: EdgeInsets.all(7),
@ -277,12 +326,18 @@ class LibraryListViewWidget extends StatelessWidget {
} }
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
entry.chapters.toList().reversed.toList().last.pushToReaderView(context); entry.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
color: context.primaryColor.withValues(alpha: 0.9), color: context.primaryColor
.withValues(alpha: 0.9),
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.all(7), padding: EdgeInsets.all(7),

View file

@ -26,7 +26,9 @@ class _ListTileMangaCategoryState extends State<ListTileMangaCategory> {
void initState() { void initState() {
final res = widget.mangasList.where( final res = widget.mangasList.where(
(element) { (element) {
return element.categories == null ? false : element.categories!.contains(widget.category.id); return element.categories == null
? false
: element.categories!.contains(widget.category.id);
}, },
).toList(); ).toList();
widget.res(res); widget.res(res);

View file

@ -35,8 +35,10 @@ class SeachFormTextField extends StatelessWidget {
icon: const Icon( icon: const Icon(
Icons.arrow_back, Icons.arrow_back,
)), )),
suffixIcon: suffixIcon: controller.text.isEmpty
controller.text.isEmpty ? null : IconButton(onPressed: onSuffixPressed, icon: const Icon(Icons.clear)), ? null
: IconButton(
onPressed: onSuffixPressed, icon: const Icon(Icons.clear)),
enabledBorder: const OutlineInputBorder( enabledBorder: const OutlineInputBorder(
borderSide: BorderSide.none, borderSide: BorderSide.none,
), ),

View file

@ -54,7 +54,8 @@ class MainScreen extends ConsumerWidget {
final location = ref.watch( final location = ref.watch(
routerCurrentLocationStateProvider(context), routerCurrentLocationStateProvider(context),
); );
bool isReadingScreen = location == '/mangareaderview' || location == '/animePlayerView'; bool isReadingScreen =
location == '/mangareaderview' || location == '/animePlayerView';
int currentIndex = switch (location) { int currentIndex = switch (location) {
null || '/MangaLibrary' => 0, null || '/MangaLibrary' => 0,
'/AnimeLibrary' => 1, '/AnimeLibrary' => 1,
@ -122,7 +123,9 @@ class MainScreen extends ConsumerWidget {
children: [ children: [
NavigationRailTheme( NavigationRailTheme(
data: NavigationRailThemeData( data: NavigationRailThemeData(
indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), indicatorShape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(30)),
), ),
child: Builder(builder: (context) { child: Builder(builder: (context) {
return NavigationRail( return NavigationRail(
@ -130,46 +133,73 @@ class MainScreen extends ConsumerWidget {
useIndicator: true, useIndicator: true,
destinations: [ destinations: [
NavigationRailDestination( NavigationRailDestination(
selectedIcon: const Icon(Icons.collections_bookmark), selectedIcon: const Icon(
icon: const Icon(Icons.collections_bookmark_outlined), Icons.collections_bookmark),
icon: const Icon(Icons
.collections_bookmark_outlined),
label: Padding( label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.manga))), padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.manga))),
NavigationRailDestination( NavigationRailDestination(
selectedIcon: const Icon(Icons.video_collection), selectedIcon: const Icon(
icon: const Icon(Icons.video_collection_outlined), Icons.video_collection),
icon: const Icon(Icons
.video_collection_outlined),
label: Padding( label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.anime))), padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.anime))),
NavigationRailDestination( NavigationRailDestination(
selectedIcon: const Icon(Icons.new_releases), selectedIcon:
icon: const Icon(Icons.new_releases_outlined), const Icon(Icons.new_releases),
icon: const Icon(
Icons.new_releases_outlined),
label: Padding( label: Padding(
padding: const EdgeInsets.only(top: 5), padding: const EdgeInsets.only(
top: 5),
child: Stack( child: Stack(
children: [ children: [
Text( Text(
getHyphenatedUpdatesLabel( getHyphenatedUpdatesLabel(
ref.watch(l10nLocaleStateProvider).languageCode, ref
.watch(
l10nLocaleStateProvider)
.languageCode,
l10n.updates, l10n.updates,
), ),
textAlign: TextAlign.center, textAlign:
TextAlign.center,
), ),
], ],
))), ))),
NavigationRailDestination( NavigationRailDestination(
selectedIcon: const Icon(Icons.history), selectedIcon:
icon: const Icon(Icons.history_outlined), const Icon(Icons.history),
icon: const Icon(
Icons.history_outlined),
label: Padding( label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.history))), padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.history))),
NavigationRailDestination( NavigationRailDestination(
selectedIcon: const Icon(Icons.explore), selectedIcon:
icon: const Icon(Icons.explore_outlined), const Icon(Icons.explore),
icon: const Icon(
Icons.explore_outlined),
label: Padding( label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.browse))), padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.browse))),
NavigationRailDestination( NavigationRailDestination(
selectedIcon: const Icon(Icons.more_horiz), selectedIcon:
icon: const Icon(Icons.more_horiz_outlined), const Icon(Icons.more_horiz),
icon: const Icon(
Icons.more_horiz_outlined),
label: Padding( label: Padding(
padding: const EdgeInsets.only(top: 5), child: Text(l10n.more))), padding: const EdgeInsets.only(
top: 5),
child: Text(l10n.more))),
], ],
selectedIndex: currentIndex, selectedIndex: currentIndex,
onDestinationSelected: (newIndex) { onDestinationSelected: (newIndex) {
@ -186,8 +216,14 @@ class MainScreen extends ConsumerWidget {
); );
}), }),
), ),
Positioned(right: 18, top: 140, child: _updatesTotalNumbers(ref)), Positioned(
Positioned(right: 18, top: 275, child: _extensionUpdateTotalNumbers(ref)), right: 18,
top: 140,
child: _updatesTotalNumbers(ref)),
Positioned(
right: 18,
top: 275,
child: _extensionUpdateTotalNumbers(ref)),
], ],
), ),
), ),
@ -216,27 +252,38 @@ class MainScreen extends ConsumerWidget {
}, },
child: NavigationBarTheme( child: NavigationBarTheme(
data: NavigationBarThemeData( data: NavigationBarThemeData(
indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)),
), ),
child: NavigationBar( child: NavigationBar(
animationDuration: const Duration(milliseconds: 500), animationDuration:
const Duration(milliseconds: 500),
selectedIndex: currentIndex, selectedIndex: currentIndex,
destinations: [ destinations: [
NavigationDestination( NavigationDestination(
selectedIcon: const Icon(Icons.collections_bookmark), selectedIcon:
icon: const Icon(Icons.collections_bookmark_outlined), const Icon(Icons.collections_bookmark),
icon: const Icon(
Icons.collections_bookmark_outlined),
label: l10n.manga), label: l10n.manga),
NavigationDestination( NavigationDestination(
selectedIcon: const Icon(Icons.video_collection), selectedIcon:
icon: const Icon(Icons.video_collection_outlined), const Icon(Icons.video_collection),
icon: const Icon(
Icons.video_collection_outlined),
label: l10n.anime), label: l10n.anime),
Stack( Stack(
children: [ children: [
NavigationDestination( NavigationDestination(
selectedIcon: const Icon(Icons.new_releases), selectedIcon:
icon: const Icon(Icons.new_releases_outlined), const Icon(Icons.new_releases),
icon: const Icon(
Icons.new_releases_outlined),
label: l10n.updates), label: l10n.updates),
Positioned(right: 14, top: 3, child: _updatesTotalNumbers(ref)), Positioned(
right: 14,
top: 3,
child: _updatesTotalNumbers(ref)),
], ],
), ),
NavigationDestination( NavigationDestination(
@ -249,7 +296,10 @@ class MainScreen extends ConsumerWidget {
selectedIcon: const Icon(Icons.explore), selectedIcon: const Icon(Icons.explore),
icon: const Icon(Icons.explore_outlined), icon: const Icon(Icons.explore_outlined),
label: l10n.browse), label: l10n.browse),
Positioned(right: 14, top: 3, child: _extensionUpdateTotalNumbers(ref)), Positioned(
right: 14,
top: 3,
child: _extensionUpdateTotalNumbers(ref)),
], ],
), ),
NavigationDestination( NavigationDestination(
@ -286,21 +336,32 @@ class MainScreen extends ConsumerWidget {
Widget _extensionUpdateTotalNumbers(WidgetRef ref) { Widget _extensionUpdateTotalNumbers(WidgetRef ref) {
return StreamBuilder( return StreamBuilder(
stream: isar.sources.filter().idIsNotNull().and().isActiveEqualTo(true).watch(fireImmediately: true), stream: isar.sources
.filter()
.idIsNotNull()
.and()
.isActiveEqualTo(true)
.watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final entries = final entries = snapshot.data!
snapshot.data!.where((element) => compareVersions(element.version!, element.versionLast!) < 0).toList(); .where((element) =>
compareVersions(element.version!, element.versionLast!) < 0)
.toList();
return entries.isEmpty return entries.isEmpty
? Container() ? Container()
: Container( : Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), color: const Color.fromARGB(255, 176, 46, 37)), borderRadius: BorderRadius.circular(10),
color: const Color.fromARGB(255, 176, 46, 37)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 3), padding:
const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
child: Text( child: Text(
entries.length.toString(), entries.length.toString(),
style: TextStyle(fontSize: 10, color: Theme.of(context).textTheme.bodySmall!.color), style: TextStyle(
fontSize: 10,
color: Theme.of(context).textTheme.bodySmall!.color),
), ),
), ),
); );
@ -324,12 +385,16 @@ Widget _updatesTotalNumbers(WidgetRef ref) {
? Container() ? Container()
: Container( : Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), color: const Color.fromARGB(255, 176, 46, 37)), borderRadius: BorderRadius.circular(10),
color: const Color.fromARGB(255, 176, 46, 37)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 3), padding:
const EdgeInsets.symmetric(horizontal: 5, vertical: 3),
child: Text( child: Text(
entries.length.toString(), entries.length.toString(),
style: TextStyle(fontSize: 10, color: Theme.of(context).textTheme.bodySmall!.color), style: TextStyle(
fontSize: 10,
color: Theme.of(context).textTheme.bodySmall!.color),
), ),
), ),
); );

View file

@ -11,11 +11,20 @@ part 'migration.g.dart';
@riverpod @riverpod
Future<void> migration(Ref ref) async { Future<void> migration(Ref ref) async {
final chapters = isar.chapters.filter().idIsNotNull().mangaIdIsNull().findAllSync(); final chapters =
final downloads = isar.downloads.filter().idIsNotNull().mangaIdIsNull().findAllSync(); isar.chapters.filter().idIsNotNull().mangaIdIsNull().findAllSync();
final histories = final downloads =
isar.historys.filter().idIsNotNull().chapterIdIsNull().or().idIsNotNull().isMangaIsNull().findAllSync(); isar.downloads.filter().idIsNotNull().mangaIdIsNull().findAllSync();
final tracks = isar.tracks.filter().idIsNotNull().isMangaIsNull().findAllSync(); final histories = isar.historys
.filter()
.idIsNotNull()
.chapterIdIsNull()
.or()
.idIsNotNull()
.isMangaIsNull()
.findAllSync();
final tracks =
isar.tracks.filter().idIsNotNull().isMangaIsNull().findAllSync();
isar.writeTxnSync(() { isar.writeTxnSync(() {
//mangaId in chapter //mangaId in chapter

View file

@ -8,17 +8,20 @@ import 'package:path/path.dart' as p;
part 'archive_reader_providers.g.dart'; part 'archive_reader_providers.g.dart';
@riverpod @riverpod
Future<List<(String, LocalExtensionType, Uint8List, String)>> getArchivesDataFromDirectory(Ref ref, String path) async { Future<List<(String, LocalExtensionType, Uint8List, String)>>
getArchivesDataFromDirectory(Ref ref, String path) async {
return compute(_extractOnly, path); return compute(_extractOnly, path);
} }
@riverpod @riverpod
Future<List<LocalArchive>> getArchiveDataFromDirectory(Ref ref, String path) async { Future<List<LocalArchive>> getArchiveDataFromDirectory(
Ref ref, String path) async {
return compute(_extract, path); return compute(_extract, path);
} }
@riverpod @riverpod
Future<(String, LocalExtensionType, Uint8List, String)> getArchivesDataFromFile(Ref ref, String path) async { Future<(String, LocalExtensionType, Uint8List, String)> getArchivesDataFromFile(
Ref ref, String path) async {
return compute(_extractArchiveOnly, path); return compute(_extractArchiveOnly, path);
} }
@ -31,7 +34,8 @@ Future<List<LocalArchive>> _extract(String data) async {
return await _searchForArchive(Directory(data)); return await _searchForArchive(Directory(data));
} }
Future<List<(String, LocalExtensionType, Uint8List, String)>> _extractOnly(String data) async { Future<List<(String, LocalExtensionType, Uint8List, String)>> _extractOnly(
String data) async {
return await _searchForArchiveOnly(Directory(data)); return await _searchForArchiveOnly(Directory(data));
} }
@ -53,7 +57,8 @@ Future<List<LocalArchive>> _searchForArchive(Directory dir) async {
return _list; return _list;
} }
Future<List<(String, LocalExtensionType, Uint8List, String)>> _searchForArchiveOnly(Directory dir) async { Future<List<(String, LocalExtensionType, Uint8List, String)>>
_searchForArchiveOnly(Directory dir) async {
List<FileSystemEntity> entities = dir.listSync(); List<FileSystemEntity> entities = dir.listSync();
for (FileSystemEntity entity in entities) { for (FileSystemEntity entity in entities) {
if (entity is Directory) { if (entity is Directory) {
@ -99,7 +104,8 @@ LocalArchive _extractArchive(String path) {
Archive? archive; Archive? archive;
final inputStream = InputFileStream(path); final inputStream = InputFileStream(path);
final extensionType = localArchive.extensionType; final extensionType = localArchive.extensionType;
if (extensionType == LocalExtensionType.cbt || extensionType == LocalExtensionType.tar) { if (extensionType == LocalExtensionType.cbt ||
extensionType == LocalExtensionType.tar) {
archive = TarDecoder().decodeStream(inputStream); archive = TarDecoder().decodeStream(inputStream);
} else { } else {
archive = ZipDecoder().decodeStream(inputStream); archive = ZipDecoder().decodeStream(inputStream);
@ -125,27 +131,35 @@ LocalArchive _extractArchive(String path) {
return localArchive; return localArchive;
} }
(String, LocalExtensionType, Uint8List, String) _extractArchiveOnly(String path) { (String, LocalExtensionType, Uint8List, String) _extractArchiveOnly(
final extensionType = setTypeExtension(p.extension(path).replaceFirst('.', '')); String path) {
final extensionType =
setTypeExtension(p.extension(path).replaceFirst('.', ''));
final name = p.basenameWithoutExtension(path); final name = p.basenameWithoutExtension(path);
Uint8List? coverImage; Uint8List? coverImage;
Archive? archive; Archive? archive;
final inputStream = InputFileStream(path); final inputStream = InputFileStream(path);
if (extensionType == LocalExtensionType.cbt || extensionType == LocalExtensionType.tar) { if (extensionType == LocalExtensionType.cbt ||
extensionType == LocalExtensionType.tar) {
archive = TarDecoder().decodeStream(inputStream); archive = TarDecoder().decodeStream(inputStream);
} else { } else {
archive = ZipDecoder().decodeStream(inputStream); archive = ZipDecoder().decodeStream(inputStream);
} }
final cover = archive.files.where((file) => file.isFile && _isImageFile(file.name) && file.name.contains("cover")); final cover = archive.files.where((file) =>
file.isFile && _isImageFile(file.name) && file.name.contains("cover"));
if (cover.isNotEmpty) { if (cover.isNotEmpty) {
coverImage = cover.first.content; coverImage = cover.first.content;
} else { } else {
List<ArchiveFile> lArchive = List<ArchiveFile> lArchive = archive.files
archive.files.where((file) => file.isFile && _isImageFile(file.name) && !file.name.contains("cover")).toList(); .where((file) =>
file.isFile &&
_isImageFile(file.name) &&
!file.name.contains("cover"))
.toList();
lArchive.sort( lArchive.sort(
(a, b) => a.name.compareTo(b.name), (a, b) => a.name.compareTo(b.name),
); );

View file

@ -26,7 +26,9 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
_init() async { _init() async {
await Future.delayed(const Duration(milliseconds: 100)); await Future.delayed(const Duration(milliseconds: 100));
await ref.read(updateMangaDetailProvider(mangaId: widget.mangaId, isInit: true).future); await ref.read(
updateMangaDetailProvider(mangaId: widget.mangaId, isInit: true)
.future);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
@ -37,7 +39,8 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
bool _isLoading = true; bool _isLoading = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final manga = ref.watch(getMangaDetailStreamProvider(mangaId: widget.mangaId)); final manga =
ref.watch(getMangaDetailStreamProvider(mangaId: widget.mangaId));
return Scaffold( return Scaffold(
body: manga.when( body: manga.when(
data: (manga) { data: (manga) {
@ -59,7 +62,9 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
if (sourceExist && !_isLoading) { if (sourceExist && !_isLoading) {
await ref.read(updateMangaDetailProvider(mangaId: manga.id, isInit: false).future); await ref.read(updateMangaDetailProvider(
mangaId: manga.id, isInit: false)
.future);
} }
}, },
child: Stack( child: Stack(
@ -73,7 +78,9 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
_isLoading = true; _isLoading = true;
}); });
if (sourceExist) { if (sourceExist) {
await ref.read(updateMangaDetailProvider(mangaId: manga.id, isInit: false).future); await ref.read(updateMangaDetailProvider(
mangaId: manga.id, isInit: false)
.future);
} }
if (mounted) { if (mounted) {
setState(() { setState(() {

View file

@ -7,7 +7,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mangayomi/eval/dart/model/m_bridge.dart'; import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/main.dart'; import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/download.dart'; import 'package:mangayomi/models/download.dart';

View file

@ -41,7 +41,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
return textPainter.size; return textPainter.size;
} }
double calculateDynamicButtonWidth(String text, TextStyle textStyle, double padding) { double calculateDynamicButtonWidth(
String text, TextStyle textStyle, double padding) {
final textSize = measureText(text, textStyle); final textSize = measureText(text, textStyle);
return textSize.width + padding; return textSize.width + padding;
} }
@ -57,20 +58,28 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
final isExtended = ref.watch(isExtendedStateProvider); final isExtended = ref.watch(isExtendedStateProvider);
return ref.watch(isLongPressedStateProvider) == true return ref.watch(isLongPressedStateProvider) == true
? Container() ? Container()
: chaptersList.isNotEmpty && chaptersList.where((element) => !element.isRead!).toList().isNotEmpty : chaptersList.isNotEmpty &&
chaptersList
.where((element) => !element.isRead!)
.toList()
.isNotEmpty
? StreamBuilder( ? StreamBuilder(
stream: isar.historys stream: isar.historys
.filter() .filter()
.idIsNotNull() .idIsNotNull()
.and() .and()
.chapter((q) => q.manga((q) => q.isMangaEqualTo(widget.manga.isManga!))) .chapter((q) => q.manga(
(q) => q.isMangaEqualTo(widget.manga.isManga!)))
.watch(fireImmediately: true), .watch(fireImmediately: true),
builder: (context, snapshot) { builder: (context, snapshot) {
String buttonLabel = widget.manga.isManga! ? l10n.read : l10n.watch; String buttonLabel =
widget.manga.isManga! ? l10n.read : l10n.watch;
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final incognitoMode = ref.watch(incognitoModeStateProvider); final incognitoMode =
ref.watch(incognitoModeStateProvider);
final entries = snapshot.data! final entries = snapshot.data!
.where((element) => element.mangaId == widget.manga.id) .where((element) =>
element.mangaId == widget.manga.id)
.toList() .toList()
.reversed .reversed
.toList(); .toList();
@ -83,8 +92,12 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
onPressed: () { onPressed: () {
chap.pushToReaderView(context); chap.pushToReaderView(context);
}, },
textWidth: measureText(l10n.resume, Theme.of(context).textTheme.labelLarge!).width, textWidth: measureText(l10n.resume,
width: calculateDynamicButtonWidth(l10n.resume, Theme.of(context).textTheme.labelLarge!, Theme.of(context).textTheme.labelLarge!)
.width,
width: calculateDynamicButtonWidth(
l10n.resume,
Theme.of(context).textTheme.labelLarge!,
50), // 50 Padding, else RenderFlex overflow Exception 50), // 50 Padding, else RenderFlex overflow Exception
); );
} }
@ -92,10 +105,19 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
isExtended: !isExtended, isExtended: !isExtended,
label: buttonLabel, label: buttonLabel,
onPressed: () { onPressed: () {
widget.manga.chapters.toList().reversed.toList().last.pushToReaderView(context); widget.manga.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
}, },
textWidth: measureText(buttonLabel, Theme.of(context).textTheme.labelLarge!).width, textWidth: measureText(buttonLabel,
width: calculateDynamicButtonWidth(buttonLabel, Theme.of(context).textTheme.labelLarge!, Theme.of(context).textTheme.labelLarge!)
.width,
width: calculateDynamicButtonWidth(
buttonLabel,
Theme.of(context).textTheme.labelLarge!,
50), // 50 Padding, else RenderFlex overflow Exception 50), // 50 Padding, else RenderFlex overflow Exception
); );
} }
@ -103,10 +125,19 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
isExtended: !isExtended, isExtended: !isExtended,
label: buttonLabel, label: buttonLabel,
onPressed: () { onPressed: () {
widget.manga.chapters.toList().reversed.toList().last.pushToReaderView(context); widget.manga.chapters
.toList()
.reversed
.toList()
.last
.pushToReaderView(context);
}, },
textWidth: measureText(buttonLabel, Theme.of(context).textTheme.labelLarge!).width, textWidth: measureText(buttonLabel,
width: calculateDynamicButtonWidth(buttonLabel, Theme.of(context).textTheme.labelLarge!, Theme.of(context).textTheme.labelLarge!)
.width,
width: calculateDynamicButtonWidth(
buttonLabel,
Theme.of(context).textTheme.labelLarge!,
50), // 50 Padding, else RenderFlex overflow Exception 50), // 50 Padding, else RenderFlex overflow Exception
); );
}, },
@ -155,7 +186,9 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
? SizedBox( ? SizedBox(
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, elevation: 0), backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
elevation: 0),
onPressed: () { onPressed: () {
final model = widget.manga; final model = widget.manga;
isar.writeTxnSync(() { isar.writeTxnSync(() {
@ -183,8 +216,9 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
), ),
) )
: ElevatedButton( : ElevatedButton(
style: style: ElevatedButton.styleFrom(
ElevatedButton.styleFrom(backgroundColor: Theme.of(context).scaffoldBackgroundColor, elevation: 0), backgroundColor: Theme.of(context).scaffoldBackgroundColor,
elevation: 0),
onPressed: () { onPressed: () {
final checkCategoryList = isar.categorys final checkCategoryList = isar.categorys
.filter() .filter()
@ -215,7 +249,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
), ),
Text( Text(
l10n.add_to_library, l10n.add_to_library,
style: TextStyle(color: context.secondaryColor, fontSize: 11), style: TextStyle(
color: context.secondaryColor, fontSize: 11),
textAlign: TextAlign.center, textAlign: TextAlign.center,
) )
], ],
@ -264,14 +299,17 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
label: entries[index].name!, label: entries[index].name!,
onTap: () { onTap: () {
setState(() { setState(() {
if (categoryIds.contains(entries[index].id)) { if (categoryIds
.contains(entries[index].id)) {
categoryIds.remove(entries[index].id); categoryIds.remove(entries[index].id);
} else { } else {
categoryIds.add(entries[index].id!); categoryIds.add(entries[index].id!);
} }
}); });
}, },
type: categoryIds.contains(entries[index].id) ? 1 : 0, type: categoryIds.contains(entries[index].id)
? 1
: 0,
); );
}, },
); );
@ -285,7 +323,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
children: [ children: [
TextButton( TextButton(
onPressed: () { onPressed: () {
context.push("/categories", extra: (true, widget.manga.isManga! ? 0 : 1)); context.push("/categories",
extra: (true, widget.manga.isManga! ? 0 : 1));
Navigator.pop(context); Navigator.pop(context);
}, },
child: Text(l10n.edit)), child: Text(l10n.edit)),
@ -305,7 +344,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
isar.writeTxnSync(() { isar.writeTxnSync(() {
model.favorite = true; model.favorite = true;
model.categories = categoryIds; model.categories = categoryIds;
model.dateAdded = DateTime.now().millisecondsSinceEpoch; model.dateAdded =
DateTime.now().millisecondsSinceEpoch;
isar.mangas.putSync(model); isar.mangas.putSync(model);
}); });
if (mounted) { if (mounted) {

View file

@ -16,5 +16,8 @@ Stream<List<Chapter>> getChaptersStream(
Ref ref, { Ref ref, {
required int mangaId, required int mangaId,
}) async* { }) async* {
yield* isar.chapters.filter().manga((q) => q.idEqualTo(mangaId)).watch(fireImmediately: true); yield* isar.chapters
.filter()
.manga((q) => q.idEqualTo(mangaId))
.watch(fireImmediately: true);
} }

View file

@ -159,7 +159,8 @@ class ChapterFilterDownloadedState extends _$ChapterFilterDownloadedState {
} }
chapterFilterDownloadedList.add(value); chapterFilterDownloadedList.add(value);
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..chapterFilterDownloadedList = chapterFilterDownloadedList); isar.settings.putSync(
settings..chapterFilterDownloadedList = chapterFilterDownloadedList);
}); });
state = type; state = type;
@ -211,7 +212,8 @@ class ChapterFilterUnreadState extends _$ChapterFilterUnreadState {
} }
chapterFilterUnreadList.add(value); chapterFilterUnreadList.add(value);
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..chapterFilterUnreadList = chapterFilterUnreadList); isar.settings
.putSync(settings..chapterFilterUnreadList = chapterFilterUnreadList);
}); });
state = type; state = type;
} }
@ -262,7 +264,8 @@ class ChapterFilterBookmarkedState extends _$ChapterFilterBookmarkedState {
} }
chapterFilterBookmarkedList.add(value); chapterFilterBookmarkedList.add(value);
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..chapterFilterBookmarkedList = chapterFilterBookmarkedList); isar.settings.putSync(
settings..chapterFilterBookmarkedList = chapterFilterBookmarkedList);
}); });
state = type; state = type;
} }
@ -282,12 +285,18 @@ class ChapterFilterBookmarkedState extends _$ChapterFilterBookmarkedState {
class ChapterFilterResultState extends _$ChapterFilterResultState { class ChapterFilterResultState extends _$ChapterFilterResultState {
@override @override
bool build({required Manga manga}) { bool build({required Manga manga}) {
final downloadFilterType = ref.watch(chapterFilterDownloadedStateProvider(mangaId: manga.id!)); final downloadFilterType =
final unreadFilterType = ref.watch(chapterFilterUnreadStateProvider(mangaId: manga.id!)); ref.watch(chapterFilterDownloadedStateProvider(mangaId: manga.id!));
final unreadFilterType =
ref.watch(chapterFilterUnreadStateProvider(mangaId: manga.id!));
final bookmarkedFilterType = ref.watch(chapterFilterBookmarkedStateProvider(mangaId: manga.id!)); final bookmarkedFilterType =
ref.watch(chapterFilterBookmarkedStateProvider(mangaId: manga.id!));
final scanlators = ref.watch(scanlatorsFilterStateProvider(manga)); final scanlators = ref.watch(scanlatorsFilterStateProvider(manga));
return downloadFilterType == 0 && unreadFilterType == 0 && bookmarkedFilterType == 0 && scanlators.$2.isEmpty; return downloadFilterType == 0 &&
unreadFilterType == 0 &&
bookmarkedFilterType == 0 &&
scanlators.$2.isEmpty;
} }
} }
@ -301,7 +310,9 @@ class ChapterSetIsBookmarkState extends _$ChapterSetIsBookmarkState {
isar.writeTxnSync(() { isar.writeTxnSync(() {
for (var chapter in chapters) { for (var chapter in chapters) {
chapter.isBookmarked = !chapter.isBookmarked!; chapter.isBookmarked = !chapter.isBookmarked!;
ref.read(changedItemsManagerProvider(managerId: 1).notifier).addUpdatedChapter(chapter, false, false); ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(chapter, false, false);
isar.chapters.putSync(chapter..manga.value = manga); isar.chapters.putSync(chapter..manga.value = manga);
chapter.manga.saveSync(); chapter.manga.saveSync();
} }
@ -321,7 +332,9 @@ class ChapterSetIsReadState extends _$ChapterSetIsReadState {
isar.writeTxnSync(() { isar.writeTxnSync(() {
for (var chapter in chapters) { for (var chapter in chapters) {
chapter.isRead = !chapter.isRead!; chapter.isRead = !chapter.isRead!;
ref.read(changedItemsManagerProvider(managerId: 1).notifier).addUpdatedChapter(chapter, false, false); ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(chapter, false, false);
isar.chapters.putSync(chapter..manga.value = manga); isar.chapters.putSync(chapter..manga.value = manga);
chapter.manga.saveSync(); chapter.manga.saveSync();
} }
@ -340,7 +353,11 @@ class ChapterSetDownloadState extends _$ChapterSetDownloadState {
ref.read(isLongPressedStateProvider.notifier).update(false); ref.read(isLongPressedStateProvider.notifier).update(false);
isar.txnSync(() { isar.txnSync(() {
for (var chapter in ref.watch(chaptersListStateProvider)) { for (var chapter in ref.watch(chaptersListStateProvider)) {
final entries = isar.downloads.filter().idIsNotNull().chapterIdEqualTo(chapter.id).findAllSync(); final entries = isar.downloads
.filter()
.idIsNotNull()
.chapterIdEqualTo(chapter.id)
.findAllSync();
if (entries.isEmpty || !entries.first.isDownload!) { if (entries.isEmpty || !entries.first.isDownload!) {
ref.watch(downloadChapterProvider(chapter: chapter)); ref.watch(downloadChapterProvider(chapter: chapter));
} }
@ -378,7 +395,8 @@ class ScanlatorsFilterState extends _$ScanlatorsFilterState {
List<String> _getScanlators() { List<String> _getScanlators() {
List<String> scanlators = []; List<String> scanlators = [];
for (var a in manga.chapters.toList()) { for (var a in manga.chapters.toList()) {
if ((a.scanlator?.isNotEmpty ?? false) && !scanlators.contains(a.scanlator)) { if ((a.scanlator?.isNotEmpty ?? false) &&
!scanlators.contains(a.scanlator)) {
scanlators.add(a.scanlator!); scanlators.add(a.scanlator!);
} }
} }
@ -399,14 +417,16 @@ class ScanlatorsFilterState extends _$ScanlatorsFilterState {
} }
filterScanlatorList.add(value); filterScanlatorList.add(value);
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.settings.putSync(settings..filterScanlatorList = filterScanlatorList); isar.settings
.putSync(settings..filterScanlatorList = filterScanlatorList);
}); });
state = (_getScanlators(), _getFilterScanlator()!, filterScanlators); state = (_getScanlators(), _getFilterScanlator()!, filterScanlators);
} }
List<String>? _getFilterScanlator() { List<String>? _getFilterScanlator() {
final scanlators = isar.settings.getSync(227)!.filterScanlatorList ?? []; final scanlators = isar.settings.getSync(227)!.filterScanlatorList ?? [];
final filter = scanlators.where((element) => element.mangaId == manga.id).toList(); final filter =
scanlators.where((element) => element.mangaId == manga.id).toList();
return filter.isEmpty ? null : filter.first.scanlators; return filter.isEmpty ? null : filter.first.scanlators;
} }
@ -421,6 +441,7 @@ class ScanlatorsFilterState extends _$ScanlatorsFilterState {
} else { } else {
scanlatorFilteredList.add(scanlator); scanlatorFilteredList.add(scanlator);
} }
state = (_getScanlators(), _getFilterScanlator() ?? [], scanlatorFilteredList); state =
(_getScanlators(), _getFilterScanlator() ?? [], scanlatorFilteredList);
} }
} }

View file

@ -18,19 +18,41 @@ class TrackState extends _$TrackState {
Track? updateTrack; Track? updateTrack;
if (track!.syncId == 1) { if (track!.syncId == 1) {
updateTrack = isManga! updateTrack = isManga!
? await ref.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga).notifier).updateManga(track!) ? await ref
: await ref.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga).notifier).updateAnime(track!); .read(
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.updateManga(track!)
: await ref
.read(
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.updateAnime(track!);
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
updateTrack = isManga! updateTrack = isManga!
? await ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).updateLibManga(track!) ? await ref
: await ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).updateLibAnime(track!); .read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.updateLibManga(track!)
: await ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.updateLibAnime(track!);
} else if (track!.syncId == 3) { } else if (track!.syncId == 3) {
updateTrack = isManga! updateTrack = isManga!
? await ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).updateLibManga(track!) ? await ref
: await ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).updateLibAnime(track!); .read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.updateLibManga(track!)
: await ref
.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.updateLibAnime(track!);
} }
ref.read(tracksProvider(syncId: track!.syncId!).notifier).updateTrackManga(updateTrack!, isManga); ref
.read(tracksProvider(syncId: track!.syncId!).notifier)
.updateTrackManga(updateTrack!, isManga);
} }
int getScoreMaxValue() { int getScoreMaxValue() {
@ -38,7 +60,11 @@ class TrackState extends _$TrackState {
if (track!.syncId == 1 || track!.syncId == 3) { if (track!.syncId == 1 || track!.syncId == 3) {
maxValue = 10; maxValue = 10;
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
maxValue = ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).getScoreValue().$1; maxValue = ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.getScoreValue()
.$1;
} }
return maxValue!; return maxValue!;
} }
@ -46,7 +72,9 @@ class TrackState extends _$TrackState {
String getTextMapper(String numberText) { String getTextMapper(String numberText) {
if (track!.syncId == 1 || track!.syncId == 3) { if (track!.syncId == 1 || track!.syncId == 3) {
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
numberText = ref.read(anilistProvider(syncId: 2, isManga: isManga).notifier).displayScore(int.parse(numberText)); numberText = ref
.read(anilistProvider(syncId: 2, isManga: isManga).notifier)
.displayScore(int.parse(numberText));
} }
return numberText; return numberText;
} }
@ -56,7 +84,11 @@ class TrackState extends _$TrackState {
if (track!.syncId == 1 || track!.syncId == 3) { if (track!.syncId == 1 || track!.syncId == 3) {
step = 1; step = 1;
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
step = ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).getScoreValue().$2; step = ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.getScoreValue()
.$2;
} }
return step!; return step!;
} }
@ -66,12 +98,15 @@ class TrackState extends _$TrackState {
if (track!.syncId == 1 || track!.syncId == 3) { if (track!.syncId == 1 || track!.syncId == 3) {
result = score.toString(); result = score.toString();
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
result = ref.read(anilistProvider(syncId: 2, isManga: isManga).notifier).displayScore(score); result = ref
.read(anilistProvider(syncId: 2, isManga: isManga).notifier)
.displayScore(score);
} }
return result!; return result!;
} }
Future setTrackSearch(TrackSearch trackSearch, int mangaId, int syncId) async { Future setTrackSearch(
TrackSearch trackSearch, int mangaId, int syncId) async {
Track? findManga; Track? findManga;
final track = Track( final track = Track(
mangaId: mangaId, mangaId: mangaId,
@ -86,20 +121,36 @@ class TrackState extends _$TrackState {
startedReadingDate: 0, startedReadingDate: 0,
finishedReadingDate: 0); finishedReadingDate: 0);
if (syncId == 1) { if (syncId == 1) {
findManga = await ref.read(myAnimeListProvider(syncId: syncId, isManga: isManga).notifier).findManga(track); findManga = await ref
.read(myAnimeListProvider(syncId: syncId, isManga: isManga).notifier)
.findManga(track);
} else if (syncId == 2) { } else if (syncId == 2) {
findManga = isManga! findManga = isManga!
? await ref.read(anilistProvider(syncId: syncId, isManga: isManga).notifier).findLibManga(track) ? await ref
: await ref.read(anilistProvider(syncId: syncId, isManga: isManga).notifier).findLibAnime(track); .read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
.findLibManga(track)
: await ref
.read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
.findLibAnime(track);
findManga ??= isManga! findManga ??= isManga!
? await ref.read(anilistProvider(syncId: syncId, isManga: isManga).notifier).addLibManga(track) ? await ref
: await ref.read(anilistProvider(syncId: syncId, isManga: isManga).notifier).addLibAnime(track); .read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
.addLibManga(track)
: await ref
.read(anilistProvider(syncId: syncId, isManga: isManga).notifier)
.addLibAnime(track);
} else if (syncId == 3) { } else if (syncId == 3) {
findManga = isManga! findManga = isManga!
? await ref.read(kitsuProvider(syncId: syncId, isManga: isManga).notifier).addLibManga(track) ? await ref
: await ref.read(kitsuProvider(syncId: syncId, isManga: isManga).notifier).addLibAnime(track); .read(kitsuProvider(syncId: syncId, isManga: isManga).notifier)
.addLibManga(track)
: await ref
.read(kitsuProvider(syncId: syncId, isManga: isManga).notifier)
.addLibAnime(track);
} }
ref.read(tracksProvider(syncId: syncId).notifier).updateTrackManga(findManga!, isManga); ref
.read(tracksProvider(syncId: syncId).notifier)
.updateTrackManga(findManga!, isManga);
} }
List<TrackStatus> getStatusList() { List<TrackStatus> getStatusList() {
@ -107,16 +158,36 @@ class TrackState extends _$TrackState {
List<TrackStatus> list = []; List<TrackStatus> list = [];
if (track!.syncId == 1) { if (track!.syncId == 1) {
statusList = isManga! statusList = isManga!
? ref.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga).notifier).myAnimeListStatusListManga ? ref
: ref.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga).notifier).myAnimeListStatusListAnime; .read(
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.myAnimeListStatusListManga
: ref
.read(
myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.myAnimeListStatusListAnime;
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
statusList = isManga! statusList = isManga!
? ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).aniListStatusListManga ? ref
: ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).aniListStatusListAnime; .read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.aniListStatusListManga
: ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.aniListStatusListAnime;
} else if (track!.syncId == 3) { } else if (track!.syncId == 3) {
statusList = isManga! statusList = isManga!
? ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).kitsuStatusListManga ? ref
: ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).kitsuStatusListAnime; .read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.kitsuStatusListManga
: ref
.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.kitsuStatusListAnime;
} }
for (var element in TrackStatus.values) { for (var element in TrackStatus.values) {
if (statusList.contains(element)) { if (statusList.contains(element)) {
@ -129,16 +200,30 @@ class TrackState extends _$TrackState {
Future<Track?> findManga() async { Future<Track?> findManga() async {
Track? findManga; Track? findManga;
if (track!.syncId == 1) { if (track!.syncId == 1) {
findManga = findManga = await ref
await ref.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga).notifier).findManga(track!); .read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.findManga(track!);
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
findManga = isManga! findManga = isManga!
? await ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).findLibManga(track!) ? await ref
: await ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).findLibAnime(track!); .read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.findLibManga(track!)
: await ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.findLibAnime(track!);
} else if (track!.syncId == 3) { } else if (track!.syncId == 3) {
findManga = isManga! findManga = isManga!
? await ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).findLibManga(track!) ? await ref
: await ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).findLibAnime(track!); .read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.findLibManga(track!)
: await ref
.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.findLibAnime(track!);
} }
return findManga; return findManga;
} }
@ -146,15 +231,30 @@ class TrackState extends _$TrackState {
Future<List<TrackSearch>?> search(String query) async { Future<List<TrackSearch>?> search(String query) async {
List<TrackSearch>? tracks; List<TrackSearch>? tracks;
if (track!.syncId == 1) { if (track!.syncId == 1) {
tracks = await ref.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga).notifier).search(query); tracks = await ref
.read(myAnimeListProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.search(query);
} else if (track!.syncId == 2) { } else if (track!.syncId == 2) {
tracks = isManga! tracks = isManga!
? await ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).search(query) ? await ref
: await ref.read(anilistProvider(syncId: track!.syncId!, isManga: isManga).notifier).searchAnime(query); .read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.search(query)
: await ref
.read(anilistProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.searchAnime(query);
} else if (track!.syncId == 3) { } else if (track!.syncId == 3) {
tracks = isManga! tracks = isManga!
? await ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).search(query) ? await ref
: await ref.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga).notifier).searchAnime(query); .read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.search(query)
: await ref
.read(kitsuProvider(syncId: track!.syncId!, isManga: isManga)
.notifier)
.searchAnime(query);
} }
return tracks; return tracks;
} }

View file

@ -12,7 +12,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'update_manga_detail_providers.g.dart'; part 'update_manga_detail_providers.g.dart';
@riverpod @riverpod
Future<dynamic> updateMangaDetail(Ref ref, {required int? mangaId, required bool isInit}) async { Future<dynamic> updateMangaDetail(Ref ref,
{required int? mangaId, required bool isInit}) async {
final manga = isar.mangas.getSync(mangaId!); final manga = isar.mangas.getSync(mangaId!);
if (manga!.chapters.isNotEmpty && isInit) { if (manga!.chapters.isNotEmpty && isInit) {
return; return;
@ -20,20 +21,31 @@ Future<dynamic> updateMangaDetail(Ref ref, {required int? mangaId, required bool
final source = getSource(manga.lang!, manga.source!); final source = getSource(manga.lang!, manga.source!);
MManga getManga; MManga getManga;
try { try {
getManga = await ref.watch(getDetailProvider(url: manga.link!, source: source!).future); getManga = await ref
.watch(getDetailProvider(url: manga.link!, source: source!).future);
} catch (e) { } catch (e) {
botToast(e.toString()); botToast(e.toString());
return; return;
} }
final genre = getManga.genre?.map((e) => e.toString().trim().trimLeft().trimRight()).toList().toSet().toList() ?? []; final genre = getManga.genre
?.map((e) => e.toString().trim().trimLeft().trimRight())
.toList()
.toSet()
.toList() ??
[];
manga manga
..imageUrl = getManga.imageUrl ?? manga.imageUrl ..imageUrl = getManga.imageUrl ?? manga.imageUrl
..name = getManga.name?.trim().trimLeft().trimRight() ?? manga.name ..name = getManga.name?.trim().trimLeft().trimRight() ?? manga.name
..genre = (genre.isEmpty ? null : genre) ?? manga.genre ?? [] ..genre = (genre.isEmpty ? null : genre) ?? manga.genre ?? []
..author = getManga.author?.trim().trimLeft().trimRight() ?? manga.author ?? "" ..author =
..artist = getManga.artist?.trim().trimLeft().trimRight() ?? manga.artist ?? "" getManga.author?.trim().trimLeft().trimRight() ?? manga.author ?? ""
..status = getManga.status == Status.unknown ? manga.status : getManga.status! ..artist =
..description = getManga.description?.trim().trimLeft().trimRight() ?? manga.description ?? "" getManga.artist?.trim().trimLeft().trimRight() ?? manga.artist ?? ""
..status =
getManga.status == Status.unknown ? manga.status : getManga.status!
..description = getManga.description?.trim().trimLeft().trimRight() ??
manga.description ??
""
..link = getManga.link?.trim().trimLeft().trimRight() ?? manga.link ..link = getManga.link?.trim().trimLeft().trimRight() ?? manga.link
..source = manga.source ..source = manga.source
..lang = manga.lang ..lang = manga.lang
@ -68,19 +80,24 @@ Future<dynamic> updateMangaDetail(Ref ref, {required int? mangaId, required bool
} }
if (chapters.isNotEmpty) { if (chapters.isNotEmpty) {
for (var chap in chapters.reversed.toList()) { for (var chap in chapters.reversed.toList()) {
ref.read(changedItemsManagerProvider(managerId: 1).notifier).addUpdatedChapter(chap, false, false); ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(chap, false, false);
isar.chapters.putSync(chap); isar.chapters.putSync(chap);
chap.manga.saveSync(); chap.manga.saveSync();
if (manga.chapters.isNotEmpty) { if (manga.chapters.isNotEmpty) {
final update = final update = Update(
Update(mangaId: mangaId, chapterName: chap.name, date: DateTime.now().millisecondsSinceEpoch.toString()) mangaId: mangaId,
..chapter.value = chap; chapterName: chap.name,
date: DateTime.now().millisecondsSinceEpoch.toString())
..chapter.value = chap;
isar.updates.putSync(update); isar.updates.putSync(update);
update.chapter.saveSync(); update.chapter.saveSync();
} }
} }
} }
final oldChapers = isar.mangas.getSync(mangaId)!.chapters.toList().reversed.toList(); final oldChapers =
isar.mangas.getSync(mangaId)!.chapters.toList().reversed.toList();
if (oldChapers.length == chaps.length) { if (oldChapers.length == chaps.length) {
for (var i = 0; i < oldChapers.length; i++) { for (var i = 0; i < oldChapers.length; i++) {
final oldChap = oldChapers[i]; final oldChap = oldChapers[i];
@ -91,7 +108,9 @@ Future<dynamic> updateMangaDetail(Ref ref, {required int? mangaId, required bool
newChap.name == oldChap.name) { newChap.name == oldChap.name) {
oldChap.url = newChap.url; oldChap.url = newChap.url;
oldChap.scanlator = newChap.scanlator; oldChap.scanlator = newChap.scanlator;
ref.read(changedItemsManagerProvider(managerId: 1).notifier).addUpdatedChapter(oldChap, false, false); ref
.read(changedItemsManagerProvider(managerId: 1).notifier)
.addUpdatedChapter(oldChap, false, false);
isar.chapters.putSync(oldChap); isar.chapters.putSync(oldChap);
oldChap.manga.saveSync(); oldChap.manga.saveSync();
} }

View file

@ -4,7 +4,11 @@ class ListTileChapterFilter extends StatelessWidget {
final String label; final String label;
final int type; final int type;
final VoidCallback onTap; final VoidCallback onTap;
const ListTileChapterFilter({super.key, required this.label, required this.type, required this.onTap}); const ListTileChapterFilter(
{super.key,
required this.label,
required this.type,
required this.onTap});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -25,19 +25,25 @@ class ChapterListTileWidget extends ConsumerWidget {
final isLongPressed = ref.watch(isLongPressedStateProvider); final isLongPressed = ref.watch(isLongPressedStateProvider);
final l10n = l10nLocalizations(context)!; final l10n = l10nLocalizations(context)!;
return Container( return Container(
color: chapterList.contains(chapter) ? context.primaryColor.withValues(alpha: 0.4) : null, color: chapterList.contains(chapter)
? context.primaryColor.withValues(alpha: 0.4)
: null,
child: ListTile( child: ListTile(
textColor: chapter.isRead! textColor: chapter.isRead!
? context.isLight ? context.isLight
? Colors.black.withValues(alpha: 0.4) ? Colors.black.withValues(alpha: 0.4)
: Colors.white.withValues(alpha: 0.3) : Colors.white.withValues(alpha: 0.3)
: null, : null,
selectedColor: chapter.isRead! ? Colors.white.withValues(alpha: 0.3) : Colors.white, selectedColor: chapter.isRead!
? Colors.white.withValues(alpha: 0.3)
: Colors.white,
onLongPress: () { onLongPress: () {
if (!isLongPressed) { if (!isLongPressed) {
ref.read(chaptersListStateProvider.notifier).update(chapter); ref.read(chaptersListStateProvider.notifier).update(chapter);
ref.read(isLongPressedStateProvider.notifier).update(!isLongPressed); ref
.read(isLongPressedStateProvider.notifier)
.update(!isLongPressed);
} else { } else {
ref.read(chaptersListStateProvider.notifier).update(chapter); ref.read(chaptersListStateProvider.notifier).update(chapter);
} }
@ -73,18 +79,23 @@ class ChapterListTileWidget extends ConsumerWidget {
Text( Text(
chapter.dateUpload == null || chapter.dateUpload!.isEmpty chapter.dateUpload == null || chapter.dateUpload!.isEmpty
? "" ? ""
: dateFormat(chapter.dateUpload!, ref: ref, context: context), : dateFormat(chapter.dateUpload!,
ref: ref, context: context),
style: const TextStyle(fontSize: 11), style: const TextStyle(fontSize: 11),
), ),
if (!chapter.isRead!) if (!chapter.isRead!)
if (chapter.lastPageRead!.isNotEmpty && chapter.lastPageRead != "1") if (chapter.lastPageRead!.isNotEmpty &&
chapter.lastPageRead != "1")
Row( Row(
children: [ children: [
const Text(''), const Text(''),
Text( Text(
!chapter.manga.value!.isManga! !chapter.manga.value!.isManga!
? l10n.episode_progress( ? l10n.episode_progress(Duration(
Duration(milliseconds: int.parse(chapter.lastPageRead!)).toString().substringBefore(".")) milliseconds:
int.parse(chapter.lastPageRead!))
.toString()
.substringBefore("."))
: l10n.page(chapter.lastPageRead!), : l10n.page(chapter.lastPageRead!),
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,

View file

@ -6,15 +6,22 @@ class ListTileChapterSort extends StatelessWidget {
final VoidCallback onTap; final VoidCallback onTap;
final bool showLeading; final bool showLeading;
const ListTileChapterSort( const ListTileChapterSort(
{super.key, required this.label, required this.reverse, required this.onTap, required this.showLeading}); {super.key,
required this.label,
required this.reverse,
required this.onTap,
required this.showLeading});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListTile( return ListTile(
iconColor: Theme.of(context).primaryColor, iconColor: Theme.of(context).primaryColor,
dense: true, dense: true,
leading: Icon(reverse ? Icons.arrow_downward_sharp : Icons.arrow_upward_sharp, leading: Icon(
color: showLeading ? Theme.of(context).primaryColor : Colors.transparent), reverse ? Icons.arrow_downward_sharp : Icons.arrow_upward_sharp,
color: showLeading
? Theme.of(context).primaryColor
: Colors.transparent),
title: Text( title: Text(
label, label,
style: const TextStyle(fontSize: 14), style: const TextStyle(fontSize: 14),

View file

@ -4,7 +4,8 @@ import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
class ReadMoreWidget extends StatefulWidget { class ReadMoreWidget extends StatefulWidget {
const ReadMoreWidget({super.key, required this.text, required this.onChanged}); const ReadMoreWidget(
{super.key, required this.text, required this.onChanged});
final Function(bool) onChanged; final Function(bool) onChanged;
final String text; final String text;
@ -12,7 +13,8 @@ class ReadMoreWidget extends StatefulWidget {
ReadMoreWidgetState createState() => ReadMoreWidgetState(); ReadMoreWidgetState createState() => ReadMoreWidgetState();
} }
class ReadMoreWidgetState extends State<ReadMoreWidget> with TickerProviderStateMixin { class ReadMoreWidgetState extends State<ReadMoreWidget>
with TickerProviderStateMixin {
late bool expanded = true; late bool expanded = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -61,7 +63,9 @@ class ReadMoreWidgetState extends State<ReadMoreWidget> with TickerProviderState
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
colors: [ colors: [
Theme.of(context).scaffoldBackgroundColor.withValues(alpha: 0.2), Theme.of(context)
.scaffoldBackgroundColor
.withValues(alpha: 0.2),
Theme.of(context).scaffoldBackgroundColor Theme.of(context).scaffoldBackgroundColor
], ],
stops: const [0, .9], stops: const [0, .9],

View file

@ -11,10 +11,12 @@ import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
class TrackerWidgetSearch extends ConsumerStatefulWidget { class TrackerWidgetSearch extends ConsumerStatefulWidget {
final bool isManga; final bool isManga;
final Track track; final Track track;
const TrackerWidgetSearch({required this.isManga, required this.track, super.key}); const TrackerWidgetSearch(
{required this.isManga, required this.track, super.key});
@override @override
ConsumerState<TrackerWidgetSearch> createState() => _TrackerWidgetSearchState(); ConsumerState<TrackerWidgetSearch> createState() =>
_TrackerWidgetSearchState();
} }
class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> { class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
@ -28,7 +30,10 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
late List<TrackSearch>? tracks = []; late List<TrackSearch>? tracks = [];
_init() async { _init() async {
await Future.delayed(const Duration(microseconds: 100)); await Future.delayed(const Duration(microseconds: 100));
tracks = await ref.read(trackStateProvider(track: widget.track, isManga: widget.isManga).notifier).search(query); tracks = await ref
.read(trackStateProvider(track: widget.track, isManga: widget.isManga)
.notifier)
.search(query);
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
@ -42,7 +47,8 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return Material(
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)), borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)),
clipBehavior: Clip.antiAliasWithSaveLayer, clipBehavior: Clip.antiAliasWithSaveLayer,
child: _isLoading child: _isLoading
? const ProgressCenter() ? const ProgressCenter()
@ -66,41 +72,50 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
child: Column( child: Column(
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Material( Material(
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
color: Colors.transparent, color: Colors.transparent,
clipBehavior: Clip.antiAliasWithSaveLayer, clipBehavior:
Clip.antiAliasWithSaveLayer,
child: Ink.image( child: Ink.image(
height: 120, height: 120,
width: 80, width: 80,
fit: BoxFit.cover, fit: BoxFit.cover,
image: CustomExtendedNetworkImageProvider(tracks![index].coverUrl!), image:
CustomExtendedNetworkImageProvider(
tracks![index].coverUrl!),
), ),
), ),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
SizedBox( SizedBox(
width: context.width(0.6), width: context.width(0.6),
child: Text( child: Text(
tracks![index].title!, tracks![index].title!,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(
fontWeight: FontWeight.bold),
), ),
), ),
Row( Row(
children: [ children: [
const Text( const Text(
"Type : ", "Type : ",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12),
), ),
Text( Text(
tracks![index].publishingType!, tracks![index].publishingType!,
style: const TextStyle(fontSize: 12), style: const TextStyle(
fontSize: 12),
), ),
], ],
), ),
@ -108,11 +123,15 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
children: [ children: [
const Text( const Text(
"Status : ", "Status : ",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12),
), ),
Text( Text(
tracks![index].publishingStatus!, tracks![index]
style: const TextStyle(fontSize: 12), .publishingStatus!,
style: const TextStyle(
fontSize: 12),
), ),
], ],
), ),
@ -153,7 +172,10 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
_isLoading = true; _isLoading = true;
}); });
tracks = await ref tracks = await ref
.read(trackStateProvider(track: widget.track, isManga: widget.isManga).notifier) .read(trackStateProvider(
track: widget.track,
isManga: widget.isManga)
.notifier)
.search(d.trim()); .search(d.trim());
if (mounted) { if (mounted) {
setState(() { setState(() {
@ -173,12 +195,16 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
}, },
icon: const Icon(Icons.clear)), icon: const Icon(Icons.clear)),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: context.primaryColor), borderSide:
BorderSide(color: context.primaryColor),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: context.primaryColor), borderSide:
BorderSide(color: context.primaryColor),
), ),
border: OutlineInputBorder(borderSide: BorderSide(color: context.primaryColor))), border: OutlineInputBorder(
borderSide:
BorderSide(color: context.primaryColor))),
), ),
), ),
], ],
@ -189,7 +215,8 @@ class _TrackerWidgetSearchState extends ConsumerState<TrackerWidgetSearch> {
} }
} }
trackersSearchraggableMenu(BuildContext context, {required Track track, required bool isManga}) async { trackersSearchraggableMenu(BuildContext context,
{required Track track, required bool isManga}) async {
return await DraggableMenu.open( return await DraggableMenu.open(
context, context,
DraggableMenu( DraggableMenu(
@ -199,7 +226,9 @@ trackersSearchraggableMenu(BuildContext context, {required Track track, required
barItem: Container( barItem: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20))), borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
child: Column( child: Column(
children: [ children: [
Row( Row(

View file

@ -38,10 +38,15 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
_init() async { _init() async {
await Future.delayed(const Duration(microseconds: 100)); await Future.delayed(const Duration(microseconds: 100));
final findManga = final findManga = await ref
await ref.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier).findManga(); .read(
trackStateProvider(track: widget.trackRes, isManga: widget.isManga)
.notifier)
.findManga();
if (mounted) { if (mounted) {
ref.read(tracksProvider(syncId: widget.syncId).notifier).updateTrackManga(findManga!, widget.isManga); ref
.read(tracksProvider(syncId: widget.syncId).notifier)
.updateTrackManga(findManga!, widget.isManga);
} }
} }
@ -51,7 +56,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
final l10nLocale = ref.watch(l10nLocaleStateProvider); final l10nLocale = ref.watch(l10nLocaleStateProvider);
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.isLight ? Theme.of(context).scaffoldBackgroundColor : Colors.black, color: context.isLight
? Theme.of(context).scaffoldBackgroundColor
: Colors.black,
borderRadius: BorderRadius.circular(20)), borderRadius: BorderRadius.circular(20)),
child: Column( child: Column(
children: [ children: [
@ -59,10 +66,12 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
children: [ children: [
if (!widget.hide) if (!widget.hide)
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
child: Container( child: Container(
decoration: decoration: BoxDecoration(
BoxDecoration(borderRadius: BorderRadius.circular(10), color: trackInfos(widget.syncId).$3), borderRadius: BorderRadius.circular(10),
color: trackInfos(widget.syncId).$3),
width: 50, width: 50,
height: 45, height: 45,
child: Image.asset( child: Image.asset(
@ -74,16 +83,22 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
Expanded( Expanded(
child: _elevatedButton( child: _elevatedButton(
context, context,
borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), borderRadius: const BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20)),
onPressed: !widget.hide onPressed: !widget.hide
? () async { ? () async {
final trackSearch = final trackSearch = await trackersSearchraggableMenu(
await trackersSearchraggableMenu(context, isManga: widget.isManga, track: widget.trackRes) context,
as TrackSearch?; isManga: widget.isManga,
track: widget.trackRes) as TrackSearch?;
if (trackSearch != null) { if (trackSearch != null) {
await ref await ref
.read(trackStateProvider(track: null, isManga: widget.isManga).notifier) .read(trackStateProvider(
.setTrackSearch(trackSearch, widget.mangaId, widget.syncId); track: null, isManga: widget.isManga)
.notifier)
.setTrackSearch(
trackSearch, widget.mangaId, widget.syncId);
} }
} }
: null, : null,
@ -95,7 +110,10 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
child: Text( child: Text(
widget.trackRes.title!, widget.trackRes.title!,
style: TextStyle( style: TextStyle(
color: Theme.of(context).textTheme.bodyMedium!.color, color: Theme.of(context)
.textTheme
.bodyMedium!
.color,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
@ -105,7 +123,10 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
), ),
IconButton( IconButton(
onPressed: () { onPressed: () {
ref.read(tracksProvider(syncId: widget.syncId).notifier).deleteTrackManga(widget.trackRes); ref
.read(tracksProvider(syncId: widget.syncId)
.notifier)
.deleteTrackManga(widget.trackRes);
}, },
icon: const Icon(Icons.cancel_outlined)) icon: const Icon(Icons.cancel_outlined))
], ],
@ -130,29 +151,39 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
child: ListView.builder( child: ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: ref itemCount: ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier) .read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getStatusList() .getStatusList()
.length, .length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final status = ref final status = ref
.read( .read(trackStateProvider(
trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier) track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.getStatusList()[index]; .getStatusList()[index];
return RadioListTile( return RadioListTile(
dense: true, dense: true,
contentPadding: const EdgeInsets.all(0), contentPadding: const EdgeInsets.all(0),
value: status, value: status,
groupValue: groupValue: toTrackStatus(
toTrackStatus(widget.trackRes.status, widget.isManga, widget.trackRes.syncId!), widget.trackRes.status,
widget.isManga,
widget.trackRes.syncId!),
onChanged: (value) { onChanged: (value) {
ref ref
.read(trackStateProvider( .read(trackStateProvider(
track: widget.trackRes..status = status, isManga: widget.isManga) track: widget.trackRes
..status = status,
isManga: widget.isManga)
.notifier) .notifier)
.updateManga(); .updateManga();
Navigator.pop(context); Navigator.pop(context);
}, },
title: Text(getTrackStatus(status, context)), title:
Text(getTrackStatus(status, context)),
); );
}, },
)), )),
@ -166,7 +197,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}, },
child: Text( child: Text(
l10n.cancel, l10n.cancel,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
], ],
) )
@ -175,7 +207,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}); });
}, },
text: getTrackStatus( text: getTrackStatus(
toTrackStatus(widget.trackRes.status, widget.isManga, widget.trackRes.syncId!), context)), toTrackStatus(widget.trackRes.status, widget.isManga,
widget.trackRes.syncId!),
context)),
), ),
Expanded( Expanded(
child: _elevatedButton(context, onPressed: () { child: _elevatedButton(context, onPressed: () {
@ -196,10 +230,13 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
NumberPicker( NumberPicker(
value: currentIntValue, value: currentIntValue,
minValue: 0, minValue: 0,
maxValue: widget.trackRes.totalChapter != 0 ? widget.trackRes.totalChapter! : 10000, maxValue: widget.trackRes.totalChapter != 0
? widget.trackRes.totalChapter!
: 10000,
step: 1, step: 1,
haptics: true, haptics: true,
onChanged: (value) => setState(() => currentIntValue = value), onChanged: (value) =>
setState(() => currentIntValue = value),
), ),
], ],
), ),
@ -215,13 +252,16 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}, },
child: Text( child: Text(
l10n.cancel, l10n.cancel,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
ref ref
.read(trackStateProvider( .read(trackStateProvider(
track: widget.trackRes..lastChapterRead = currentIntValue, track: widget.trackRes
..lastChapterRead =
currentIntValue,
isManga: widget.isManga) isManga: widget.isManga)
.notifier) .notifier)
.updateManga(); .updateManga();
@ -229,7 +269,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}, },
child: Text( child: Text(
l10n.ok, l10n.ok,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
], ],
) )
@ -261,21 +302,28 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
value: currentIntValue, value: currentIntValue,
minValue: 0, minValue: 0,
maxValue: ref maxValue: ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga) .read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier) .notifier)
.getScoreMaxValue(), .getScoreMaxValue(),
textMapper: (numberText) { textMapper: (numberText) {
return ref return ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga) .read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier) .notifier)
.getTextMapper(numberText); .getTextMapper(numberText);
}, },
step: ref step: ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga) .read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier) .notifier)
.getScoreStep(), .getScoreStep(),
haptics: true, haptics: true,
onChanged: (value) => setState(() => currentIntValue = value), onChanged: (value) =>
setState(() => currentIntValue = value),
), ),
], ],
), ),
@ -291,13 +339,15 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}, },
child: Text( child: Text(
l10n.cancel, l10n.cancel,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
ref ref
.read(trackStateProvider( .read(trackStateProvider(
track: widget.trackRes..score = currentIntValue, track: widget.trackRes
..score = currentIntValue,
isManga: widget.isManga) isManga: widget.isManga)
.notifier) .notifier)
.updateManga(); .updateManga();
@ -305,7 +355,8 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}, },
child: Text( child: Text(
l10n.ok, l10n.ok,
style: TextStyle(color: context.primaryColor), style: TextStyle(
color: context.primaryColor),
)), )),
], ],
) )
@ -315,7 +366,10 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
}, },
text: widget.trackRes.score != 0 text: widget.trackRes.score != 0
? ref ? ref
.read(trackStateProvider(track: widget.trackRes, isManga: widget.isManga).notifier) .read(trackStateProvider(
track: widget.trackRes,
isManga: widget.isManga)
.notifier)
.displayScore(widget.trackRes.score!) .displayScore(widget.trackRes.score!)
: l10n!.score), : l10n!.score),
) )
@ -324,8 +378,9 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: _elevatedButton(context, borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(20)), child: _elevatedButton(context,
onPressed: () async { borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(20)), onPressed: () async {
DateTime? newDate = await showDatePicker( DateTime? newDate = await showDatePicker(
helpText: l10n!.start_date, helpText: l10n!.start_date,
locale: l10nLocale, locale: l10nLocale,
@ -336,20 +391,27 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
if (newDate == null) return; if (newDate == null) return;
ref ref
.read(trackStateProvider( .read(trackStateProvider(
track: widget.trackRes..startedReadingDate = newDate.millisecondsSinceEpoch, track: widget.trackRes
..startedReadingDate =
newDate.millisecondsSinceEpoch,
isManga: widget.isManga) isManga: widget.isManga)
.notifier) .notifier)
.updateManga(); .updateManga();
}, },
text: widget.trackRes.startedReadingDate != null && text: widget.trackRes.startedReadingDate != null &&
widget.trackRes.startedReadingDate! > DateTime(1970).millisecondsSinceEpoch widget.trackRes.startedReadingDate! >
? dateFormat(widget.trackRes.startedReadingDate.toString(), DateTime(1970).millisecondsSinceEpoch
ref: ref, useRelativeTimesTamps: false, context: context) ? dateFormat(
widget.trackRes.startedReadingDate.toString(),
ref: ref,
useRelativeTimesTamps: false,
context: context)
: l10n!.start_date), : l10n!.start_date),
), ),
Expanded( Expanded(
child: _elevatedButton(context, borderRadius: const BorderRadius.only(bottomRight: Radius.circular(20)), child: _elevatedButton(context,
onPressed: () async { borderRadius: const BorderRadius.only(
bottomRight: Radius.circular(20)), onPressed: () async {
DateTime? newDate = await showDatePicker( DateTime? newDate = await showDatePicker(
helpText: l10n!.finish_date, helpText: l10n!.finish_date,
locale: l10nLocale, locale: l10nLocale,
@ -360,15 +422,21 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
if (newDate == null) return; if (newDate == null) return;
ref ref
.read(trackStateProvider( .read(trackStateProvider(
track: widget.trackRes..finishedReadingDate = newDate.millisecondsSinceEpoch, track: widget.trackRes
..finishedReadingDate =
newDate.millisecondsSinceEpoch,
isManga: widget.isManga) isManga: widget.isManga)
.notifier) .notifier)
.updateManga(); .updateManga();
}, },
text: widget.trackRes.finishedReadingDate != null && text: widget.trackRes.finishedReadingDate != null &&
widget.trackRes.finishedReadingDate! > DateTime(1970).millisecondsSinceEpoch widget.trackRes.finishedReadingDate! >
? dateFormat(widget.trackRes.finishedReadingDate.toString(), DateTime(1970).millisecondsSinceEpoch
ref: ref, useRelativeTimesTamps: false, context: context) ? dateFormat(
widget.trackRes.finishedReadingDate.toString(),
ref: ref,
useRelativeTimesTamps: false,
context: context)
: l10n!.finish_date), : l10n!.finish_date),
) )
], ],
@ -380,20 +448,32 @@ class _TrackerWidgetState extends ConsumerState<TrackerWidget> {
} }
Widget _elevatedButton(BuildContext context, Widget _elevatedButton(BuildContext context,
{required Function()? onPressed, String text = "", Widget? child, BorderRadiusGeometry? borderRadius}) { {required Function()? onPressed,
String text = "",
Widget? child,
BorderRadiusGeometry? borderRadius}) {
return ElevatedButton( return ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
backgroundColor: context.isLight ? Theme.of(context).scaffoldBackgroundColor : Colors.black, backgroundColor: context.isLight
? Theme.of(context).scaffoldBackgroundColor
: Colors.black,
elevation: 0, elevation: 0,
shadowColor: Colors.transparent, shadowColor: Colors.transparent,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide(width: 0, color: context.secondaryColor.withValues(alpha: 0.1)), side: BorderSide(
width: 0,
color: context.secondaryColor.withValues(alpha: 0.1)),
borderRadius: borderRadius ?? BorderRadius.circular(0))), borderRadius: borderRadius ?? BorderRadius.circular(0))),
onPressed: onPressed, onPressed: onPressed,
child: child ?? child: child ??
Text( Text(
text, text,
style: TextStyle(color: Theme.of(context).textTheme.bodyMedium!.color!.withValues(alpha: 0.9)), style: TextStyle(
color: Theme.of(context)
.textTheme
.bodyMedium!
.color!
.withValues(alpha: 0.9)),
)); ));
} }

View file

@ -35,19 +35,24 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
final StorageProvider _storageProvider = StorageProvider(); final StorageProvider _storageProvider = StorageProvider();
void _startDownload(bool? useWifi) async { void _startDownload(bool? useWifi) async {
await ref.watch(downloadChapterProvider(chapter: widget.chapter, useWifi: useWifi).future); await ref.watch(
downloadChapterProvider(chapter: widget.chapter, useWifi: useWifi)
.future);
} }
late final manga = widget.chapter.manga.value!; late final manga = widget.chapter.manga.value!;
void _sendFile() async { void _sendFile() async {
final mangaDir = await _storageProvider.getMangaMainDirectory(widget.chapter); final mangaDir =
final path = await _storageProvider.getMangaChapterDirectory(widget.chapter); await _storageProvider.getMangaMainDirectory(widget.chapter);
final path =
await _storageProvider.getMangaChapterDirectory(widget.chapter);
List<XFile> files = []; List<XFile> files = [];
final cbzFile = File(p.join(mangaDir!.path, "${widget.chapter.name}.cbz")); final cbzFile = File(p.join(mangaDir!.path, "${widget.chapter.name}.cbz"));
final mp4File = File(p.join(mangaDir.path, "${widget.chapter.name!.replaceForbiddenCharacters(' ')}.mp4")); final mp4File = File(p.join(mangaDir.path,
"${widget.chapter.name!.replaceForbiddenCharacters(' ')}.mp4"));
if (cbzFile.existsSync()) { if (cbzFile.existsSync()) {
files = [XFile(cbzFile.path)]; files = [XFile(cbzFile.path)];
} else if (mp4File.existsSync()) { } else if (mp4File.existsSync()) {
@ -61,18 +66,22 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
} }
void _deleteFile() async { void _deleteFile() async {
final mangaDir = await _storageProvider.getMangaMainDirectory(widget.chapter); final mangaDir =
final path = await _storageProvider.getMangaChapterDirectory(widget.chapter); await _storageProvider.getMangaMainDirectory(widget.chapter);
final path =
await _storageProvider.getMangaChapterDirectory(widget.chapter);
try { try {
try { try {
final cbzFile = File(p.join(mangaDir!.path, "${widget.chapter.name}.cbz")); final cbzFile =
File(p.join(mangaDir!.path, "${widget.chapter.name}.cbz"));
if (cbzFile.existsSync()) { if (cbzFile.existsSync()) {
cbzFile.deleteSync(); cbzFile.deleteSync();
} }
} catch (_) {} } catch (_) {}
try { try {
final mp4File = File(p.join(mangaDir!.path, "${widget.chapter.name!.replaceForbiddenCharacters(' ')}.mp4")); final mp4File = File(p.join(mangaDir!.path,
"${widget.chapter.name!.replaceForbiddenCharacters(' ')}.mp4"));
if (mp4File.existsSync()) { if (mp4File.existsSync()) {
mp4File.deleteSync(); mp4File.deleteSync();
} }
@ -80,7 +89,11 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
path!.deleteSync(recursive: true); path!.deleteSync(recursive: true);
} catch (_) {} } catch (_) {}
isar.writeTxnSync(() { isar.writeTxnSync(() {
int id = isar.downloads.filter().chapterIdEqualTo(widget.chapter.id!).findFirstSync()!.id!; int id = isar.downloads
.filter()
.chapterIdEqualTo(widget.chapter.id!)
.findFirstSync()!
.id!;
isar.downloads.deleteSync(id); isar.downloads.deleteSync(id);
}); });
} }
@ -111,7 +124,10 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
child: Icon( child: Icon(
size: 25, size: 25,
Icons.check_circle, Icons.check_circle,
color: Theme.of(context).iconTheme.color!.withValues(alpha: 0.7), color: Theme.of(context)
.iconTheme
.color!
.withValues(alpha: 0.7),
), ),
onSelected: (value) { onSelected: (value) {
if (value == 0) { if (value == 0) {
@ -125,7 +141,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
PopupMenuItem(value: 1, child: Text(l10n.delete)), PopupMenuItem(value: 1, child: Text(l10n.delete)),
], ],
) )
: entries.first.isStartDownload! && entries.first.succeeded == 0 : entries.first.isStartDownload! &&
entries.first.succeeded == 0
? SizedBox( ? SizedBox(
height: 41, height: 41,
width: 35, width: 35,
@ -144,7 +161,9 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
} }
}, },
itemBuilder: (context) => [ itemBuilder: (context) => [
PopupMenuItem(value: 1, child: Text(l10n.start_downloading)), PopupMenuItem(
value: 1,
child: Text(l10n.start_downloading)),
PopupMenuItem(value: 0, child: Text(l10n.cancel)), PopupMenuItem(value: 0, child: Text(l10n.cancel)),
], ],
)) ))
@ -159,19 +178,25 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
Align( Align(
alignment: Alignment.center, alignment: Alignment.center,
child: TweenAnimationBuilder<double>( child: TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 250), duration:
const Duration(milliseconds: 250),
curve: Curves.easeInOut, curve: Curves.easeInOut,
tween: Tween<double>( tween: Tween<double>(
begin: 0, begin: 0,
end: (entries.first.succeeded! / entries.first.total!), end: (entries.first.succeeded! /
entries.first.total!),
), ),
builder: (context, value, _) => SizedBox( builder: (context, value, _) =>
SizedBox(
height: 2, height: 2,
width: 2, width: 2,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 19, strokeWidth: 19,
value: value, value: value,
color: Theme.of(context).iconTheme.color!.withValues(alpha: 0.7), color: Theme.of(context)
.iconTheme
.color!
.withValues(alpha: 0.7),
), ),
), ),
), ),
@ -180,9 +205,15 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
alignment: Alignment.center, alignment: Alignment.center,
child: Icon( child: Icon(
Icons.arrow_downward_sharp, Icons.arrow_downward_sharp,
color: (entries.first.succeeded! / entries.first.total!) > 0.5 color: (entries.first.succeeded! /
? Theme.of(context).scaffoldBackgroundColor entries.first.total!) >
: Theme.of(context).iconTheme.color!.withValues(alpha: 0.7), 0.5
? Theme.of(context)
.scaffoldBackgroundColor
: Theme.of(context)
.iconTheme
.color!
.withValues(alpha: 0.7),
)), )),
], ],
), ),
@ -198,8 +229,11 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
} }
}, },
itemBuilder: (context) => [ itemBuilder: (context) => [
PopupMenuItem(value: 1, child: Text(l10n.start_downloading)), PopupMenuItem(
PopupMenuItem(value: 0, child: Text(l10n.cancel)), value: 1,
child: Text(l10n.start_downloading)),
PopupMenuItem(
value: 0, child: Text(l10n.cancel)),
], ],
)) ))
: entries.first.succeeded == 0 : entries.first.succeeded == 0
@ -212,7 +246,10 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}, },
icon: Icon( icon: Icon(
FontAwesomeIcons.circleDown, FontAwesomeIcons.circleDown,
color: Theme.of(context).iconTheme.color!.withValues(alpha: 0.7), color: Theme.of(context)
.iconTheme
.color!
.withValues(alpha: 0.7),
size: 25, size: 25,
)) ))
: SizedBox( : SizedBox(
@ -235,7 +272,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
} }
}, },
itemBuilder: (context) => [ itemBuilder: (context) => [
PopupMenuItem(value: 0, child: Text(l10n.retry)), PopupMenuItem(
value: 0, child: Text(l10n.retry)),
], ],
)); ));
} }
@ -255,7 +293,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
} }
}, },
itemBuilder: (context) => [ itemBuilder: (context) => [
PopupMenuItem(value: 1, child: Text(l10n.start_downloading)), PopupMenuItem(
value: 1, child: Text(l10n.start_downloading)),
PopupMenuItem(value: 0, child: Text(l10n.cancel)), PopupMenuItem(value: 0, child: Text(l10n.cancel)),
], ],
)) ))
@ -287,7 +326,10 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
[]; [];
await FileDownloader().cancelTasksWithIds(_pageUrls); await FileDownloader().cancelTasksWithIds(_pageUrls);
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
final chapterD = isar.downloads.filter().chapterIdEqualTo(widget.chapter.id!).findFirstSync(); final chapterD = isar.downloads
.filter()
.chapterIdEqualTo(widget.chapter.id!)
.findFirstSync();
if (chapterD != null) { if (chapterD != null) {
final verifyId = isar.downloads.getSync(chapterD.id!); final verifyId = isar.downloads.getSync(chapterD.id!);
isar.writeTxnSync(() { isar.writeTxnSync(() {

View file

@ -7,8 +7,8 @@ import 'package:path/path.dart' as path;
part 'convert_to_cbz.g.dart'; part 'convert_to_cbz.g.dart';
@riverpod @riverpod
Future<List<String>> convertToCBZ( Future<List<String>> convertToCBZ(Ref ref, String chapterDir, String mangaDir,
Ref ref, String chapterDir, String mangaDir, String chapterName, List<String> pageList) async { String chapterName, List<String> pageList) async {
return compute(_convertToCBZ, (chapterDir, mangaDir, chapterName, pageList)); return compute(_convertToCBZ, (chapterDir, mangaDir, chapterName, pageList));
} }

View file

@ -41,8 +41,9 @@ Future<List<PageUrl>> downloadChapter(
bool isOk = false; bool isOk = false;
final manga = chapter.manga.value!; final manga = chapter.manga.value!;
final path1 = await storageProvider.getDirectory(); final path1 = await storageProvider.getDirectory();
String scanlator = String scanlator = (chapter.scanlator?.isNotEmpty ?? false)
(chapter.scanlator?.isNotEmpty ?? false) ? "${chapter.scanlator!.replaceForbiddenCharacters('_')}_" : ""; ? "${chapter.scanlator!.replaceForbiddenCharacters('_')}_"
: "";
final chapterName = chapter.name!.replaceForbiddenCharacters(' '); final chapterName = chapter.name!.replaceForbiddenCharacters(' ');
final isManga = manga.isManga!; final isManga = manga.isManga!;
@ -68,12 +69,13 @@ Future<List<PageUrl>> downloadChapter(
Future<void> processConvert() async { Future<void> processConvert() async {
if (hasM3U8File) { if (hasM3U8File) {
await m3u8Downloader?.mergeTsToMp4(p.join(path!.path, "$chapterName.mp4"), p.join(path.path, chapterName)); await m3u8Downloader?.mergeTsToMp4(p.join(path!.path, "$chapterName.mp4"),
p.join(path.path, chapterName));
} else { } else {
if (ref.watch(saveAsCBZArchiveStateProvider)) { if (ref.watch(saveAsCBZArchiveStateProvider)) {
await ref.watch( await ref.watch(convertToCBZProvider(path!.path, mangaDir!.path,
convertToCBZProvider(path!.path, mangaDir!.path, chapter.name!, pageUrls.map((e) => e.url).toList()) chapter.name!, pageUrls.map((e) => e.url).toList())
.future); .future);
} }
} }
} }
@ -86,12 +88,17 @@ Future<List<PageUrl>> downloadChapter(
chapterPageUrls.add(chapterPageUrl); chapterPageUrls.add(chapterPageUrl);
} }
} }
final chapterPageHeaders = pageUrls.map((e) => e.headers == null ? null : jsonEncode(e.headers)).toList(); final chapterPageHeaders = pageUrls
.map((e) => e.headers == null ? null : jsonEncode(e.headers))
.toList();
chapterPageUrls.add(ChapterPageurls() chapterPageUrls.add(ChapterPageurls()
..chapterId = chapter.id ..chapterId = chapter.id
..urls = pageUrls.map((e) => e.url).toList() ..urls = pageUrls.map((e) => e.url).toList()
..headers = chapterPageHeaders.first != null ? chapterPageHeaders.map((e) => e.toString()).toList() : null); ..headers = chapterPageHeaders.first != null
isar.writeTxnSync(() => isar.settings.putSync(settings..chapterPageUrlsList = chapterPageUrls)); ? chapterPageHeaders.map((e) => e.toString()).toList()
: null);
isar.writeTxnSync(() =>
isar.settings.putSync(settings..chapterPageUrlsList = chapterPageUrls));
} }
if (isManga) { if (isManga) {
@ -108,9 +115,13 @@ Future<List<PageUrl>> downloadChapter(
} else { } else {
ref.read(getVideoListProvider(episode: chapter).future).then((value) async { ref.read(getVideoListProvider(episode: chapter).future).then((value) async {
final m3u8Urls = value.$1 final m3u8Urls = value.$1
.where((element) => element.originalUrl.endsWith(".m3u8") || element.originalUrl.endsWith(".m3u")) .where((element) =>
element.originalUrl.endsWith(".m3u8") ||
element.originalUrl.endsWith(".m3u"))
.toList();
final nonM3u8Urls = value.$1
.where((element) => element.originalUrl.isMediaVideo())
.toList(); .toList();
final nonM3u8Urls = value.$1.where((element) => element.originalUrl.isMediaVideo()).toList();
nonM3U8File = nonM3u8Urls.isNotEmpty; nonM3U8File = nonM3u8Urls.isNotEmpty;
hasM3U8File = nonM3U8File ? false : m3u8Urls.isNotEmpty; hasM3U8File = nonM3U8File ? false : m3u8Urls.isNotEmpty;
final videosUrls = nonM3U8File ? nonM3u8Urls : m3u8Urls; final videosUrls = nonM3U8File ? nonM3u8Urls : m3u8Urls;
@ -121,9 +132,12 @@ Future<List<PageUrl>> downloadChapter(
m3u8Url: videosUrls.first.url, m3u8Url: videosUrls.first.url,
downloadDir: p.join(path!.path, chapterName), downloadDir: p.join(path!.path, chapterName),
headers: videosUrls.first.headers ?? {}); headers: videosUrls.first.headers ?? {});
(tsList, tsKey, tsIv, m3u8MediaSequence) = await m3u8Downloader!.getTsList(); (tsList, tsKey, tsIv, m3u8MediaSequence) =
await m3u8Downloader!.getTsList();
} }
pageUrls = hasM3U8File ? [...tsList.map((e) => PageUrl(e.url))] : [PageUrl(videosUrls.first.url)]; pageUrls = hasM3U8File
? [...tsList.map((e) => PageUrl(e.url))]
: [PageUrl(videosUrls.first.url)];
videoHeader.addAll(videosUrls.first.headers ?? {}); videoHeader.addAll(videosUrls.first.headers ?? {});
isOk = true; isOk = true;
} }
@ -140,12 +154,18 @@ Future<List<PageUrl>> downloadChapter(
if (pageUrls.isNotEmpty) { if (pageUrls.isNotEmpty) {
bool cbzFileExist = bool cbzFileExist =
await File(p.join(mangaDir!.path, "${chapter.name}.cbz")).exists() && ref.watch(saveAsCBZArchiveStateProvider); await File(p.join(mangaDir!.path, "${chapter.name}.cbz")).exists() &&
bool mp4FileExist = await File(p.join(mangaDir.path, "$chapterName.mp4")).exists(); ref.watch(saveAsCBZArchiveStateProvider);
bool mp4FileExist =
await File(p.join(mangaDir.path, "$chapterName.mp4")).exists();
if (!cbzFileExist && isManga || !mp4FileExist && !isManga) { if (!cbzFileExist && isManga || !mp4FileExist && !isManga) {
for (var index = 0; index < pageUrls.length; index++) { for (var index = 0; index < pageUrls.length; index++) {
final path2 = Directory(p.join(path1.path, "downloads", isManga ? "Manga" : "Anime", final path2 = Directory(p.join(
"${manga.source} (${manga.lang!.toUpperCase()})", manga.name!.replaceForbiddenCharacters('_'))); path1.path,
"downloads",
isManga ? "Manga" : "Anime",
"${manga.source} (${manga.lang!.toUpperCase()})",
manga.name!.replaceForbiddenCharacters('_')));
if (!(await path2.exists())) { if (!(await path2.exists())) {
await path2.create(recursive: true); await path2.create(recursive: true);
} }
@ -156,7 +176,10 @@ Future<List<PageUrl>> downloadChapter(
} }
final page = pageUrls[index]; final page = pageUrls[index];
final cookie = MClient.getCookiesPref(page.url); final cookie = MClient.getCookiesPref(page.url);
final headers = isManga ? ref.watch(headersProvider(source: manga.source!, lang: manga.lang!)) : videoHeader; final headers = isManga
? ref.watch(
headersProvider(source: manga.source!, lang: manga.lang!))
: videoHeader;
if (cookie.isNotEmpty) { if (cookie.isNotEmpty) {
final userAgent = isar.settings.getSync(227)!.userAgent!; final userAgent = isar.settings.getSync(227)!.userAgent!;
headers.addAll(cookie); headers.addAll(cookie);
@ -166,7 +189,8 @@ Future<List<PageUrl>> downloadChapter(
pageHeaders.addAll(page.headers ?? {}); pageHeaders.addAll(page.headers ?? {});
if (isManga) { if (isManga) {
final file = File(p.join(tempDir.path, "Mangayomi", finalPath, "${padIndex(index + 1)}.jpg")); final file = File(p.join(tempDir.path, "Mangayomi", finalPath,
"${padIndex(index + 1)}.jpg"));
if (file.existsSync()) { if (file.existsSync()) {
Directory(path.path).createSync(recursive: true); Directory(path.path).createSync(recursive: true);
await file.copy(p.join(path.path, "${padIndex(index + 1)}.jpg")); await file.copy(p.join(path.path, "${padIndex(index + 1)}.jpg"));
@ -175,7 +199,8 @@ Future<List<PageUrl>> downloadChapter(
if (!(await path.exists())) { if (!(await path.exists())) {
await path.create(); await path.create();
} }
if (!(await File(p.join(path.path, "${padIndex(index + 1)}.jpg")).exists())) { if (!(await File(p.join(path.path, "${padIndex(index + 1)}.jpg"))
.exists())) {
tasks.add(DownloadTask( tasks.add(DownloadTask(
taskId: page.url, taskId: page.url,
headers: pageHeaders, headers: pageHeaders,
@ -190,16 +215,21 @@ Future<List<PageUrl>> downloadChapter(
} }
} }
} else { } else {
final file = File(p.join(tempDir.path, "Mangayomi", finalPath, "$chapterName.mp4")); final file = File(
p.join(tempDir.path, "Mangayomi", finalPath, "$chapterName.mp4"));
if (file.existsSync()) { if (file.existsSync()) {
await file.copy(p.join(path.path, "$chapterName.mp4")); await file.copy(p.join(path.path, "$chapterName.mp4"));
await file.delete(); await file.delete();
} else if (hasM3U8File) { } else if (hasM3U8File) {
final tempFile = File(p.join(tempDir.path, "Mangayomi", finalPath, chapterName, "TS_${index + 1}.ts")); final tempFile = File(p.join(tempDir.path, "Mangayomi", finalPath,
final file = File(p.join(path.path, chapterName, "TS_${index + 1}.ts")); chapterName, "TS_${index + 1}.ts"));
final file =
File(p.join(path.path, chapterName, "TS_${index + 1}.ts"));
if (tempFile.existsSync()) { if (tempFile.existsSync()) {
Directory(p.join(path.path, chapterName)).createSync(recursive: true); Directory(p.join(path.path, chapterName))
await tempFile.copy(p.join(path.path, chapterName, "TS_${index + 1}.ts")); .createSync(recursive: true);
await tempFile
.copy(p.join(path.path, chapterName, "TS_${index + 1}.ts"));
await tempFile.delete(); await tempFile.delete();
} else if (!(file.existsSync())) { } else if (!(file.existsSync())) {
tasks.add(DownloadTask( tasks.add(DownloadTask(
@ -264,7 +294,10 @@ Future<List<PageUrl>> downloadChapter(
if (succeeded == tasks.length) { if (succeeded == tasks.length) {
await processConvert(); await processConvert();
} }
bool isEmpty = isar.downloads.filter().chapterIdEqualTo(chapter.id!).isEmptySync(); bool isEmpty = isar.downloads
.filter()
.chapterIdEqualTo(chapter.id!)
.isEmptySync();
if (isEmpty) { if (isEmpty) {
final download = Download( final download = Download(
succeeded: succeeded, succeeded: succeeded,
@ -279,7 +312,10 @@ Future<List<PageUrl>> downloadChapter(
isar.downloads.putSync(download..chapter.value = chapter); isar.downloads.putSync(download..chapter.value = chapter);
}); });
} else { } else {
final download = isar.downloads.filter().chapterIdEqualTo(chapter.id!).findFirstSync()!; final download = isar.downloads
.filter()
.chapterIdEqualTo(chapter.id!)
.findFirstSync()!;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.downloads.putSync(download isar.downloads.putSync(download
..succeeded = succeeded ..succeeded = succeeded
@ -292,7 +328,10 @@ Future<List<PageUrl>> downloadChapter(
taskProgressCallback: (taskProgress) async { taskProgressCallback: (taskProgress) async {
final progress = taskProgress.progress; final progress = taskProgress.progress;
if (!isManga && !hasM3U8File) { if (!isManga && !hasM3U8File) {
bool isEmpty = isar.downloads.filter().chapterIdEqualTo(chapter.id!).isEmptySync(); bool isEmpty = isar.downloads
.filter()
.chapterIdEqualTo(chapter.id!)
.isEmptySync();
if (isEmpty) { if (isEmpty) {
final download = Download( final download = Download(
succeeded: (progress * 100).toInt(), succeeded: (progress * 100).toInt(),
@ -307,7 +346,10 @@ Future<List<PageUrl>> downloadChapter(
isar.downloads.putSync(download..chapter.value = chapter); isar.downloads.putSync(download..chapter.value = chapter);
}); });
} else { } else {
final download = isar.downloads.filter().chapterIdEqualTo(chapter.id!).findFirstSync()!; final download = isar.downloads
.filter()
.chapterIdEqualTo(chapter.id!)
.findFirstSync()!;
isar.writeTxnSync(() { isar.writeTxnSync(() {
isar.downloads.putSync(download isar.downloads.putSync(download
..succeeded = (progress * 100).toInt() ..succeeded = (progress * 100).toInt()
@ -317,11 +359,14 @@ Future<List<PageUrl>> downloadChapter(
} }
} }
if (progress == 1.0) { if (progress == 1.0) {
final file = File(p.join(tempDir.path, taskProgress.task.directory, taskProgress.task.filename)); final file = File(p.join(tempDir.path, taskProgress.task.directory,
taskProgress.task.filename));
if (hasM3U8File) { if (hasM3U8File) {
final newFile = await file.copy(p.join(path!.path, chapterName, taskProgress.task.filename)); final newFile = await file.copy(
p.join(path!.path, chapterName, taskProgress.task.filename));
await file.delete(); await file.delete();
await m3u8Downloader?.processBytes(newFile, tsKey, tsIv, m3u8MediaSequence); await m3u8Downloader?.processBytes(
newFile, tsKey, tsIv, m3u8MediaSequence);
} else { } else {
await file.copy(p.join(path!.path, taskProgress.task.filename)); await file.copy(p.join(path!.path, taskProgress.task.filename));
await file.delete(); await file.delete();

View file

@ -31,7 +31,11 @@ class MangaHomeScreen extends ConsumerStatefulWidget {
final bool isLatest; final bool isLatest;
final String query; final String query;
const MangaHomeScreen( const MangaHomeScreen(
{required this.source, this.query = "", this.isSearch = false, this.isLatest = false, super.key}); {required this.source,
this.query = "",
this.isSearch = false,
this.isLatest = false,
super.key});
@override @override
ConsumerState<MangaHomeScreen> createState() => _MangaHomeScreenState(); ConsumerState<MangaHomeScreen> createState() => _MangaHomeScreenState();
@ -86,9 +90,14 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
source: source, source: source,
page: _page + 1, page: _page + 1,
).future); ).future);
} else if (_selectedIndex == 2 && (_isSearch && _query.isNotEmpty) || _isFiltering) { } else if (_selectedIndex == 2 && (_isSearch && _query.isNotEmpty) ||
mangaRes = await ref _isFiltering) {
.watch(searchProvider(source: source, query: _query, page: _page + 1, filterList: filters).future); mangaRes = await ref.watch(searchProvider(
source: source,
query: _query,
page: _page + 1,
filterList: filters)
.future);
} }
} }
if (mangaRes!.list.isNotEmpty) { if (mangaRes!.list.isNotEmpty) {
@ -115,8 +124,10 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final supportsLatest = ref.watch(supportsLatestProvider(source: source)); final supportsLatest = ref.watch(supportsLatestProvider(source: source));
final filterList = getFilterList(source: source); final filterList = getFilterList(source: source);
if (_selectedIndex == 2 && (_isSearch && _query.isNotEmpty) || _isFiltering) { if (_selectedIndex == 2 && (_isSearch && _query.isNotEmpty) ||
_getManga = ref.watch(searchProvider(source: source, query: _query, page: 1, filterList: filters)); _isFiltering) {
_getManga = ref.watch(searchProvider(
source: source, query: _query, page: 1, filterList: filters));
} else if (_selectedIndex == 1 && !_isSearch && _query.isEmpty) { } else if (_selectedIndex == 1 && !_isSearch && _query.isEmpty) {
_getManga = ref.watch(getLatestUpdatesProvider(source: source, page: 1)); _getManga = ref.watch(getLatestUpdatesProvider(source: source, page: 1));
} else if (_selectedIndex == 0 && !_isSearch && _query.isEmpty) { } else if (_selectedIndex == 0 && !_isSearch && _query.isEmpty) {
@ -125,7 +136,9 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
final l10n = context.l10n; final l10n = context.l10n;
final displayType = ref.watch(mangaHomeDisplayTypeStateProvider); final displayType = ref.watch(mangaHomeDisplayTypeStateProvider);
final displayTypeIcon = switch (displayType) { final displayTypeIcon = switch (displayType) {
DisplayType.comfortableGrid || DisplayType.compactGrid => Icons.view_module, DisplayType.comfortableGrid ||
DisplayType.compactGrid =>
Icons.view_module,
_ => Icons.view_list, _ => Icons.view_list,
}; };
return Scaffold( return Scaffold(
@ -179,13 +192,16 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
_isSearch = true; _isSearch = true;
}); });
}, },
icon: Icon(Icons.search, color: Theme.of(context).hintColor)), icon:
Icon(Icons.search, color: Theme.of(context).hintColor)),
PopupMenuButton( PopupMenuButton(
popUpAnimationStyle: popupAnimationStyle, popUpAnimationStyle: popupAnimationStyle,
icon: Icon(displayTypeIcon), icon: Icon(displayTypeIcon),
itemBuilder: (context) { itemBuilder: (context) {
final displayType = ref.watch(mangaHomeDisplayTypeStateProvider); final displayType =
final displayTypeNotifier = ref.read(mangaHomeDisplayTypeStateProvider.notifier); ref.watch(mangaHomeDisplayTypeStateProvider);
final displayTypeNotifier =
ref.read(mangaHomeDisplayTypeStateProvider.notifier);
return [ return [
PopupMenuItem<int>( PopupMenuItem<int>(
value: 0, value: 0,
@ -242,11 +258,17 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
}, },
onSelected: (value) async { onSelected: (value) async {
if (value == 0) { if (value == 0) {
final baseUrl = ref.watch(sourceBaseUrlProvider(source: source)); final baseUrl =
Map<String, dynamic> data = {'url': baseUrl, 'sourceId': source.id.toString(), 'title': ''}; ref.watch(sourceBaseUrlProvider(source: source));
Map<String, dynamic> data = {
'url': baseUrl,
'sourceId': source.id.toString(),
'title': ''
};
context.push("/mangawebview", extra: data); context.push("/mangawebview", extra: data);
} else { } else {
final res = await context.push('/extension_detail', extra: source); final res =
await context.push('/extension_detail', extra: source);
if (res != null && mounted) { if (res != null && mounted) {
setState(() { setState(() {
source = res as Source; source = res as Source;
@ -284,7 +306,8 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
if (index == 2) { if (index == 2) {
final result = await showModalBottomSheet( final result = await showModalBottomSheet(
context: context, context: context,
builder: (context) => StatefulBuilder(builder: (context, setState) { builder: (context) =>
StatefulBuilder(builder: (context, setState) {
return Column( return Column(
children: [ children: [
Padding( Padding(
@ -294,20 +317,25 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
TextButton( TextButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
filters = getFilterList(source: source); filters = getFilterList(
source: source);
}); });
}, },
child: Text(l10n.reset), child: Text(l10n.reset),
), ),
const Spacer(), const Spacer(),
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: context.primaryColor), style: ElevatedButton.styleFrom(
backgroundColor:
context.primaryColor),
onPressed: () { onPressed: () {
Navigator.pop(context, 'filter'); Navigator.pop(context, 'filter');
}, },
child: Text( child: Text(
l10n.filter, l10n.filter,
style: TextStyle(color: Theme.of(context).scaffoldBackgroundColor), style: TextStyle(
color: Theme.of(context)
.scaffoldBackgroundColor),
), ),
), ),
], ],
@ -339,8 +367,11 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
}); });
} }
_getManga = ref _getManga = ref.refresh(searchProvider(
.refresh(searchProvider(source: source, query: _query, page: 1, filterList: filters)); source: source,
query: _query,
page: 1,
filterList: filters));
} }
} else { } else {
_mangaList.clear(); _mangaList.clear();
@ -385,7 +416,8 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
_mangaList.addAll(data.list); _mangaList.addAll(data.list);
} }
Widget buildProgressIndicator() { Widget buildProgressIndicator() {
return !(data!.list.isNotEmpty && (data.hasNextPage || _hasNextPage)) return !(data!.list.isNotEmpty &&
(data.hasNextPage || _hasNextPage))
? Container() ? Container()
: _isLoading : _isLoading
? const Center( ? const Center(
@ -401,7 +433,9 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))), shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5))),
onPressed: () { onPressed: () {
if (!_getManga!.isLoading) { if (!_getManga!.isLoading) {
if (mounted) { if (mounted) {
@ -420,15 +454,19 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
} }
}, },
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Text( Text(
l10n.load_more, l10n.load_more,
style: const TextStyle(overflow: TextOverflow.ellipsis), style: const TextStyle(
overflow: TextOverflow.ellipsis),
maxLines: 2, maxLines: 2,
), ),
const Icon(Icons.arrow_forward_outlined), const Icon(
Icons.arrow_forward_outlined),
], ],
)), )),
); );
@ -438,8 +476,12 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
return Center(child: Text(l10n.no_result)); return Center(child: Text(l10n.no_result));
} }
_scrollController.addListener(() { _scrollController.addListener(() {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { if (_scrollController.position.pixels ==
if (_mangaList.isNotEmpty && (_hasNextPage) && !_isLoading && !_getManga!.isLoading) { _scrollController.position.maxScrollExtent) {
if (_mangaList.isNotEmpty &&
(_hasNextPage) &&
!_isLoading &&
!_getManga!.isLoading) {
if (mounted) { if (mounted) {
setState(() { setState(() {
_isLoading = true; _isLoading = true;
@ -457,9 +499,13 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
} }
}); });
_length = source.isFullData! ? _fullDataLength : _mangaList.length; _length =
_length = (_mangaList.length < _length ? _mangaList.length : _length); source.isFullData! ? _fullDataLength : _mangaList.length;
final isComfortableGrid = displayType == DisplayType.comfortableGrid; _length = (_mangaList.length < _length
? _mangaList.length
: _length);
final isComfortableGrid =
displayType == DisplayType.comfortableGrid;
return Padding( return Padding(
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: Column( child: Column(
@ -474,16 +520,21 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
return buildProgressIndicator(); return buildProgressIndicator();
} }
return MangaHomeImageCardListTile( return MangaHomeImageCardListTile(
isManga: source.isManga ?? true, manga: _mangaList[index], source: source); isManga: source.isManga ?? true,
manga: _mangaList[index],
source: source);
}) })
: Consumer(builder: (context, ref, child) { : Consumer(builder: (context, ref, child) {
final gridSize = ref.watch(libraryGridSizeStateProvider(isManga: source.isManga!)); final gridSize = ref.watch(
libraryGridSizeStateProvider(
isManga: source.isManga!));
return GridViewWidget( return GridViewWidget(
gridSize: gridSize, gridSize: gridSize,
controller: _scrollController, controller: _scrollController,
itemCount: _length + 1, itemCount: _length + 1,
childAspectRatio: isComfortableGrid ? 0.642 : 0.69, childAspectRatio:
isComfortableGrid ? 0.642 : 0.69,
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (index == _length) { if (index == _length) {
return buildProgressIndicator(); return buildProgressIndicator();
@ -514,12 +565,22 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
children: [ children: [
IconButton( IconButton(
onPressed: () { onPressed: () {
if (_selectedIndex == 2 && (_isSearch && _query.isNotEmpty) || _isFiltering) { if (_selectedIndex == 2 &&
ref.invalidate( (_isSearch && _query.isNotEmpty) ||
searchProvider(source: source, query: _query, page: 1, filterList: filters)); _isFiltering) {
} else if (_selectedIndex == 1 && !_isSearch && _query.isEmpty) { ref.invalidate(searchProvider(
ref.invalidate(getLatestUpdatesProvider(source: source, page: 1)); source: source,
} else if (_selectedIndex == 0 && !_isSearch && _query.isEmpty) { query: _query,
page: 1,
filterList: filters));
} else if (_selectedIndex == 1 &&
!_isSearch &&
_query.isEmpty) {
ref.invalidate(getLatestUpdatesProvider(
source: source, page: 1));
} else if (_selectedIndex == 0 &&
!_isSearch &&
_query.isEmpty) {
ref.invalidate(getPopularProvider( ref.invalidate(getPopularProvider(
source: source, source: source,
page: 1, page: 1,
@ -537,12 +598,14 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
children: [ children: [
IconButton( IconButton(
onPressed: () async { onPressed: () async {
final baseUrl = ref.watch(sourceBaseUrlProvider(source: source)); final baseUrl = ref.watch(
sourceBaseUrlProvider(source: source));
Map<String, dynamic> data = { Map<String, dynamic> data = {
'url': baseUrl, 'url': baseUrl,
'sourceId': source.id.toString(), 'sourceId': source.id.toString(),
'title': '', 'title': '',
"hasCloudFlare": source.hasCloudflare ?? false "hasCloudFlare":
source.hasCloudflare ?? false
}; };
context.push("/mangawebview", extra: data); context.push("/mangawebview", extra: data);
}, },
@ -580,7 +643,11 @@ class MangaHomeImageCard extends ConsumerStatefulWidget {
final Source source; final Source source;
final bool isComfortableGrid; final bool isComfortableGrid;
const MangaHomeImageCard( const MangaHomeImageCard(
{super.key, required this.manga, required this.source, required this.isManga, required this.isComfortableGrid}); {super.key,
required this.manga,
required this.source,
required this.isManga,
required this.isComfortableGrid});
@override @override
ConsumerState<MangaHomeImageCard> createState() => _MangaHomeImageCardState(); ConsumerState<MangaHomeImageCard> createState() => _MangaHomeImageCardState();
@ -607,19 +674,28 @@ class MangaHomeImageCardListTile extends ConsumerStatefulWidget {
final MManga manga; final MManga manga;
final bool isManga; final bool isManga;
final Source source; final Source source;
const MangaHomeImageCardListTile({super.key, required this.manga, required this.source, required this.isManga}); const MangaHomeImageCardListTile(
{super.key,
required this.manga,
required this.source,
required this.isManga});
@override @override
ConsumerState<MangaHomeImageCardListTile> createState() => _MangaHomeImageCardListTileState(); ConsumerState<MangaHomeImageCardListTile> createState() =>
_MangaHomeImageCardListTileState();
} }
class _MangaHomeImageCardListTileState extends ConsumerState<MangaHomeImageCardListTile> class _MangaHomeImageCardListTileState
extends ConsumerState<MangaHomeImageCardListTile>
with AutomaticKeepAliveClientMixin<MangaHomeImageCardListTile> { with AutomaticKeepAliveClientMixin<MangaHomeImageCardListTile> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
return MangaImageCardListTileWidget(getMangaDetail: widget.manga, source: widget.source, isManga: widget.isManga); return MangaImageCardListTileWidget(
getMangaDetail: widget.manga,
source: widget.source,
isManga: widget.isManga);
} }
@override @override

View file

@ -5,7 +5,8 @@ import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
class FilterWidget extends StatelessWidget { class FilterWidget extends StatelessWidget {
final List<dynamic> filterList; final List<dynamic> filterList;
final Function(List<dynamic>) onChanged; final Function(List<dynamic>) onChanged;
const FilterWidget({super.key, required this.onChanged, required this.filterList}); const FilterWidget(
{super.key, required this.onChanged, required this.filterList});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -83,14 +84,18 @@ class FilterWidget extends StatelessWidget {
final selected = filterState.values[filterState.state.index] == e; final selected = filterState.values[filterState.state.index] == e;
return ListTile( return ListTile(
dense: true, dense: true,
leading: Icon(ascending ? Icons.arrow_upward_rounded : Icons.arrow_downward_rounded, leading: Icon(
ascending
? Icons.arrow_upward_rounded
: Icons.arrow_downward_rounded,
color: selected ? null : Colors.transparent), color: selected ? null : Colors.transparent),
title: Text(e.name), title: Text(e.name),
onTap: () { onTap: () {
if (selected) { if (selected) {
filterState.state.ascending = !ascending; filterState.state.ascending = !ascending;
} else { } else {
filterState.state.index = filterState.values.indexWhere((element) => element == e); filterState.state.index = filterState.values
.indexWhere((element) => element == e);
} }
filterList[idx] = filterState; filterList[idx] = filterState;
onChanged(filterList); onChanged(filterList);
@ -113,20 +118,24 @@ class FilterWidget extends StatelessWidget {
Expanded( Expanded(
child: DropdownButtonHideUnderline( child: DropdownButtonHideUnderline(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 25), padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 25),
child: DropdownButton( child: DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down), icon: const Icon(Icons.keyboard_arrow_down),
isExpanded: true, isExpanded: true,
value: filterState.values[filterState.state], value: filterState.values[filterState.state],
hint: Text(filterState.name, style: const TextStyle(fontSize: 13)), hint: Text(filterState.name,
style: const TextStyle(fontSize: 13)),
items: filterState.values items: filterState.values
.map((e) => DropdownMenuItem( .map((e) => DropdownMenuItem(
value: e, value: e,
child: Text(e.name, style: const TextStyle(fontSize: 13)), child: Text(e.name,
style: const TextStyle(fontSize: 13)),
)) ))
.toList(), .toList(),
onChanged: (value) { onChanged: (value) {
filterState.state = filterState.values.indexWhere((element) => element == value); filterState.state = filterState.values
.indexWhere((element) => element == value);
onChanged(filterList); onChanged(filterList);
}, },
), ),
@ -147,10 +156,15 @@ class SeachFormTextFieldWidget extends StatefulWidget {
final String labelText; final String labelText;
final String text; final String text;
final Function(String) onChanged; final Function(String) onChanged;
const SeachFormTextFieldWidget({super.key, required this.text, required this.onChanged, required this.labelText}); const SeachFormTextFieldWidget(
{super.key,
required this.text,
required this.onChanged,
required this.labelText});
@override @override
State<SeachFormTextFieldWidget> createState() => _SeachFormTextFieldWidgetState(); State<SeachFormTextFieldWidget> createState() =>
_SeachFormTextFieldWidgetState();
} }
class _SeachFormTextFieldWidgetState extends State<SeachFormTextFieldWidget> { class _SeachFormTextFieldWidgetState extends State<SeachFormTextFieldWidget> {

View file

@ -7,7 +7,11 @@ class MangasCardSelector extends StatelessWidget {
final bool selected; final bool selected;
final VoidCallback onPressed; final VoidCallback onPressed;
const MangasCardSelector( const MangasCardSelector(
{super.key, required this.text, required this.icon, required this.selected, required this.onPressed}); {super.key,
required this.text,
required this.icon,
required this.selected,
required this.onPressed});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -18,7 +22,8 @@ class MangasCardSelector extends StatelessWidget {
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
side: BorderSide(width: 0.6, color: context.primaryColor), side: BorderSide(width: 0.6, color: context.primaryColor),
backgroundColor: selected ? context.primaryColor : null, backgroundColor: selected ? context.primaryColor : null,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)), shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)),
), ),
onPressed: onPressed, onPressed: onPressed,
child: Padding( child: Padding(

View file

@ -27,14 +27,17 @@ class DoubleColummView extends StatefulWidget {
State<DoubleColummView> createState() => _DoubleColummViewState(); State<DoubleColummView> createState() => _DoubleColummViewState();
} }
class _DoubleColummViewState extends State<DoubleColummView> with TickerProviderStateMixin { class _DoubleColummViewState extends State<DoubleColummView>
with TickerProviderStateMixin {
late AnimationController _scaleAnimationController; late AnimationController _scaleAnimationController;
late Animation<double> _animation; late Animation<double> _animation;
Alignment _scalePosition = Alignment.center; Alignment _scalePosition = Alignment.center;
final PhotoViewController _photoViewController = PhotoViewController(); final PhotoViewController _photoViewController = PhotoViewController();
final PhotoViewScaleStateController _photoViewScaleStateController = PhotoViewScaleStateController(); final PhotoViewScaleStateController _photoViewScaleStateController =
PhotoViewScaleStateController();
Duration? _doubleTapAnimationDuration() { Duration? _doubleTapAnimationDuration() {
int doubleTapAnimationValue = isar.settings.getSync(227)!.doubleTapAnimationSpeed!; int doubleTapAnimationValue =
isar.settings.getSync(227)!.doubleTapAnimationSpeed!;
if (doubleTapAnimationValue == 0) { if (doubleTapAnimationValue == 0) {
return const Duration(milliseconds: 10); return const Duration(milliseconds: 10);
} else if (doubleTapAnimationValue == 1) { } else if (doubleTapAnimationValue == 1) {
@ -43,7 +46,8 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
return const Duration(milliseconds: 200); return const Duration(milliseconds: 200);
} }
void _onScaleEnd(BuildContext context, ScaleEndDetails details, PhotoViewControllerValue controllerValue) { void _onScaleEnd(BuildContext context, ScaleEndDetails details,
PhotoViewControllerValue controllerValue) {
if (controllerValue.scale! < 1) { if (controllerValue.scale! < 1) {
_photoViewScaleStateController.reset(); _photoViewScaleStateController.reset();
} }
@ -52,15 +56,16 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
double get pixelRatio => View.of(context).devicePixelRatio; double get pixelRatio => View.of(context).devicePixelRatio;
Size get size => View.of(context).physicalSize / pixelRatio; Size get size => View.of(context).physicalSize / pixelRatio;
Alignment _computeAlignmentByTapOffset(Offset offset) { Alignment _computeAlignmentByTapOffset(Offset offset) {
return Alignment( return Alignment((offset.dx - size.width / 2) / (size.width / 2),
(offset.dx - size.width / 2) / (size.width / 2), (offset.dy - size.height / 2) / (size.height / 2)); (offset.dy - size.height / 2) / (size.height / 2));
} }
@override @override
void initState() { void initState() {
_scaleAnimationController = AnimationController(duration: _doubleTapAnimationDuration(), vsync: this); _scaleAnimationController = AnimationController(
_animation = duration: _doubleTapAnimationDuration(), vsync: this);
Tween(begin: 1.0, end: 2.0).animate(CurvedAnimation(curve: Curves.ease, parent: _scaleAnimationController)); _animation = Tween(begin: 1.0, end: 2.0).animate(
CurvedAnimation(curve: Curves.ease, parent: _scaleAnimationController));
_animation.addListener(() { _animation.addListener(() {
_photoViewController.scale = _animation.value; _photoViewController.scale = _animation.value;
}); });
@ -122,32 +127,42 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
child: ImageViewPaged( child: ImageViewPaged(
data: widget.datas[0]!, data: widget.datas[0]!,
loadStateChanged: (state) { loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) { if (state.extendedImageLoadState ==
final ImageChunkEvent? loadingProgress = state.loadingProgress; LoadState.loading) {
final double progress = loadingProgress?.expectedTotalBytes != null final ImageChunkEvent? loadingProgress =
? loadingProgress!.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! state.loadingProgress;
: 0; final double progress =
loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container( return Container(
color: getBackgroundColor(widget.backgroundColor), color: getBackgroundColor(widget.backgroundColor),
height: context.height(0.8), height: context.height(0.8),
child: CircularProgressIndicatorAnimateRotate(progress: progress), child: CircularProgressIndicatorAnimateRotate(
progress: progress),
); );
} }
if (state.extendedImageLoadState == LoadState.completed) { if (state.extendedImageLoadState ==
LoadState.completed) {
widget.isFailedToLoadImage(false); widget.isFailedToLoadImage(false);
return Image(image: state.imageProvider); return Image(image: state.imageProvider);
} }
if (state.extendedImageLoadState == LoadState.failed) { if (state.extendedImageLoadState ==
LoadState.failed) {
widget.isFailedToLoadImage(true); widget.isFailedToLoadImage(true);
return Container( return Container(
color: getBackgroundColor(widget.backgroundColor), color:
getBackgroundColor(widget.backgroundColor),
height: context.height(0.8), height: context.height(0.8),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
l10n.image_loading_error, l10n.image_loading_error,
style: TextStyle(color: Colors.white.withValues(alpha: 0.7)), style: TextStyle(
color: Colors.white
.withValues(alpha: 0.7)),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -162,9 +177,14 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.primaryColor, borderRadius: BorderRadius.circular(30)), color: context.primaryColor,
borderRadius:
BorderRadius.circular(30)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding:
const EdgeInsets.symmetric(
vertical: 8,
horizontal: 16),
child: Text( child: Text(
l10n.retry, l10n.retry,
), ),
@ -176,7 +196,8 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
} }
return null; return null;
}, },
onLongPressData: (datas) => widget.onLongPressData.call(datas), onLongPressData: (datas) =>
widget.onLongPressData.call(datas),
), ),
), ),
// if (widget.datas[1] != null) const SizedBox(width: 10), // if (widget.datas[1] != null) const SizedBox(width: 10),
@ -185,32 +206,42 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
child: ImageViewPaged( child: ImageViewPaged(
data: widget.datas[1]!, data: widget.datas[1]!,
loadStateChanged: (state) { loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) { if (state.extendedImageLoadState ==
final ImageChunkEvent? loadingProgress = state.loadingProgress; LoadState.loading) {
final double progress = loadingProgress?.expectedTotalBytes != null final ImageChunkEvent? loadingProgress =
? loadingProgress!.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! state.loadingProgress;
: 0; final double progress =
loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container( return Container(
color: getBackgroundColor(widget.backgroundColor), color: getBackgroundColor(widget.backgroundColor),
height: context.height(0.8), height: context.height(0.8),
child: CircularProgressIndicatorAnimateRotate(progress: progress), child: CircularProgressIndicatorAnimateRotate(
progress: progress),
); );
} }
if (state.extendedImageLoadState == LoadState.completed) { if (state.extendedImageLoadState ==
LoadState.completed) {
widget.isFailedToLoadImage(false); widget.isFailedToLoadImage(false);
return Image(image: state.imageProvider); return Image(image: state.imageProvider);
} }
if (state.extendedImageLoadState == LoadState.failed) { if (state.extendedImageLoadState ==
LoadState.failed) {
widget.isFailedToLoadImage(true); widget.isFailedToLoadImage(true);
return Container( return Container(
color: getBackgroundColor(widget.backgroundColor), color:
getBackgroundColor(widget.backgroundColor),
height: context.height(0.8), height: context.height(0.8),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
l10n.image_loading_error, l10n.image_loading_error,
style: TextStyle(color: Colors.white.withValues(alpha: 0.7)), style: TextStyle(
color: Colors.white
.withValues(alpha: 0.7)),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -225,9 +256,14 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.primaryColor, borderRadius: BorderRadius.circular(30)), color: context.primaryColor,
borderRadius:
BorderRadius.circular(30)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding:
const EdgeInsets.symmetric(
vertical: 8,
horizontal: 16),
child: Text( child: Text(
l10n.retry, l10n.retry,
), ),
@ -239,7 +275,8 @@ class _DoubleColummViewState extends State<DoubleColummView> with TickerProvider
} }
return null; return null;
}, },
onLongPressData: (datas) => widget.onLongPressData.call(datas), onLongPressData: (datas) =>
widget.onLongPressData.call(datas),
), ),
), ),
], ],

View file

@ -39,14 +39,18 @@ class DoubleColummVerticalView extends StatelessWidget {
data: datas[0]!, data: datas[0]!,
loadStateChanged: (state) { loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) { if (state.extendedImageLoadState == LoadState.loading) {
final ImageChunkEvent? loadingProgress = state.loadingProgress; final ImageChunkEvent? loadingProgress =
final double progress = loadingProgress?.expectedTotalBytes != null state.loadingProgress;
? loadingProgress!.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! final double progress =
: 0; loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container( return Container(
color: getBackgroundColor(backgroundColor), color: getBackgroundColor(backgroundColor),
height: context.height(0.8), height: context.height(0.8),
child: CircularProgressIndicatorAnimateRotate(progress: progress), child: CircularProgressIndicatorAnimateRotate(
progress: progress),
); );
} }
if (state.extendedImageLoadState == LoadState.completed) { if (state.extendedImageLoadState == LoadState.completed) {
@ -63,7 +67,8 @@ class DoubleColummVerticalView extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.image_loading_error, l10n.image_loading_error,
style: TextStyle(color: Colors.white.withValues(alpha: 0.7)), style: TextStyle(
color: Colors.white.withValues(alpha: 0.7)),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -78,9 +83,12 @@ class DoubleColummVerticalView extends StatelessWidget {
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.primaryColor, borderRadius: BorderRadius.circular(30)), color: context.primaryColor,
borderRadius:
BorderRadius.circular(30)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 16),
child: Text( child: Text(
l10n.retry, l10n.retry,
), ),
@ -102,14 +110,18 @@ class DoubleColummVerticalView extends StatelessWidget {
data: datas[1]!, data: datas[1]!,
loadStateChanged: (state) { loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) { if (state.extendedImageLoadState == LoadState.loading) {
final ImageChunkEvent? loadingProgress = state.loadingProgress; final ImageChunkEvent? loadingProgress =
final double progress = loadingProgress?.expectedTotalBytes != null state.loadingProgress;
? loadingProgress!.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! final double progress =
: 0; loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0;
return Container( return Container(
color: getBackgroundColor(backgroundColor), color: getBackgroundColor(backgroundColor),
height: context.height(0.8), height: context.height(0.8),
child: CircularProgressIndicatorAnimateRotate(progress: progress), child: CircularProgressIndicatorAnimateRotate(
progress: progress),
); );
} }
if (state.extendedImageLoadState == LoadState.completed) { if (state.extendedImageLoadState == LoadState.completed) {
@ -126,7 +138,8 @@ class DoubleColummVerticalView extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.image_loading_error, l10n.image_loading_error,
style: TextStyle(color: Colors.white.withValues(alpha: 0.7)), style: TextStyle(
color: Colors.white.withValues(alpha: 0.7)),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -141,9 +154,12 @@ class DoubleColummVerticalView extends StatelessWidget {
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.primaryColor, borderRadius: BorderRadius.circular(30)), color: context.primaryColor,
borderRadius:
BorderRadius.circular(30)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 16),
child: Text( child: Text(
l10n.retry, l10n.retry,
), ),

View file

@ -12,7 +12,8 @@ class ImageViewPaged extends ConsumerWidget {
final Function(UChapDataPreload data) onLongPressData; final Function(UChapDataPreload data) onLongPressData;
final Widget? Function(ExtendedImageState state) loadStateChanged; final Widget? Function(ExtendedImageState state) loadStateChanged;
final Function(ExtendedImageGestureState state)? onDoubleTap; final Function(ExtendedImageGestureState state)? onDoubleTap;
final GestureConfig Function(ExtendedImageState state)? initGestureConfigHandler; final GestureConfig Function(ExtendedImageState state)?
initGestureConfigHandler;
const ImageViewPaged({ const ImageViewPaged({
super.key, super.key,
required this.data, required this.data,

View file

@ -40,7 +40,8 @@ class ImageViewVertical extends ConsumerWidget {
if (state.extendedImageLoadState == LoadState.loading) { if (state.extendedImageLoadState == LoadState.loading) {
final ImageChunkEvent? loadingProgress = state.loadingProgress; final ImageChunkEvent? loadingProgress = state.loadingProgress;
final double progress = loadingProgress?.expectedTotalBytes != null final double progress = loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! ? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: 0; : 0;
return Container( return Container(
color: Colors.black, color: Colors.black,
@ -59,7 +60,8 @@ class ImageViewVertical extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text(context.l10n.image_loading_error, Text(context.l10n.image_loading_error,
style: TextStyle(color: Colors.white.withValues(alpha: 0.7))), style: TextStyle(
color: Colors.white.withValues(alpha: 0.7))),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: GestureDetector( child: GestureDetector(
@ -72,10 +74,12 @@ class ImageViewVertical extends ConsumerWidget {
failedToLoadImage(false); failedToLoadImage(false);
}, },
child: Container( child: Container(
decoration: decoration: BoxDecoration(
BoxDecoration(color: context.primaryColor, borderRadius: BorderRadius.circular(30)), color: context.primaryColor,
borderRadius: BorderRadius.circular(30)),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 16),
child: Text( child: Text(
context.l10n.retry, context.l10n.retry,
), ),

Some files were not shown because too many files have changed in this diff Show more